diff --git a/mealie/core/settings/db_providers.py b/mealie/core/settings/db_providers.py index f8f0e40e2e8d..e94781bcddf3 100644 --- a/mealie/core/settings/db_providers.py +++ b/mealie/core/settings/db_providers.py @@ -1,7 +1,8 @@ from abc import ABC, abstractmethod from pathlib import Path -from pydantic import BaseModel, BaseSettings, PostgresDsn +from pydantic import BaseModel, PostgresDsn +from pydantic_settings import BaseSettings class AbstractDBProvider(ABC): diff --git a/mealie/core/settings/settings.py b/mealie/core/settings/settings.py index 37f93738caa8..c7a72bef40f4 100644 --- a/mealie/core/settings/settings.py +++ b/mealie/core/settings/settings.py @@ -1,7 +1,8 @@ import secrets from pathlib import Path -from pydantic import BaseSettings, NoneStr, validator +from pydantic import field_validator +from pydantic_settings import BaseSettings, SettingsConfigDict from .db_providers import AbstractDBProvider, db_provider_factory @@ -48,7 +49,8 @@ class AppSettings(BaseSettings): SECURITY_USER_LOCKOUT_TIME: int = 24 "time in hours" - @validator("BASE_URL") + @field_validator("BASE_URL") + @classmethod def remove_trailing_slash(cls, v: str) -> str: if v and v[-1] == "/": return v[:-1] @@ -127,15 +129,15 @@ class AppSettings(BaseSettings): # LDAP Configuration LDAP_AUTH_ENABLED: bool = False - LDAP_SERVER_URL: NoneStr = None + LDAP_SERVER_URL: None | str = None LDAP_TLS_INSECURE: bool = False - LDAP_TLS_CACERTFILE: NoneStr = None + LDAP_TLS_CACERTFILE: None | str = None LDAP_ENABLE_STARTTLS: bool = False - LDAP_BASE_DN: NoneStr = None - LDAP_QUERY_BIND: NoneStr = None - LDAP_QUERY_PASSWORD: NoneStr = None - LDAP_USER_FILTER: NoneStr = None - LDAP_ADMIN_FILTER: NoneStr = None + LDAP_BASE_DN: None | str = None + LDAP_QUERY_BIND: None | str = None + LDAP_QUERY_PASSWORD: None | str = None + LDAP_USER_FILTER: None | str = None + LDAP_ADMIN_FILTER: None | str = None LDAP_ID_ATTRIBUTE: str = "uid" LDAP_MAIL_ATTRIBUTE: str = "mail" LDAP_NAME_ATTRIBUTE: str = "name" @@ -157,9 +159,7 @@ class AppSettings(BaseSettings): # Testing Config TESTING: bool = False - - class Config: - arbitrary_types_allowed = True + model_config = SettingsConfigDict(arbitrary_types_allowed=True) def app_settings_constructor(data_dir: Path, production: bool, env_file: Path, env_encoding="utf-8") -> AppSettings: diff --git a/mealie/db/models/group/group.py b/mealie/db/models/group/group.py index fd6ea814454e..02fdc365ac48 100644 --- a/mealie/db/models/group/group.py +++ b/mealie/db/models/group/group.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Optional import sqlalchemy as sa import sqlalchemy.orm as orm +from pydantic import ConfigDict from sqlalchemy import select from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.orm.session import Session @@ -78,18 +79,16 @@ class Group(SqlAlchemyBase, BaseMixins): ingredient_foods: Mapped[list["IngredientFoodModel"]] = orm.relationship("IngredientFoodModel", **common_args) tools: Mapped[list["Tool"]] = orm.relationship("Tool", **common_args) tags: Mapped[list["Tag"]] = orm.relationship("Tag", **common_args) - - class Config: - exclude = { - "users", - "webhooks", - "shopping_lists", - "cookbooks", - "preferences", - "invite_tokens", - "mealplans", - "data_exports", - } + model_config = ConfigDict(exclude={ + "users", + "webhooks", + "shopping_lists", + "cookbooks", + "preferences", + "invite_tokens", + "mealplans", + "data_exports", + }) @auto_init() def __init__(self, **_) -> None: diff --git a/mealie/db/models/group/report.py b/mealie/db/models/group/report.py index c7771efcde74..011589c3c18d 100644 --- a/mealie/db/models/group/report.py +++ b/mealie/db/models/group/report.py @@ -1,6 +1,7 @@ from datetime import datetime from typing import TYPE_CHECKING +from pydantic import ConfigDict from sqlalchemy import ForeignKey, orm from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.sql.sqltypes import Boolean, DateTime, String @@ -47,9 +48,7 @@ class ReportModel(SqlAlchemyBase, BaseMixins): # Relationships group_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("groups.id"), nullable=False, index=True) group: Mapped["Group"] = orm.relationship("Group", back_populates="group_reports", single_parent=True) - - class Config: - exclude = ["entries"] + model_config = ConfigDict(exclude=["entries"]) @auto_init() def __init__(self, **_) -> None: diff --git a/mealie/db/models/group/shopping_list.py b/mealie/db/models/group/shopping_list.py index 01c0086bdbd7..caafed8667ff 100644 --- a/mealie/db/models/group/shopping_list.py +++ b/mealie/db/models/group/shopping_list.py @@ -1,5 +1,6 @@ from typing import TYPE_CHECKING, Optional +from pydantic import ConfigDict from sqlalchemy import Boolean, Float, ForeignKey, Integer, String, orm from sqlalchemy.ext.orderinglist import ordering_list from sqlalchemy.orm import Mapped, mapped_column @@ -72,9 +73,7 @@ class ShoppingListItem(SqlAlchemyBase, BaseMixins): recipe_references: Mapped[list[ShoppingListItemRecipeReference]] = orm.relationship( ShoppingListItemRecipeReference, cascade="all, delete, delete-orphan" ) - - class Config: - exclude = {"id", "label", "food", "unit"} + model_config = ConfigDict(exclude={"id", "label", "food", "unit"}) @api_extras @auto_init() @@ -94,9 +93,7 @@ class ShoppingListRecipeReference(BaseMixins, SqlAlchemyBase): ) recipe_quantity: Mapped[float] = mapped_column(Float, nullable=False) - - class Config: - exclude = {"id", "recipe"} + model_config = ConfigDict(exclude={"id", "recipe"}) @auto_init() def __init__(self, **_) -> None: @@ -114,9 +111,7 @@ class ShoppingListMultiPurposeLabel(SqlAlchemyBase, BaseMixins): "MultiPurposeLabel", back_populates="shopping_lists_label_settings" ) position: Mapped[int] = mapped_column(Integer, nullable=False, default=0) - - class Config: - exclude = {"label"} + model_config = ConfigDict(exclude={"label"}) @auto_init() def __init__(self, **_) -> None: @@ -148,9 +143,7 @@ class ShoppingList(SqlAlchemyBase, BaseMixins): collection_class=ordering_list("position"), ) extras: Mapped[list[ShoppingListExtras]] = orm.relationship("ShoppingListExtras", cascade="all, delete-orphan") - - class Config: - exclude = {"id", "list_items"} + model_config = ConfigDict(exclude={"id", "list_items"}) @api_extras @auto_init() diff --git a/mealie/db/models/recipe/instruction.py b/mealie/db/models/recipe/instruction.py index 01592ae30d67..59f02485b277 100644 --- a/mealie/db/models/recipe/instruction.py +++ b/mealie/db/models/recipe/instruction.py @@ -1,3 +1,4 @@ +from pydantic import ConfigDict from sqlalchemy import ForeignKey, Integer, String, orm from sqlalchemy.orm import Mapped, mapped_column @@ -28,12 +29,10 @@ class RecipeInstruction(SqlAlchemyBase): ingredient_references: Mapped[list[RecipeIngredientRefLink]] = orm.relationship( RecipeIngredientRefLink, cascade="all, delete-orphan" ) - - class Config: - exclude = { - "id", - "ingredient_references", - } + model_config = ConfigDict(exclude={ + "id", + "ingredient_references", + }) @auto_init() def __init__(self, ingredient_references, session, **_) -> None: diff --git a/mealie/db/models/recipe/recipe.py b/mealie/db/models/recipe/recipe.py index b181a232082b..477cf6007114 100644 --- a/mealie/db/models/recipe/recipe.py +++ b/mealie/db/models/recipe/recipe.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING import sqlalchemy as sa import sqlalchemy.orm as orm +from pydantic import ConfigDict from sqlalchemy import event from sqlalchemy.ext.orderinglist import ordering_list from sqlalchemy.orm import Mapped, mapped_column, validates @@ -135,19 +136,16 @@ class RecipeModel(SqlAlchemyBase, BaseMixins): # Automatically updated by sqlalchemy event, do not write to this manually name_normalized: Mapped[str] = mapped_column(sa.String, nullable=False, index=True) description_normalized: Mapped[str | None] = mapped_column(sa.String, index=True) - - class Config: - get_attr = "slug" - exclude = { - "assets", - "notes", - "nutrition", - "recipe_ingredient", - "recipe_instructions", - "settings", - "comments", - "timeline_events", - } + model_config = ConfigDict(get_attr="slug", exclude={ + "assets", + "notes", + "nutrition", + "recipe_ingredient", + "recipe_instructions", + "settings", + "comments", + "timeline_events", + }) @validates("name") def validate_name(self, _, name): diff --git a/mealie/db/models/users/users.py b/mealie/db/models/users/users.py index 5252785c72c4..bacdc8afdc53 100644 --- a/mealie/db/models/users/users.py +++ b/mealie/db/models/users/users.py @@ -2,6 +2,7 @@ import enum from datetime import datetime from typing import TYPE_CHECKING, Optional +from pydantic import ConfigDict from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, Integer, String, orm from sqlalchemy.orm import Mapped, mapped_column @@ -83,16 +84,14 @@ class User(SqlAlchemyBase, BaseMixins): favorite_recipes: Mapped[list["RecipeModel"]] = orm.relationship( "RecipeModel", secondary=users_to_favorites, back_populates="favorited_by" ) - - class Config: - exclude = { - "password", - "admin", - "can_manage", - "can_invite", - "can_organize", - "group", - } + model_config = ConfigDict(exclude={ + "password", + "admin", + "can_manage", + "can_invite", + "can_organize", + "group", + }) @auto_init() def __init__(self, session, full_name, password, group: str | None = None, **kwargs) -> None: diff --git a/mealie/repos/repository_recipes.py b/mealie/repos/repository_recipes.py index a782daf4713b..3b12ac2f5fe2 100644 --- a/mealie/repos/repository_recipes.py +++ b/mealie/repos/repository_recipes.py @@ -60,7 +60,7 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]): stmt = ( select(self.model) .join(RecipeSettings) - .filter(RecipeSettings.public == True) # noqa: 711 + .filter(RecipeSettings.public is True) # noqa: 711 .order_by(order_attr.desc()) .offset(start) .limit(limit) @@ -70,7 +70,7 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]): stmt = ( select(self.model) .join(RecipeSettings) - .filter(RecipeSettings.public == True) # noqa: 711 + .filter(RecipeSettings.public is True) # noqa: 711 .offset(start) .limit(limit) ) diff --git a/mealie/routes/_base/base_controllers.py b/mealie/routes/_base/base_controllers.py index 1c9a60f8021f..dea4c1250543 100644 --- a/mealie/routes/_base/base_controllers.py +++ b/mealie/routes/_base/base_controllers.py @@ -2,7 +2,7 @@ from abc import ABC from logging import Logger from fastapi import Depends -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from sqlalchemy.orm import Session from mealie.core.config import get_app_dirs, get_app_settings @@ -57,9 +57,7 @@ class _BaseController(ABC): if not self._folders: self._folders = get_app_dirs() return self._folders - - class Config: - arbitrary_types_allowed = True + model_config = ConfigDict(arbitrary_types_allowed=True) class BasePublicController(_BaseController): diff --git a/mealie/routes/organizers/controller_categories.py b/mealie/routes/organizers/controller_categories.py index 3e584225b940..f08ac5f1727e 100644 --- a/mealie/routes/organizers/controller_categories.py +++ b/mealie/routes/organizers/controller_categories.py @@ -1,7 +1,7 @@ from functools import cached_property from fastapi import APIRouter, Depends -from pydantic import UUID4, BaseModel +from pydantic import UUID4, BaseModel, ConfigDict from mealie.routes._base import BaseCrudController, controller from mealie.routes._base.mixins import HttpRepo @@ -20,9 +20,7 @@ class CategorySummary(BaseModel): id: UUID4 slug: str name: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @controller(router) diff --git a/mealie/schema/_mealie/mealie_model.py b/mealie/schema/_mealie/mealie_model.py index 1777458b5853..52a54fad6a5f 100644 --- a/mealie/schema/_mealie/mealie_model.py +++ b/mealie/schema/_mealie/mealie_model.py @@ -4,16 +4,14 @@ from collections.abc import Sequence from typing import Protocol, TypeVar from humps.main import camelize -from pydantic import UUID4, BaseModel +from pydantic import UUID4, BaseModel, ConfigDict from sqlalchemy.orm.interfaces import LoaderOption T = TypeVar("T", bound=BaseModel) class MealieModel(BaseModel): - class Config: - alias_generator = camelize - allow_population_by_field_name = True + model_config = ConfigDict(alias_generator=camelize, populate_by_name=True) def cast(self, cls: type[T], **kwargs) -> T: """ diff --git a/mealie/schema/admin/backup.py b/mealie/schema/admin/backup.py index c59cd40fc027..730dc9063453 100644 --- a/mealie/schema/admin/backup.py +++ b/mealie/schema/admin/backup.py @@ -19,9 +19,9 @@ class ImportJob(BackupOptions): class CreateBackup(BaseModel): - tag: str | None + tag: str | None = None options: BackupOptions - templates: list[str] | None + templates: list[str] | None = None class BackupFile(BaseModel): diff --git a/mealie/schema/admin/restore.py b/mealie/schema/admin/restore.py index 4983f8b3134e..68b973cf8746 100644 --- a/mealie/schema/admin/restore.py +++ b/mealie/schema/admin/restore.py @@ -4,11 +4,11 @@ from pydantic.main import BaseModel class ImportBase(BaseModel): name: str status: bool - exception: str | None + exception: str | None = None class RecipeImport(ImportBase): - slug: str | None + slug: str | None = None class CommentImport(ImportBase): diff --git a/mealie/schema/admin/settings.py b/mealie/schema/admin/settings.py index baef0b7ef919..87742922f428 100644 --- a/mealie/schema/admin/settings.py +++ b/mealie/schema/admin/settings.py @@ -1,4 +1,4 @@ -from pydantic import validator +from pydantic import ConfigDict, validator from slugify import slugify from mealie.schema._mealie import MealieModel @@ -11,10 +11,10 @@ class CustomPageBase(MealieModel): slug: str | None position: int categories: list[RecipeCategoryResponse] = [] + model_config = ConfigDict(from_attributes=True) - class Config: - orm_mode = True - + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("slug", always=True, pre=True) def validate_slug(slug: str, values): name: str = values["name"] @@ -28,6 +28,4 @@ class CustomPageBase(MealieModel): class CustomPageOut(CustomPageBase): id: int - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/cookbook/cookbook.py b/mealie/schema/cookbook/cookbook.py index 3769cfae07a7..404e09335aa1 100644 --- a/mealie/schema/cookbook/cookbook.py +++ b/mealie/schema/cookbook/cookbook.py @@ -1,4 +1,4 @@ -from pydantic import UUID4, validator +from pydantic import UUID4, ConfigDict, validator from slugify import slugify from sqlalchemy.orm import joinedload from sqlalchemy.orm.interfaces import LoaderOption @@ -24,10 +24,14 @@ class CreateCookBook(MealieModel): require_all_tags: bool = True require_all_tools: bool = True + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("public", always=True, pre=True) def validate_public(public: bool | None, values: dict) -> bool: # type: ignore return False if public is None else public + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("slug", always=True, pre=True) def validate_slug(slug: str, values): # type: ignore name: str = values["name"] @@ -50,9 +54,7 @@ class UpdateCookBook(SaveCookBook): class ReadCookBook(UpdateCookBook): group_id: UUID4 categories: list[CategoryBase] = [] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -66,6 +68,4 @@ class CookBookPagination(PaginationBase): class RecipeCookBook(ReadCookBook): group_id: UUID4 recipes: list[RecipeSummary] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/group/group_events.py b/mealie/schema/group/group_events.py index 9f15f98c54ff..2d7e4f93b80a 100644 --- a/mealie/schema/group/group_events.py +++ b/mealie/schema/group/group_events.py @@ -1,4 +1,4 @@ -from pydantic import UUID4, NoneStr +from pydantic import UUID4, ConfigDict, NoneStr from sqlalchemy.orm import joinedload from sqlalchemy.orm.interfaces import LoaderOption @@ -54,9 +54,7 @@ class GroupEventNotifierOptionsSave(GroupEventNotifierOptions): class GroupEventNotifierOptionsOut(GroupEventNotifierOptions): id: UUID4 - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) # ======================================================================= @@ -85,9 +83,7 @@ class GroupEventNotifierOut(MealieModel): enabled: bool group_id: UUID4 options: GroupEventNotifierOptionsOut - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -100,6 +96,4 @@ class GroupEventPagination(PaginationBase): class GroupEventNotifierPrivate(GroupEventNotifierOut): apprise_url: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/group/group_exports.py b/mealie/schema/group/group_exports.py index e271261de455..ce2dcc2e17d7 100644 --- a/mealie/schema/group/group_exports.py +++ b/mealie/schema/group/group_exports.py @@ -1,6 +1,6 @@ from datetime import datetime -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from mealie.schema._mealie import MealieModel @@ -13,6 +13,4 @@ class GroupDataExport(MealieModel): path: str size: str expires: datetime - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/group/group_preferences.py b/mealie/schema/group/group_preferences.py index 492f9fa96b8d..4b47787de9a0 100644 --- a/mealie/schema/group/group_preferences.py +++ b/mealie/schema/group/group_preferences.py @@ -1,6 +1,6 @@ from uuid import UUID -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from mealie.schema._mealie import MealieModel @@ -24,6 +24,4 @@ class CreateGroupPreferences(UpdateGroupPreferences): class ReadGroupPreferences(CreateGroupPreferences): id: UUID4 - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/group/group_seeder.py b/mealie/schema/group/group_seeder.py index 1514b4dfe234..611966a5025b 100644 --- a/mealie/schema/group/group_seeder.py +++ b/mealie/schema/group/group_seeder.py @@ -7,6 +7,8 @@ from mealie.schema._mealie.validators import validate_locale class SeederConfig(MealieModel): locale: str + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("locale") def valid_locale(cls, v, values, **kwargs): if not validate_locale(v): diff --git a/mealie/schema/group/group_shopping_list.py b/mealie/schema/group/group_shopping_list.py index 82d4c27d1b14..b112dec96187 100644 --- a/mealie/schema/group/group_shopping_list.py +++ b/mealie/schema/group/group_shopping_list.py @@ -2,7 +2,7 @@ from __future__ import annotations from datetime import datetime -from pydantic import UUID4, validator +from pydantic import UUID4, ConfigDict, field_validator from sqlalchemy.orm import joinedload, selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -35,7 +35,8 @@ class ShoppingListItemRecipeRefCreate(MealieModel): recipe_scale: NoneFloat = 1 """the number of times this recipe has been added""" - @validator("recipe_quantity", pre=True) + @field_validator("recipe_quantity", mode="before") + @classmethod def default_none_to_zero(cls, v): return 0 if v is None else v @@ -46,8 +47,7 @@ class ShoppingListItemRecipeRefUpdate(ShoppingListItemRecipeRefCreate): class ShoppingListItemRecipeRefOut(ShoppingListItemRecipeRefUpdate): - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class ShoppingListItemBase(RecipeIngredientBase): @@ -98,10 +98,9 @@ class ShoppingListItemOut(ShoppingListItemBase): if (not self.label) and (self.food and self.food.label): self.label = self.food.label self.label_id = self.label.id - - class Config: - orm_mode = True - getter_dict = ExtrasGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=ExtrasGetterDict) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -135,9 +134,7 @@ class ShoppingListMultiPurposeLabelUpdate(ShoppingListMultiPurposeLabelCreate): class ShoppingListMultiPurposeLabelOut(ShoppingListMultiPurposeLabelUpdate): label: MultiPurposeLabelSummary - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -164,9 +161,7 @@ class ShoppingListRecipeRefOut(MealieModel): """the number of times this recipe has been added""" recipe: RecipeSummary - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -185,10 +180,9 @@ class ShoppingListSummary(ShoppingListSave): id: UUID4 recipe_references: list[ShoppingListRecipeRefOut] label_settings: list[ShoppingListMultiPurposeLabelOut] - - class Config: - orm_mode = True - getter_dict = ExtrasGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=ExtrasGetterDict) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -219,10 +213,9 @@ class ShoppingListUpdate(ShoppingListSave): class ShoppingListOut(ShoppingListUpdate): recipe_references: list[ShoppingListRecipeRefOut] label_settings: list[ShoppingListMultiPurposeLabelOut] - - class Config: - orm_mode = True - getter_dict = ExtrasGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=ExtrasGetterDict) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/schema/group/invite_token.py b/mealie/schema/group/invite_token.py index dac57448d08e..dc59ff0536a4 100644 --- a/mealie/schema/group/invite_token.py +++ b/mealie/schema/group/invite_token.py @@ -1,6 +1,6 @@ from uuid import UUID -from pydantic import NoneStr +from pydantic import ConfigDict, NoneStr from mealie.schema._mealie import MealieModel @@ -19,9 +19,7 @@ class ReadInviteToken(MealieModel): token: str uses_left: int group_id: UUID - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class EmailInvitation(MealieModel): diff --git a/mealie/schema/group/webhook.py b/mealie/schema/group/webhook.py index b72769862635..1fe4d22718e9 100644 --- a/mealie/schema/group/webhook.py +++ b/mealie/schema/group/webhook.py @@ -3,7 +3,7 @@ import enum from uuid import UUID from isodate import parse_time -from pydantic import UUID4, validator +from pydantic import UUID4, ConfigDict, field_validator from pydantic.datetime_parse import parse_datetime from mealie.schema._mealie import MealieModel @@ -22,7 +22,8 @@ class CreateWebhook(MealieModel): webhook_type: WebhookType = WebhookType.mealplan scheduled_time: datetime.time - @validator("scheduled_time", pre=True) + @field_validator("scheduled_time", mode="before") + @classmethod @classmethod def validate_scheduled_time(cls, v): """ @@ -55,9 +56,7 @@ class SaveWebhook(CreateWebhook): class ReadWebhook(SaveWebhook): id: UUID4 - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class WebhookPagination(PaginationBase): diff --git a/mealie/schema/labels/multi_purpose_label.py b/mealie/schema/labels/multi_purpose_label.py index 9faea5d9879f..17fead0d8ba5 100644 --- a/mealie/schema/labels/multi_purpose_label.py +++ b/mealie/schema/labels/multi_purpose_label.py @@ -1,6 +1,6 @@ from __future__ import annotations -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from mealie.schema._mealie import MealieModel from mealie.schema.response.pagination import PaginationBase @@ -21,9 +21,7 @@ class MultiPurposeLabelUpdate(MultiPurposeLabelSave): class MultiPurposeLabelSummary(MultiPurposeLabelUpdate): pass - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class MultiPurposeLabelPagination(PaginationBase): @@ -31,11 +29,7 @@ class MultiPurposeLabelPagination(PaginationBase): class MultiPurposeLabelOut(MultiPurposeLabelUpdate): - # shopping_list_items: list[ShoppingListItemOut] = [] - # foods: list[IngredientFood] = [] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) # from mealie.schema.recipe.recipe_ingredient import IngredientFood diff --git a/mealie/schema/meal_plan/meal.py b/mealie/schema/meal_plan/meal.py index 718bc76673a3..b7eae0ceade0 100644 --- a/mealie/schema/meal_plan/meal.py +++ b/mealie/schema/meal_plan/meal.py @@ -1,6 +1,6 @@ from datetime import date -from pydantic import validator +from pydantic import ConfigDict, validator from mealie.schema._mealie import MealieModel @@ -9,24 +9,18 @@ class MealIn(MealieModel): slug: str | None name: str | None description: str | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class MealDayIn(MealieModel): date: date | None meals: list[MealIn] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class MealDayOut(MealDayIn): id: int - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class MealPlanIn(MealieModel): @@ -35,19 +29,17 @@ class MealPlanIn(MealieModel): end_date: date plan_days: list[MealDayIn] + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("end_date") def end_date_after_start_date(v, values, config, field): if "start_date" in values and v < values["start_date"]: raise ValueError("EndDate should be greater than StartDate") return v - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class MealPlanOut(MealPlanIn): id: int shopping_list: int | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/meal_plan/new_meal.py b/mealie/schema/meal_plan/new_meal.py index 90513f241be1..bdc2aeb99b7d 100644 --- a/mealie/schema/meal_plan/new_meal.py +++ b/mealie/schema/meal_plan/new_meal.py @@ -2,7 +2,7 @@ from datetime import date from enum import Enum from uuid import UUID -from pydantic import validator +from pydantic import ConfigDict, validator from sqlalchemy.orm import selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -32,6 +32,8 @@ class CreatePlanEntry(MealieModel): text: str = "" recipe_id: UUID | None + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("recipe_id", always=True) @classmethod def id_or_title(cls, value, values): @@ -50,16 +52,12 @@ class UpdatePlanEntry(CreatePlanEntry): class SavePlanEntry(CreatePlanEntry): group_id: UUID user_id: UUID | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class ReadPlanEntry(UpdatePlanEntry): recipe: RecipeSummary | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/schema/meal_plan/plan_rules.py b/mealie/schema/meal_plan/plan_rules.py index 36f69af71f30..08dc8e63ac51 100644 --- a/mealie/schema/meal_plan/plan_rules.py +++ b/mealie/schema/meal_plan/plan_rules.py @@ -1,7 +1,7 @@ import datetime from enum import Enum -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from sqlalchemy.orm import joinedload from sqlalchemy.orm.interfaces import LoaderOption @@ -14,14 +14,11 @@ class Category(MealieModel): id: UUID4 name: str slug: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class Tag(Category): - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class PlanRulesDay(str, Enum): @@ -64,9 +61,7 @@ class PlanRulesSave(PlanRulesCreate): class PlanRulesOut(PlanRulesSave): id: UUID4 - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/schema/meal_plan/shopping_list.py b/mealie/schema/meal_plan/shopping_list.py index a7acadb0eeaf..48047e0c7e16 100644 --- a/mealie/schema/meal_plan/shopping_list.py +++ b/mealie/schema/meal_plan/shopping_list.py @@ -1,3 +1,5 @@ +from pydantic import ConfigDict + from mealie.schema._mealie import MealieModel from mealie.schema.getter_dict import GroupGetterDict @@ -7,9 +9,7 @@ class ListItem(MealieModel): text: str = "" quantity: int = 1 checked: bool = False - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class ShoppingListIn(MealieModel): @@ -20,7 +20,6 @@ class ShoppingListIn(MealieModel): class ShoppingListOut(ShoppingListIn): id: int - - class Config: - orm_mode = True - getter_dict = GroupGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=GroupGetterDict) diff --git a/mealie/schema/recipe/recipe.py b/mealie/schema/recipe/recipe.py index 22c812e4e5f9..3ee4eacc4a3c 100644 --- a/mealie/schema/recipe/recipe.py +++ b/mealie/schema/recipe/recipe.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Any from uuid import uuid4 -from pydantic import UUID4, BaseModel, Field, validator +from pydantic import UUID4, BaseModel, ConfigDict, Field, validator from slugify import slugify from sqlalchemy.orm import joinedload, selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -36,9 +36,7 @@ class RecipeTag(MealieModel): id: UUID4 | None = None name: str slug: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeTagPagination(PaginationBase): @@ -105,9 +103,7 @@ class RecipeSummary(MealieModel): created_at: datetime.datetime | None update_at: datetime.datetime | None last_made: datetime.datetime | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipePagination(PaginationBase): @@ -171,10 +167,9 @@ class Recipe(RecipeSummary): raise ValueError("Recipe has no ID") return self.image_dir_from_id(self.id) - - class Config: - orm_mode = True - getter_dict = ExtrasGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=ExtrasGetterDict) @classmethod def from_orm(cls, obj): @@ -195,6 +190,8 @@ class Recipe(RecipeSummary): ingredient.is_food = not ingredient.disable_amount ingredient.display = ingredient._format_display() + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("slug", always=True, pre=True, allow_reuse=True) def validate_slug(slug: str, values): # type: ignore if not values.get("name"): @@ -202,6 +199,8 @@ class Recipe(RecipeSummary): return slugify(values["name"]) + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("recipe_ingredient", always=True, pre=True, allow_reuse=True) def validate_ingredients(recipe_ingredient, values): if not recipe_ingredient or not isinstance(recipe_ingredient, list): @@ -212,24 +211,32 @@ class Recipe(RecipeSummary): return recipe_ingredient + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("tags", always=True, pre=True, allow_reuse=True) def validate_tags(cats: list[Any]): # type: ignore if isinstance(cats, list) and cats and isinstance(cats[0], str): return [RecipeTag(id=uuid4(), name=c, slug=slugify(c)) for c in cats] return cats + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("recipe_category", always=True, pre=True, allow_reuse=True) def validate_categories(cats: list[Any]): # type: ignore if isinstance(cats, list) and cats and isinstance(cats[0], str): return [RecipeCategory(id=uuid4(), name=c, slug=slugify(c)) for c in cats] return cats + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("group_id", always=True, pre=True, allow_reuse=True) def validate_group_id(group_id: Any): if isinstance(group_id, int): return uuid4() return group_id + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("user_id", always=True, pre=True, allow_reuse=True) def validate_user_id(user_id: Any): if isinstance(user_id, int): diff --git a/mealie/schema/recipe/recipe_asset.py b/mealie/schema/recipe/recipe_asset.py index 8abdcf4552fe..6bfb028317a6 100644 --- a/mealie/schema/recipe/recipe_asset.py +++ b/mealie/schema/recipe/recipe_asset.py @@ -1,3 +1,5 @@ +from pydantic import ConfigDict + from mealie.schema._mealie import MealieModel @@ -5,6 +7,4 @@ class RecipeAsset(MealieModel): name: str icon: str file_name: str | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/recipe/recipe_category.py b/mealie/schema/recipe/recipe_category.py index c1be3dc42e13..a4ca46a0cfb7 100644 --- a/mealie/schema/recipe/recipe_category.py +++ b/mealie/schema/recipe/recipe_category.py @@ -1,4 +1,4 @@ -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from sqlalchemy.orm import selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -17,24 +17,18 @@ class CategorySave(CategoryIn): class CategoryBase(CategoryIn): id: UUID4 slug: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class CategoryOut(CategoryBase): slug: str group_id: UUID4 - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeCategoryResponse(CategoryBase): recipes: "list[RecipeSummary]" = [] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class TagIn(CategoryIn): @@ -52,9 +46,7 @@ class TagBase(CategoryBase): class TagOut(TagSave): id: UUID4 slug: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeTagResponse(RecipeCategoryResponse): diff --git a/mealie/schema/recipe/recipe_comments.py b/mealie/schema/recipe/recipe_comments.py index 68adc17bc532..a80b17965dfa 100644 --- a/mealie/schema/recipe/recipe_comments.py +++ b/mealie/schema/recipe/recipe_comments.py @@ -1,6 +1,6 @@ from datetime import datetime -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from sqlalchemy.orm import joinedload from sqlalchemy.orm.interfaces import LoaderOption @@ -13,9 +13,7 @@ class UserBase(MealieModel): id: UUID4 username: str | None admin: bool - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeCommentCreate(MealieModel): @@ -39,9 +37,7 @@ class RecipeCommentOut(RecipeCommentCreate): update_at: datetime user_id: UUID4 user: UserBase - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/schema/recipe/recipe_ingredient.py b/mealie/schema/recipe/recipe_ingredient.py index ef4facb60ad2..3fa5c191a549 100644 --- a/mealie/schema/recipe/recipe_ingredient.py +++ b/mealie/schema/recipe/recipe_ingredient.py @@ -5,7 +5,7 @@ import enum from fractions import Fraction from uuid import UUID, uuid4 -from pydantic import UUID4, Field, validator +from pydantic import UUID4, ConfigDict, Field, field_validator, validator from sqlalchemy.orm import joinedload from sqlalchemy.orm.interfaces import LoaderOption @@ -49,10 +49,9 @@ class IngredientFood(CreateIngredientFood): label: MultiPurposeLabelSummary | None = None created_at: datetime.datetime | None update_at: datetime.datetime | None - - class Config: - orm_mode = True - getter_dict = ExtrasGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=ExtrasGetterDict) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -77,9 +76,7 @@ class IngredientUnit(CreateIngredientUnit): id: UUID4 created_at: datetime.datetime | None update_at: datetime.datetime | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeIngredientBase(MealieModel): @@ -114,14 +111,16 @@ class RecipeIngredientBase(MealieModel): if not self.display: self.display = self._format_display() - @validator("unit", pre=True) + @field_validator("unit", mode="before") + @classmethod def validate_unit(cls, v): if isinstance(v, str): return CreateIngredientUnit(name=v) else: return v - @validator("food", pre=True) + @field_validator("food", mode="before") + @classmethod def validate_food(cls, v): if isinstance(v, str): return CreateIngredientFood(name=v) @@ -200,11 +199,10 @@ class RecipeIngredient(RecipeIngredientBase): # It is required for the reorder and section titles to function properly because of how # Vue handles reactivity. ref may serve another purpose in the future. reference_id: UUID = Field(default_factory=uuid4) + model_config = ConfigDict(from_attributes=True) - class Config: - orm_mode = True - - @validator("quantity", pre=True) + @field_validator("quantity", mode="before") + @classmethod def validate_quantity(cls, value) -> NoneFloat: """ Sometimes the frontend UI will provide an empty string as a "null" value because of the default @@ -226,6 +224,8 @@ class IngredientConfidence(MealieModel): quantity: NoneFloat = None food: NoneFloat = None + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("quantity", pre=True) @classmethod def validate_quantity(cls, value, values) -> NoneFloat: diff --git a/mealie/schema/recipe/recipe_notes.py b/mealie/schema/recipe/recipe_notes.py index ae8633a884b9..6829a2bf4f42 100644 --- a/mealie/schema/recipe/recipe_notes.py +++ b/mealie/schema/recipe/recipe_notes.py @@ -1,9 +1,7 @@ -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict class RecipeNote(BaseModel): title: str text: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/recipe/recipe_nutrition.py b/mealie/schema/recipe/recipe_nutrition.py index 776b5bf4c084..ca9b7bb9935a 100644 --- a/mealie/schema/recipe/recipe_nutrition.py +++ b/mealie/schema/recipe/recipe_nutrition.py @@ -1,3 +1,5 @@ +from pydantic import ConfigDict + from mealie.schema._mealie import MealieModel @@ -9,6 +11,4 @@ class Nutrition(MealieModel): fiber_content: str | None sodium_content: str | None sugar_content: str | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/recipe/recipe_scraper.py b/mealie/schema/recipe/recipe_scraper.py index 841e73e47818..efe164025aa4 100644 --- a/mealie/schema/recipe/recipe_scraper.py +++ b/mealie/schema/recipe/recipe_scraper.py @@ -1,3 +1,5 @@ +from pydantic import ConfigDict + from mealie.schema._mealie.mealie_model import MealieModel @@ -8,11 +10,9 @@ class ScrapeRecipeTest(MealieModel): class ScrapeRecipe(MealieModel): url: str include_tags: bool = False - - class Config: - schema_extra = { - "example": { - "url": "https://myfavoriterecipes.com/recipes", - "includeTags": True, - }, - } + model_config = ConfigDict(json_schema_extra={ + "example": { + "url": "https://myfavoriterecipes.com/recipes", + "includeTags": True, + }, + }) diff --git a/mealie/schema/recipe/recipe_settings.py b/mealie/schema/recipe/recipe_settings.py index c188235ad3d7..1d90c3397de2 100644 --- a/mealie/schema/recipe/recipe_settings.py +++ b/mealie/schema/recipe/recipe_settings.py @@ -1,3 +1,5 @@ +from pydantic import ConfigDict + from mealie.schema._mealie import MealieModel @@ -9,6 +11,4 @@ class RecipeSettings(MealieModel): disable_comments: bool = True disable_amount: bool = True locked: bool = False - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/recipe/recipe_share_token.py b/mealie/schema/recipe/recipe_share_token.py index b03a48a539a8..6976548661f9 100644 --- a/mealie/schema/recipe/recipe_share_token.py +++ b/mealie/schema/recipe/recipe_share_token.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta -from pydantic import UUID4, Field +from pydantic import UUID4, ConfigDict, Field from sqlalchemy.orm import selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -26,16 +26,12 @@ class RecipeShareTokenSave(RecipeShareTokenCreate): class RecipeShareTokenSummary(RecipeShareTokenSave): id: UUID4 created_at: datetime - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeShareToken(RecipeShareTokenSummary): recipe: Recipe - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/schema/recipe/recipe_step.py b/mealie/schema/recipe/recipe_step.py index 6db07c215edd..6da3b4442a99 100644 --- a/mealie/schema/recipe/recipe_step.py +++ b/mealie/schema/recipe/recipe_step.py @@ -1,6 +1,6 @@ from uuid import UUID, uuid4 -from pydantic import UUID4, Field +from pydantic import UUID4, ConfigDict, Field from mealie.schema._mealie import MealieModel @@ -11,9 +11,7 @@ class IngredientReferences(MealieModel): """ reference_id: UUID4 | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeStep(MealieModel): @@ -21,6 +19,4 @@ class RecipeStep(MealieModel): title: str | None = "" text: str ingredient_references: list[IngredientReferences] = [] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/recipe/recipe_timeline_events.py b/mealie/schema/recipe/recipe_timeline_events.py index f344742dd919..364d2287485d 100644 --- a/mealie/schema/recipe/recipe_timeline_events.py +++ b/mealie/schema/recipe/recipe_timeline_events.py @@ -2,7 +2,7 @@ from datetime import datetime from enum import Enum from pathlib import Path -from pydantic import UUID4, Field +from pydantic import UUID4, ConfigDict, Field from mealie.core.config import get_app_dirs from mealie.schema._mealie.mealie_model import MealieModel @@ -35,9 +35,7 @@ class RecipeTimelineEventIn(MealieModel): image: TimelineEventImage | None = TimelineEventImage.does_not_have_image timestamp: datetime = datetime.now() - - class Config: - use_enum_values = True + model_config = ConfigDict(use_enum_values=True) class RecipeTimelineEventCreate(RecipeTimelineEventIn): @@ -48,18 +46,14 @@ class RecipeTimelineEventUpdate(MealieModel): subject: str message: str | None = Field(alias="eventMessage") image: TimelineEventImage | None = None - - class Config: - use_enum_values = True + model_config = ConfigDict(use_enum_values=True) class RecipeTimelineEventOut(RecipeTimelineEventCreate): id: UUID4 created_at: datetime update_at: datetime - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def image_dir_from_id(cls, recipe_id: UUID4 | str, timeline_event_id: UUID4 | str) -> Path: diff --git a/mealie/schema/recipe/recipe_tool.py b/mealie/schema/recipe/recipe_tool.py index 88c8478573cf..ae85617c5cdc 100644 --- a/mealie/schema/recipe/recipe_tool.py +++ b/mealie/schema/recipe/recipe_tool.py @@ -1,4 +1,4 @@ -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from sqlalchemy.orm import selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -19,16 +19,12 @@ class RecipeToolSave(RecipeToolCreate): class RecipeToolOut(RecipeToolCreate): id: UUID4 slug: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class RecipeToolResponse(RecipeToolOut): recipes: list["RecipeSummary"] = [] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/schema/recipe/request_helpers.py b/mealie/schema/recipe/request_helpers.py index 4b1a8c1a28d8..67df9b253577 100644 --- a/mealie/schema/recipe/request_helpers.py +++ b/mealie/schema/recipe/request_helpers.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict from mealie.schema._mealie import MealieModel @@ -10,8 +10,7 @@ class RecipeSlug(MealieModel): class SlugResponse(BaseModel): - class Config: - schema_extra = {"example": "adult-mac-and-cheese"} + model_config = ConfigDict(json_schema_extra={"example": "adult-mac-and-cheese"}) class UpdateImageResponse(BaseModel): @@ -23,4 +22,4 @@ class RecipeZipTokenResponse(BaseModel): class RecipeDuplicate(BaseModel): - name: str | None + name: str | None = None diff --git a/mealie/schema/reports/reports.py b/mealie/schema/reports/reports.py index df6583363073..b4a5aaf17dc6 100644 --- a/mealie/schema/reports/reports.py +++ b/mealie/schema/reports/reports.py @@ -1,7 +1,7 @@ import datetime import enum -from pydantic import Field +from pydantic import ConfigDict, Field from pydantic.types import UUID4 from sqlalchemy.orm import joinedload from sqlalchemy.orm.interfaces import LoaderOption @@ -34,9 +34,7 @@ class ReportEntryCreate(MealieModel): class ReportEntryOut(ReportEntryCreate): id: UUID4 - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class ReportCreate(MealieModel): @@ -53,9 +51,7 @@ class ReportSummary(ReportCreate): class ReportOut(ReportSummary): entries: list[ReportEntryOut] = [] - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/schema/response/pagination.py b/mealie/schema/response/pagination.py index f6605ed67dd2..e88e22a584e4 100644 --- a/mealie/schema/response/pagination.py +++ b/mealie/schema/response/pagination.py @@ -4,7 +4,6 @@ from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit from humps import camelize from pydantic import UUID4, BaseModel, validator -from pydantic.generics import GenericModel from mealie.schema._mealie import MealieModel @@ -34,6 +33,8 @@ class PaginationQuery(MealieModel): query_filter: str | None = None pagination_seed: str | None = None + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("pagination_seed", always=True, pre=True) def validate_randseed(cls, pagination_seed, values): if values.get("order_by") == "random" and not pagination_seed: @@ -41,7 +42,7 @@ class PaginationQuery(MealieModel): return pagination_seed -class PaginationBase(GenericModel, Generic[DataT]): +class PaginationBase(BaseModel, Generic[DataT]): page: int = 1 per_page: int = 10 total: int = 0 diff --git a/mealie/schema/server/tasks.py b/mealie/schema/server/tasks.py index 20b5faa4cf18..b467a0655d63 100644 --- a/mealie/schema/server/tasks.py +++ b/mealie/schema/server/tasks.py @@ -2,7 +2,7 @@ import datetime import enum from uuid import UUID -from pydantic import Field +from pydantic import ConfigDict, Field from mealie.schema._mealie import MealieModel from mealie.schema.response.pagination import PaginationBase @@ -43,9 +43,7 @@ class ServerTaskCreate(MealieModel): class ServerTask(ServerTaskCreate): id: int - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class ServerTaskPagination(PaginationBase): diff --git a/mealie/schema/user/auth.py b/mealie/schema/user/auth.py index 657eab590f9f..7ecf0dc2cc09 100644 --- a/mealie/schema/user/auth.py +++ b/mealie/schema/user/auth.py @@ -1,5 +1,6 @@ -from pydantic import UUID4, BaseModel -from pydantic.types import constr +from typing import Annotated + +from pydantic import UUID4, BaseModel, StringConstraints from mealie.schema._mealie.mealie_model import MealieModel @@ -10,8 +11,8 @@ class Token(BaseModel): class TokenData(BaseModel): - user_id: UUID4 | None - username: constr(to_lower=True, strip_whitespace=True) | None = None # type: ignore + user_id: UUID4 | None = None + username: Annotated[str, StringConstraints(to_lower=True, strip_whitespace=True)] | None = None # type: ignore class UnlockResults(MealieModel): diff --git a/mealie/schema/user/registration.py b/mealie/schema/user/registration.py index 6eadda5648e3..9f6b66597e9a 100644 --- a/mealie/schema/user/registration.py +++ b/mealie/schema/user/registration.py @@ -1,5 +1,7 @@ -from pydantic import validator -from pydantic.types import NoneStr, constr +from typing import Annotated + +from pydantic import StringConstraints, validator +from pydantic.types import NoneStr from mealie.schema._mealie import MealieModel from mealie.schema._mealie.validators import validate_locale @@ -8,8 +10,8 @@ from mealie.schema._mealie.validators import validate_locale class CreateUserRegistration(MealieModel): group: NoneStr = None group_token: NoneStr = None - email: constr(to_lower=True, strip_whitespace=True) # type: ignore - username: constr(to_lower=True, strip_whitespace=True) # type: ignore + email: Annotated[str, StringConstraints(to_lower=True, strip_whitespace=True)] # type: ignore + username: Annotated[str, StringConstraints(to_lower=True, strip_whitespace=True)] # type: ignore password: str password_confirm: str advanced: bool = False @@ -18,12 +20,16 @@ class CreateUserRegistration(MealieModel): seed_data: bool = False locale: str = "en-US" + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("locale") def valid_locale(cls, v, values, **kwargs): if not validate_locale(v): raise ValueError("invalid locale") return v + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("password_confirm") @classmethod def passwords_match(cls, value, values): @@ -31,6 +37,8 @@ class CreateUserRegistration(MealieModel): raise ValueError("passwords do not match") return value + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("group_token", always=True) @classmethod def group_or_token(cls, value, values): diff --git a/mealie/schema/user/user.py b/mealie/schema/user/user.py index 2240aeb730ec..3b2faf2e33f0 100644 --- a/mealie/schema/user/user.py +++ b/mealie/schema/user/user.py @@ -1,10 +1,9 @@ from datetime import datetime, timedelta from pathlib import Path -from typing import Any +from typing import Annotated, Any from uuid import UUID -from pydantic import UUID4, Field, validator -from pydantic.types import constr +from pydantic import UUID4, ConfigDict, Field, StringConstraints, field_validator from sqlalchemy.orm import joinedload, selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -35,24 +34,18 @@ class LongLiveTokenOut(MealieModel): name: str id: int created_at: datetime | None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class CreateToken(LongLiveTokenIn): user_id: UUID4 token: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class DeleteTokenResponse(MealieModel): token_delete: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class ChangePassword(MealieModel): @@ -62,15 +55,13 @@ class ChangePassword(MealieModel): class GroupBase(MealieModel): name: str - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) class UserBase(MealieModel): username: str | None full_name: str | None = None - email: constr(to_lower=True, strip_whitespace=True) # type: ignore + email: Annotated[str, StringConstraints(to_lower=True, strip_whitespace=True)] # type: ignore auth_method: AuthMethod = AuthMethod.MEALIE admin: bool = False group: str | None @@ -80,20 +71,17 @@ class UserBase(MealieModel): can_invite: bool = False can_manage: bool = False can_organize: bool = False - - class Config: - orm_mode = True - getter_dict = GroupGetterDict - - schema_extra = { - "example": { - "username": "ChangeMe", - "fullName": "Change Me", - "email": "changeme@email.com", - "group": settings.DEFAULT_GROUP, - "admin": "false", - } + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=GroupGetterDict, json_schema_extra={ + "example": { + "username": "ChangeMe", + "fullName": "Change Me", + "email": "changeme@email.com", + "group": settings.DEFAULT_GROUP, + "admin": "false", } + }) class UserIn(UserBase): @@ -107,11 +95,9 @@ class UserOut(UserBase): tokens: list[LongLiveTokenOut] | None cache_key: str favorite_recipes: list[str] | None = [] - - class Config: - orm_mode = True - - getter_dict = UserGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=UserGetterDict) @property def is_default_user(self) -> bool: @@ -128,10 +114,9 @@ class UserPagination(PaginationBase): class UserFavorites(UserBase): favorite_recipes: list[RecipeSummary] = [] # type: ignore - - class Config: - orm_mode = True - getter_dict = GroupGetterDict + # TODO[pydantic]: The following keys were removed: `getter_dict`. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. + model_config = ConfigDict(from_attributes=True, getter_dict=GroupGetterDict) @classmethod def loader_options(cls) -> list[LoaderOption]: @@ -148,11 +133,10 @@ class PrivateUser(UserOut): group_id: UUID4 login_attemps: int = 0 locked_at: datetime | None = None + model_config = ConfigDict(from_attributes=True) - class Config: - orm_mode = True - - @validator("login_attemps", pre=True) + @field_validator("login_attemps", mode="before") + @classmethod def none_to_zero(cls, v): return 0 if v is None else v @@ -189,9 +173,7 @@ class UpdateGroup(GroupBase): class GroupInDB(UpdateGroup): users: list[UserOut] | None preferences: ReadGroupPreferences | None = None - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @staticmethod def get_directory(id: UUID4) -> Path: @@ -232,6 +214,4 @@ class GroupPagination(PaginationBase): class LongLiveTokenInDB(CreateToken): id: int user: PrivateUser - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) diff --git a/mealie/schema/user/user_passwords.py b/mealie/schema/user/user_passwords.py index 9fe3235ace3a..3e10945eeb1b 100644 --- a/mealie/schema/user/user_passwords.py +++ b/mealie/schema/user/user_passwords.py @@ -1,4 +1,4 @@ -from pydantic import UUID4 +from pydantic import UUID4, ConfigDict from sqlalchemy.orm import selectinload from sqlalchemy.orm.interfaces import LoaderOption @@ -33,9 +33,7 @@ class SavePasswordResetToken(MealieModel): class PrivatePasswordResetToken(SavePasswordResetToken): user: PrivateUser - - class Config: - orm_mode = True + model_config = ConfigDict(from_attributes=True) @classmethod def loader_options(cls) -> list[LoaderOption]: diff --git a/mealie/services/event_bus_service/event_types.py b/mealie/services/event_bus_service/event_types.py index 93529f1db6a2..d0c72c16922c 100644 --- a/mealie/services/event_bus_service/event_types.py +++ b/mealie/services/event_bus_service/event_types.py @@ -177,8 +177,8 @@ class Event(MealieModel): document_data: EventDocumentDataBase # set at instantiation - event_id: UUID4 | None - timestamp: datetime | None + event_id: UUID4 | None = None + timestamp: datetime | None = None def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) diff --git a/mealie/services/parser_services/brute/process.py b/mealie/services/parser_services/brute/process.py index ade777cf8a1f..585f85f68f42 100644 --- a/mealie/services/parser_services/brute/process.py +++ b/mealie/services/parser_services/brute/process.py @@ -1,7 +1,7 @@ import string import unicodedata -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict from .._helpers import check_char, move_parens_to_end @@ -11,9 +11,7 @@ class BruteParsedIngredient(BaseModel): note: str = "" amount: float = 1.0 unit: str = "" - - class Config: - anystr_strip_whitespace = True + model_config = ConfigDict(str_strip_whitespace=True) def parse_fraction(x): diff --git a/mealie/services/parser_services/crfpp/processor.py b/mealie/services/parser_services/crfpp/processor.py index d0bf1b69cc66..f5c33dd4d332 100644 --- a/mealie/services/parser_services/crfpp/processor.py +++ b/mealie/services/parser_services/crfpp/processor.py @@ -31,6 +31,8 @@ class CRFIngredient(BaseModel): unit: str = "" confidence: CRFConfidence + # TODO[pydantic]: We couldn't refactor the `validator`, please replace it by `field_validator` manually. + # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-validators for more information. @validator("qty", always=True, pre=True) def validate_qty(qty, values): # sourcery skip: merge-nested-ifs if qty is None or qty == "": diff --git a/poetry.lock b/poetry.lock index 5aae63777ea4..20865acb3122 100644 --- a/poetry.lock +++ b/poetry.lock @@ -44,6 +44,17 @@ files = [ [package.extras] dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"] +[[package]] +name = "annotated-types" +version = "0.5.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.7" +files = [ + {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, + {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, +] + [[package]] name = "anyio" version = "3.6.2" @@ -545,24 +556,22 @@ cli = ["requests"] [[package]] name = "fastapi" -version = "0.95.0" +version = "0.101.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.95.0-py3-none-any.whl", hash = "sha256:daf73bbe844180200be7966f68e8ec9fd8be57079dff1bacb366db32729e6eb5"}, - {file = "fastapi-0.95.0.tar.gz", hash = "sha256:99d4fdb10e9dd9a24027ac1d0bd4b56702652056ca17a6c8721eec4ad2f14e18"}, + {file = "fastapi-0.101.0-py3-none-any.whl", hash = "sha256:494eb3494d89e8079c20859d7ca695f66eaccc40f46fe8c75ab6186d15f05ffd"}, + {file = "fastapi-0.101.0.tar.gz", hash = "sha256:ca2ae65fe42f6a34b5cf6c994337149154b1b400c39809d7b2dccdceb5ae77af"}, ] [package.dependencies] -pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = ">=0.26.1,<0.27.0" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.27.0,<0.28.0" +typing-extensions = ">=4.5.0" [package.extras] -all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" @@ -1696,55 +1705,150 @@ pyasn1 = ">=0.4.6,<0.5.0" [[package]] name = "pydantic" -version = "1.10.7" -description = "Data validation and settings management using python type hints" +version = "2.1.1" +description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, - {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, - {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, - {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, - {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, - {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, - {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, - {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, - {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, - {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, + {file = "pydantic-2.1.1-py3-none-any.whl", hash = "sha256:43bdbf359d6304c57afda15c2b95797295b702948082d4c23851ce752f21da70"}, + {file = "pydantic-2.1.1.tar.gz", hash = "sha256:22d63db5ce4831afd16e7c58b3192d3faf8f79154980d9397d9867254310ba4b"}, ] [package.dependencies] -typing-extensions = ">=4.2.0" +annotated-types = ">=0.4.0" +pydantic-core = "2.4.0" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.4.0" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.4.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:2ca4687dd996bde7f3c420def450797feeb20dcee2b9687023e3323c73fc14a2"}, + {file = "pydantic_core-2.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:782fced7d61469fd1231b184a80e4f2fa7ad54cd7173834651a453f96f29d673"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6213b471b68146af97b8551294e59e7392c2117e28ffad9c557c65087f4baee3"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63797499a219d8e81eb4e0c42222d0a4c8ec896f5c76751d4258af95de41fdf1"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:0455876d575a35defc4da7e0a199596d6c773e20d3d42fa1fc29f6aa640369ed"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:8c938c96294d983dcf419b54dba2d21056959c22911d41788efbf949a29ae30d"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:878a5017d93e776c379af4e7b20f173c82594d94fa073059bcc546789ad50bf8"}, + {file = "pydantic_core-2.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:69159afc2f2dc43285725f16143bc5df3c853bc1cb7df6021fce7ef1c69e8171"}, + {file = "pydantic_core-2.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54df7df399b777c1fd144f541c95d351b3aa110535a6810a6a569905d106b6f3"}, + {file = "pydantic_core-2.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e412607ca89a0ced10758dfb8f9adcc365ce4c1c377e637c01989a75e9a9ec8a"}, + {file = "pydantic_core-2.4.0-cp310-none-win32.whl", hash = "sha256:853f103e2b9a58832fdd08a587a51de8b552ae90e1a5d167f316b7eabf8d7dde"}, + {file = "pydantic_core-2.4.0-cp310-none-win_amd64.whl", hash = "sha256:3ba2c9c94a9176f6321a879c8b864d7c5b12d34f549a4c216c72ce213d7d953c"}, + {file = "pydantic_core-2.4.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:a8b7acd04896e8f161e1500dc5f218017db05c1d322f054e89cbd089ce5d0071"}, + {file = "pydantic_core-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:16468bd074fa4567592d3255bf25528ed41e6b616d69bf07096bdb5b66f947d1"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cba5ad5eef02c86a1f3da00544cbc59a510d596b27566479a7cd4d91c6187a11"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7206e41e04b443016e930e01685bab7a308113c0b251b3f906942c8d4b48fcb"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:c1375025f0bfc9155286ebae8eecc65e33e494c90025cda69e247c3ccd2bab00"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:3534118289e33130ed3f1cc487002e8d09b9f359be48b02e9cd3de58ce58fba9"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:94d2b36a74623caab262bf95f0e365c2c058396082bd9d6a9e825657d0c1e7fa"}, + {file = "pydantic_core-2.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:af24ad4fbaa5e4a2000beae0c3b7fd1c78d7819ab90f9370a1cfd8998e3f8a3c"}, + {file = "pydantic_core-2.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bf10963d8aed8bbe0165b41797c9463d4c5c8788ae6a77c68427569be6bead41"}, + {file = "pydantic_core-2.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68199ada7c310ddb8c76efbb606a0de656b40899388a7498954f423e03fc38be"}, + {file = "pydantic_core-2.4.0-cp311-none-win32.whl", hash = "sha256:6f855bcc96ed3dd56da7373cfcc9dcbabbc2073cac7f65c185772d08884790ce"}, + {file = "pydantic_core-2.4.0-cp311-none-win_amd64.whl", hash = "sha256:de39eb3bab93a99ddda1ac1b9aa331b944d8bcc4aa9141148f7fd8ee0299dafc"}, + {file = "pydantic_core-2.4.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:f773b39780323a0499b53ebd91a28ad11cde6705605d98d999dfa08624caf064"}, + {file = "pydantic_core-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a297c0d6c61963c5c3726840677b798ca5b7dfc71bc9c02b9a4af11d23236008"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:546064c55264156b973b5e65e5fafbe5e62390902ce3cf6b4005765505e8ff56"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36ba9e728588588f0196deaf6751b9222492331b5552f865a8ff120869d372e0"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_24_armv7l.whl", hash = "sha256:57a53a75010c635b3ad6499e7721eaa3b450e03f6862afe2dbef9c8f66e46ec8"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_24_ppc64le.whl", hash = "sha256:4b262bbc13022f2097c48a21adcc360a81d83dc1d854c11b94953cd46d7d3c07"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_24_s390x.whl", hash = "sha256:01947ad728f426fa07fcb26457ebf90ce29320259938414bc0edd1476e75addb"}, + {file = "pydantic_core-2.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b2799c2eaf182769889761d4fb4d78b82bc47dae833799fedbf69fc7de306faa"}, + {file = "pydantic_core-2.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a08fd490ba36d1fbb2cd5dcdcfb9f3892deb93bd53456724389135712b5fc735"}, + {file = "pydantic_core-2.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1e8a7c62d15a5c4b307271e4252d76ebb981d6251c6ecea4daf203ef0179ea4f"}, + {file = "pydantic_core-2.4.0-cp312-none-win32.whl", hash = "sha256:9206c14a67c38de7b916e486ae280017cf394fa4b1aa95cfe88621a4e1d79725"}, + {file = "pydantic_core-2.4.0-cp312-none-win_amd64.whl", hash = "sha256:884235507549a6b2d3c4113fb1877ae263109e787d9e0eb25c35982ab28d0399"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:4cbe929efa77a806e8f1a97793f2dc3ea3475ae21a9ed0f37c21320fe93f6f50"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:9137289de8fe845c246a8c3482dd0cb40338846ba683756d8f489a4bd8fddcae"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5d8e764b5646623e57575f624f8ebb8f7a9f7fd1fae682ef87869ca5fec8dcf"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fba0aff4c407d0274e43697e785bcac155ad962be57518d1c711f45e72da70f"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:30527d173e826f2f7651f91c821e337073df1555e3b5a0b7b1e2c39e26e50678"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:bd7d1dde70ff3e09e4bc7a1cbb91a7a538add291bfd5b3e70ef1e7b45192440f"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:72f1216ca8cef7b8adacd4c4c6b89c3b0c4f97503197f5284c80f36d6e4edd30"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b013c7861a7c7bfcec48fd709513fea6f9f31727e7a0a93ca0dd12e056740717"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:478f5f6d7e32bd4a04d102160efb2d389432ecf095fe87c555c0a6fc4adfc1a4"}, + {file = "pydantic_core-2.4.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d9610b47b5fe4aacbbba6a9cb5f12cbe864eec99dbfed5710bd32ef5dd8a5d5b"}, + {file = "pydantic_core-2.4.0-cp37-none-win32.whl", hash = "sha256:ff246c0111076c8022f9ba325c294f2cb5983403506989253e04dbae565e019b"}, + {file = "pydantic_core-2.4.0-cp37-none-win_amd64.whl", hash = "sha256:d0c2b713464a8e263a243ae7980d81ce2de5ac59a9f798a282e44350b42dc516"}, + {file = "pydantic_core-2.4.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:12ef6838245569fd60a179fade81ca4b90ae2fa0ef355d616f519f7bb27582db"}, + {file = "pydantic_core-2.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49db206eb8fdc4b4f30e6e3e410584146d813c151928f94ec0db06c4f2595538"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a507d7fa44688bbac76af6521e488b3da93de155b9cba6f2c9b7833ce243d59"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffe18407a4d000c568182ce5388bbbedeb099896904e43fc14eee76cfae6dec5"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:fa8e48001b39d54d97d7b380a0669fa99fc0feeb972e35a2d677ba59164a9a22"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:394f12a2671ff8c4dfa2e85be6c08be0651ad85bc1e6aa9c77c21671baaf28cd"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:2f9ea0355f90db2a76af530245fa42f04d98f752a1236ed7c6809ec484560d5b"}, + {file = "pydantic_core-2.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:61d4e713f467abcdd59b47665d488bb898ad3dd47ce7446522a50e0cbd8e8279"}, + {file = "pydantic_core-2.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:453862ab268f6326b01f067ed89cb3a527d34dc46f6f4eeec46a15bbc706d0da"}, + {file = "pydantic_core-2.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:56a85fa0dab1567bd0cac10f0c3837b03e8a0d939e6a8061a3a420acd97e9421"}, + {file = "pydantic_core-2.4.0-cp38-none-win32.whl", hash = "sha256:0d726108c1c0380b88b6dd4db559f0280e0ceda9e077f46ff90bc85cd4d03e77"}, + {file = "pydantic_core-2.4.0-cp38-none-win_amd64.whl", hash = "sha256:047580388644c473b934d27849f8ed8dbe45df0adb72104e78b543e13bf69762"}, + {file = "pydantic_core-2.4.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:867d3eea954bea807cabba83cfc939c889a18576d66d197c60025b15269d7cc0"}, + {file = "pydantic_core-2.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:664402ef0c238a7f8a46efb101789d5f2275600fb18114446efec83cfadb5b66"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64e8012ad60a5f0da09ed48725e6e923d1be25f2f091a640af6079f874663813"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac2b680de398f293b68183317432b3d67ab3faeba216aec18de0c395cb5e3060"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:8efc1be43b036c2b6bcfb1451df24ee0ddcf69c31351003daf2699ed93f5687b"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:d93aedbc4614cc21b9ab0d0c4ccd7143354c1f7cffbbe96ae5216ad21d1b21b5"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:af788b64e13d52fc3600a68b16d31fa8d8573e3ff2fc9a38f8a60b8d94d1f012"}, + {file = "pydantic_core-2.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97c6349c81cee2e69ef59eba6e6c08c5936e6b01c2d50b9e4ac152217845ae09"}, + {file = "pydantic_core-2.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cc086ddb6dc654a15deeed1d1f2bcb1cb924ebd70df9dca738af19f64229b06c"}, + {file = "pydantic_core-2.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e953353180bec330c3b830891d260b6f8e576e2d18db3c78d314e56bb2276066"}, + {file = "pydantic_core-2.4.0-cp39-none-win32.whl", hash = "sha256:6feb4b64d11d5420e517910d60a907d08d846cacaf4e029668725cd21d16743c"}, + {file = "pydantic_core-2.4.0-cp39-none-win_amd64.whl", hash = "sha256:153a61ac4030fa019b70b31fb7986461119230d3ba0ab661c757cfea652f4332"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:3fcf529382b282a30b466bd7af05be28e22aa620e016135ac414f14e1ee6b9e1"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2edef05b63d82568b877002dc4cb5cc18f8929b59077120192df1e03e0c633f8"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da055a1b0bfa8041bb2ff586b2cb0353ed03944a3472186a02cc44a557a0e661"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:77dadc764cf7c5405e04866181c5bd94a447372a9763e473abb63d1dfe9b7387"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a4ea23b07f29487a7bef2a869f68c7ee0e05424d81375ce3d3de829314c6b5ec"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:382f0baa044d674ad59455a5eff83d7965572b745cc72df35c52c2ce8c731d37"}, + {file = "pydantic_core-2.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:08f89697625e453421401c7f661b9d1eb4c9e4c0a12fd256eeb55b06994ac6af"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:43a405ce520b45941df9ff55d0cd09762017756a7b413bbad3a6e8178e64a2c2"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:584a7a818c84767af16ce8bda5d4f7fedb37d3d231fc89928a192f567e4ef685"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04922fea7b13cd480586fa106345fe06e43220b8327358873c22d8dfa7a711c7"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17156abac20a9feed10feec867fddd91a80819a485b0107fe61f09f2117fe5f3"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4e562cc63b04636cde361fd47569162f1daa94c759220ff202a8129902229114"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:90f3785146f701e053bb6b9e8f53acce2c919aca91df88bd4975be0cb926eb41"}, + {file = "pydantic_core-2.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e40b1e97edd3dc127aa53d8a5e539a3d0c227d71574d3f9ac1af02d58218a122"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:b27f3e67f6e031f6620655741b7d0d6bebea8b25d415924b3e8bfef2dd7bd841"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be86c2eb12fb0f846262ace9d8f032dc6978b8cb26a058920ecb723dbcb87d05"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4665f7ed345012a8d2eddf4203ef145f5f56a291d010382d235b94e91813f88a"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:79262be5a292d1df060f29b9a7cdd66934801f987a817632d7552534a172709a"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5fd905a69ac74eaba5041e21a1e8b1a479dab2b41c93bdcc4c1cede3c12a8d86"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:2ad538b7e07343001934417cdc8584623b4d8823c5b8b258e75ec8d327cec969"}, + {file = "pydantic_core-2.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:dd2429f7635ad4857b5881503f9c310be7761dc681c467a9d27787b674d1250a"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:efff8b6761a1f6e45cebd1b7a6406eb2723d2d5710ff0d1b624fe11313693989"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32a1e0352558cd7ccc014ffe818c7d87b15ec6145875e2cc5fa4bb7351a1033d"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a027f41c5008571314861744d83aff75a34cf3a07022e0be32b214a5bc93f7f1"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1927f0e15d190f11f0b8344373731e28fd774c6d676d8a6cfadc95c77214a48b"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7aa82d483d5fb867d4fb10a138ffd57b0f1644e99f2f4f336e48790ada9ada5e"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b85778308bf945e9b33ac604e6793df9b07933108d20bdf53811bc7c2798a4af"}, + {file = "pydantic_core-2.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3ded19dcaefe2f6706d81e0db787b59095f4ad0fbadce1edffdf092294c8a23f"}, + {file = "pydantic_core-2.4.0.tar.gz", hash = "sha256:ec3473c9789cc00c7260d840c3db2c16dbfc816ca70ec87a00cddfa3e1a1cdd5"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.0.2" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_settings-2.0.2-py3-none-any.whl", hash = "sha256:6183a2abeab465d5a3ab69758e9a22d38b0cc2ba193f0b85f6971a252ea630f6"}, + {file = "pydantic_settings-2.0.2.tar.gz", hash = "sha256:342337fff50b23585e807a86dec85037900972364435c55c2fc00d16ff080539"}, +] + +[package.dependencies] +pydantic = ">=2.0.1" +python-dotenv = ">=0.21.0" [[package]] name = "pydantic-to-typescript" @@ -2453,13 +2557,13 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "starlette" -version = "0.26.1" +version = "0.27.0" description = "The little ASGI library that shines." optional = false python-versions = ">=3.7" files = [ - {file = "starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"}, - {file = "starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"}, + {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, + {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, ] [package.dependencies] @@ -2561,13 +2665,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.4.0" +version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] [[package]] @@ -2935,4 +3039,4 @@ pgsql = ["psycopg2-binary"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "6ec46a82cad73c78013d1729df179a3fb5c4e12eb2a11ca04b2412d6b8e5b25f" +content-hash = "86c45be1f77b9a37fe0933536a5ca4dda9e8bfafd94ce008db9070e870c9cbd1" diff --git a/pyproject.toml b/pyproject.toml index f6601bb6d18e..f5a97cd44e48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,14 +20,14 @@ appdirs = "1.4.4" apprise = "^1.2.0" bcrypt = "^4.0.1" extruct = "^0.14.0" -fastapi = "^0.95.0" +fastapi = "^0.101.0" gunicorn = "^20.1.0" httpx = "^0.23.1" lxml = "^4.7.1" orjson = "^3.8.0" passlib = "^1.7.4" psycopg2-binary = {version = "^2.9.1", optional = true} -pydantic = "^1.10.4" +pydantic = "^2.1.1" pyhumps = "^3.5.3" pytesseract = "^0.3.9" python = "^3.10" @@ -43,6 +43,7 @@ tzdata = "^2022.7" uvicorn = {extras = ["standard"], version = "^0.21.0"} beautifulsoup4 = "^4.11.2" isodate = "^0.6.1" +pydantic-settings = "^2.0.2" [tool.poetry.group.dev.dependencies] black = "^23.1.0"