feat: Upgrade to Pydantic V2 (#3134)

* bumped pydantic
This commit is contained in:
Michael Genson
2024-02-11 10:47:37 -06:00
committed by GitHub
parent 248459671e
commit 7a107584c7
129 changed files with 1138 additions and 833 deletions

View File

@@ -1,11 +1,13 @@
from __future__ import annotations
import datetime
from numbers import Number
from pathlib import Path
from typing import Any, ClassVar
from typing import Annotated, Any, ClassVar
from uuid import uuid4
from pydantic import UUID4, BaseModel, Field, validator
from pydantic import UUID4, BaseModel, ConfigDict, Field, field_validator
from pydantic_core.core_schema import ValidationInfo
from slugify import slugify
from sqlalchemy import Select, desc, func, or_, select, text
from sqlalchemy.orm import Session, joinedload, selectinload
@@ -22,7 +24,6 @@ from ...db.models.recipe import (
RecipeInstruction,
RecipeModel,
)
from ..getter_dict import ExtrasGetterDict
from .recipe_asset import RecipeAsset
from .recipe_comments import RecipeCommentOut
from .recipe_notes import RecipeNote
@@ -39,9 +40,7 @@ class RecipeTag(MealieModel):
slug: str
_searchable_properties: ClassVar[list[str]] = ["name"]
class Config:
orm_mode = True
model_config = ConfigDict(from_attributes=True)
class RecipeTagPagination(PaginationBase):
@@ -80,16 +79,16 @@ class CreateRecipe(MealieModel):
class RecipeSummary(MealieModel):
id: UUID4 | None
id: UUID4 | None = None
_normalize_search: ClassVar[bool] = True
user_id: UUID4 = Field(default_factory=uuid4)
group_id: UUID4 = Field(default_factory=uuid4)
user_id: UUID4 = Field(default_factory=uuid4, validate_default=True)
group_id: UUID4 = Field(default_factory=uuid4, validate_default=True)
name: str | None
slug: str = ""
image: Any | None
recipe_yield: str | None
name: str | None = None
slug: Annotated[str, Field(validate_default=True)] = ""
image: Any | None = None
recipe_yield: str | None = None
total_time: str | None = None
prep_time: str | None = None
@@ -97,21 +96,28 @@ class RecipeSummary(MealieModel):
perform_time: str | None = None
description: str | None = ""
recipe_category: list[RecipeCategory] | None = []
tags: list[RecipeTag] | None = []
recipe_category: Annotated[list[RecipeCategory] | None, Field(validate_default=True)] | None = []
tags: Annotated[list[RecipeTag] | None, Field(validate_default=True)] = []
tools: list[RecipeTool] = []
rating: int | None
rating: int | None = None
org_url: str | None = Field(None, alias="orgURL")
date_added: datetime.date | None
date_updated: datetime.datetime | None
date_added: datetime.date | None = None
date_updated: datetime.datetime | None = None
created_at: datetime.datetime | None
update_at: datetime.datetime | None
last_made: datetime.datetime | None
created_at: datetime.datetime | None = None
update_at: datetime.datetime | None = None
last_made: datetime.datetime | None = None
model_config = ConfigDict(from_attributes=True)
class Config:
orm_mode = True
@field_validator("recipe_yield", "total_time", "prep_time", "cook_time", "perform_time", mode="before")
def clean_strings(val: Any):
if val is None:
return val
if isinstance(val, Number):
return str(val)
return val
class RecipePagination(PaginationBase):
@@ -119,9 +125,9 @@ class RecipePagination(PaginationBase):
class Recipe(RecipeSummary):
recipe_ingredient: list[RecipeIngredient] = []
recipe_ingredient: Annotated[list[RecipeIngredient], Field(validate_default=True)] = []
recipe_instructions: list[RecipeStep] | None = []
nutrition: Nutrition | None
nutrition: Nutrition | None = None
# Mealie Specific
settings: RecipeSettings | None = None
@@ -175,13 +181,11 @@ class Recipe(RecipeSummary):
return self.image_dir_from_id(self.id)
class Config:
orm_mode = True
getter_dict = ExtrasGetterDict
model_config = ConfigDict(from_attributes=True)
@classmethod
def from_orm(cls, obj):
recipe = super().from_orm(obj)
def model_validate(cls, obj):
recipe = super().model_validate(obj)
recipe.__post_init__()
return recipe
@@ -198,15 +202,15 @@ class Recipe(RecipeSummary):
ingredient.is_food = not ingredient.disable_amount
ingredient.display = ingredient._format_display()
@validator("slug", always=True, pre=True, allow_reuse=True)
def validate_slug(slug: str, values): # type: ignore
if not values.get("name"):
@field_validator("slug", mode="before")
def validate_slug(slug: str, info: ValidationInfo):
if not info.data.get("name"):
return slug
return slugify(values["name"])
return slugify(info.data["name"])
@validator("recipe_ingredient", always=True, pre=True, allow_reuse=True)
def validate_ingredients(recipe_ingredient, values):
@field_validator("recipe_ingredient", mode="before")
def validate_ingredients(recipe_ingredient):
if not recipe_ingredient or not isinstance(recipe_ingredient, list):
return recipe_ingredient
@@ -215,30 +219,37 @@ class Recipe(RecipeSummary):
return recipe_ingredient
@validator("tags", always=True, pre=True, allow_reuse=True)
def validate_tags(cats: list[Any]): # type: ignore
@field_validator("tags", mode="before")
def validate_tags(cats: list[Any]):
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
@validator("recipe_category", always=True, pre=True, allow_reuse=True)
def validate_categories(cats: list[Any]): # type: ignore
@field_validator("recipe_category", mode="before")
def validate_categories(cats: list[Any]):
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
@validator("group_id", always=True, pre=True, allow_reuse=True)
@field_validator("group_id", mode="before")
def validate_group_id(group_id: Any):
if isinstance(group_id, int):
return uuid4()
return group_id
@validator("user_id", always=True, pre=True, allow_reuse=True)
@field_validator("user_id", mode="before")
def validate_user_id(user_id: Any):
if isinstance(user_id, int):
return uuid4()
return user_id
@field_validator("extras", mode="before")
def convert_extras_to_dict(cls, v):
if isinstance(v, dict):
return v
return {x.key_name: x.value for x in v} if v else {}
@classmethod
def loader_options(cls) -> list[LoaderOption]:
return [
@@ -332,5 +343,5 @@ class RecipeLastMade(BaseModel):
from mealie.schema.recipe.recipe_ingredient import RecipeIngredient # noqa: E402
RecipeSummary.update_forward_refs()
Recipe.update_forward_refs()
RecipeSummary.model_rebuild()
Recipe.model_rebuild()