diff --git a/mealie/schema/_mealie/mealie_model.py b/mealie/schema/_mealie/mealie_model.py index d7d70a6dc..ec54c3ff1 100644 --- a/mealie/schema/_mealie/mealie_model.py +++ b/mealie/schema/_mealie/mealie_model.py @@ -4,7 +4,7 @@ import re from collections.abc import Sequence from datetime import UTC, datetime from enum import Enum -from typing import ClassVar, Protocol, Self, TypeVar +from typing import ClassVar, Protocol, Self from humps.main import camelize from pydantic import UUID4, AliasChoices, BaseModel, ConfigDict, Field, model_validator @@ -14,8 +14,6 @@ from sqlalchemy.orm.interfaces import LoaderOption from mealie.db.models._model_base import SqlAlchemyBase -T = TypeVar("T", bound=BaseModel) - HOUR_ONLY_TZ_PATTERN = re.compile(r"[+-]\d{2}$") @@ -56,7 +54,7 @@ class MealieModel(BaseModel): @model_validator(mode="before") @classmethod - def fix_hour_only_tz(cls, data: T) -> T: + def fix_hour_only_tz[T: BaseModel](cls, data: T) -> T: """ Fixes datetimes with timezones that only have the hour portion. @@ -91,7 +89,7 @@ class MealieModel(BaseModel): return self - def cast(self, cls: type[T], **kwargs) -> T: + def cast[T: BaseModel](self, cls: type[T], **kwargs) -> T: """ Cast the current model to another with additional arguments. Useful for transforming DTOs into models that are saved to a database @@ -100,7 +98,7 @@ class MealieModel(BaseModel): create_data.update(kwargs or {}) return cls(**create_data) - def map_to(self, dest: T) -> T: + def map_to[T: BaseModel](self, dest: T) -> T: """ Map matching values from the current model to another model. Model returned for method chaining. @@ -121,7 +119,7 @@ class MealieModel(BaseModel): if field in self.model_fields: setattr(self, field, getattr(src, field)) - def merge(self, src: T, replace_null=False): + def merge[T: BaseModel](self, src: T, replace_null=False): """ Replace matching values from another instance to the current instance. """ diff --git a/mealie/schema/response/query_filter.py b/mealie/schema/response/query_filter.py index eb7651a3f..9e41490f3 100644 --- a/mealie/schema/response/query_filter.py +++ b/mealie/schema/response/query_filter.py @@ -3,7 +3,7 @@ from __future__ import annotations import re from collections import deque from enum import Enum -from typing import Any, TypeVar, cast +from typing import Any, cast from uuid import UUID import sqlalchemy as sa @@ -19,8 +19,6 @@ from mealie.db.models._model_utils.datetime import NaiveDateTime from mealie.db.models._model_utils.guid import GUID from mealie.schema._mealie.mealie_model import MealieModel -Model = TypeVar("Model", bound=SqlAlchemyBase) - class RelationalKeyword(Enum): IS = "IS" @@ -274,7 +272,7 @@ class QueryFilterBuilder: return consolidated_group_builder.self_group() @classmethod - def get_model_and_model_attr_from_attr_string( + def get_model_and_model_attr_from_attr_string[Model: SqlAlchemyBase]( cls, attr_string: str, model: type[Model], *, query: sa.Select | None = None ) -> tuple[SqlAlchemyBase, InstrumentedAttribute, sa.Select | None]: """ @@ -343,7 +341,7 @@ class QueryFilterBuilder: return model_attr @classmethod - def _get_filter_element( + def _get_filter_element[Model: SqlAlchemyBase]( cls, query: sa.Select, component: QueryFilterBuilderComponent, @@ -397,7 +395,7 @@ class QueryFilterBuilder: return element - def filter_query( + def filter_query[Model: SqlAlchemyBase]( self, query: sa.Select, model: type[Model], column_aliases: dict[str, sa.ColumnElement] | None = None ) -> sa.Select: """ diff --git a/mealie/services/migrations/utils/database_helpers.py b/mealie/services/migrations/utils/database_helpers.py index d8e860195..80db1acd3 100644 --- a/mealie/services/migrations/utils/database_helpers.py +++ b/mealie/services/migrations/utils/database_helpers.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections.abc import Iterable -from typing import TYPE_CHECKING, TypeVar +from typing import TYPE_CHECKING from pydantic import BaseModel from slugify import slugify @@ -12,8 +12,6 @@ from mealie.schema.recipe import RecipeCategory from mealie.schema.recipe.recipe import RecipeTag from mealie.schema.recipe.recipe_category import CategoryOut, CategorySave, TagOut, TagSave -T = TypeVar("T", bound=BaseModel) - if TYPE_CHECKING: from mealie.repos.repository_generic import RepositoryGeneric @@ -23,7 +21,7 @@ class DatabaseMigrationHelpers: self.session = session self.db = db - def _get_or_set_generic( + def _get_or_set_generic[T: BaseModel]( self, accessor: RepositoryGeneric, items: Iterable[str], create_model: type[T], out_model: type[T] ) -> list[T]: """ diff --git a/mealie/services/parser_services/_base.py b/mealie/services/parser_services/_base.py index 33e5a265c..1a2be34cc 100644 --- a/mealie/services/parser_services/_base.py +++ b/mealie/services/parser_services/_base.py @@ -1,5 +1,4 @@ from abc import ABC, abstractmethod -from typing import TypeVar from pydantic import UUID4, BaseModel from rapidfuzz import fuzz, process @@ -17,8 +16,6 @@ from mealie.schema.recipe.recipe_ingredient import ( ) from mealie.schema.response.pagination import PaginationQuery -T = TypeVar("T", bound=BaseModel) - class DataMatcher: def __init__( @@ -83,7 +80,9 @@ class DataMatcher: return self._units_by_alias @classmethod - def find_match(cls, match_value: str, *, store_map: dict[str, T], fuzzy_match_threshold: int = 0) -> T | None: + def find_match[T: BaseModel]( + cls, match_value: str, *, store_map: dict[str, T], fuzzy_match_threshold: int = 0 + ) -> T | None: # check for literal matches if match_value in store_map: return store_map[match_value]