mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-10 04:15:38 -05:00
chore(deps): update dependency ruff to ^0.12.0 (#5568)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import abc
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
import jwt
|
||||
from sqlalchemy.orm.session import Session
|
||||
@@ -13,10 +12,8 @@ ALGORITHM = "HS256"
|
||||
ISS = "mealie"
|
||||
remember_me_duration = timedelta(days=14)
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class AuthProvider(Generic[T], metaclass=abc.ABCMeta):
|
||||
class AuthProvider[T](metaclass=abc.ABCMeta):
|
||||
"""Base Authentication Provider interface"""
|
||||
|
||||
def __init__(self, session: Session, data: T) -> None:
|
||||
|
||||
@@ -4,7 +4,7 @@ import random
|
||||
from collections.abc import Iterable
|
||||
from datetime import UTC, datetime
|
||||
from math import ceil
|
||||
from typing import Any, Generic, TypeVar
|
||||
from typing import Any
|
||||
|
||||
from fastapi import HTTPException
|
||||
from pydantic import UUID4, BaseModel
|
||||
@@ -28,18 +28,13 @@ from mealie.schema.response.query_search import SearchFilter
|
||||
|
||||
from ._utils import NOT_SET, NotSet
|
||||
|
||||
Schema = TypeVar("Schema", bound=MealieModel)
|
||||
Model = TypeVar("Model", bound=SqlAlchemyBase)
|
||||
|
||||
T = TypeVar("T", bound="RepositoryGeneric")
|
||||
|
||||
|
||||
class RepositoryGeneric(Generic[Schema, Model]):
|
||||
class RepositoryGeneric[Schema: MealieModel, Model: SqlAlchemyBase]:
|
||||
"""A Generic BaseAccess Model method to perform common operations on the database
|
||||
|
||||
Args:
|
||||
Generic ([Schema]): Represents the Pydantic Model
|
||||
Generic ([Model]): Represents the SqlAlchemyModel Model
|
||||
Schema: Represents the Pydantic Model
|
||||
Model: Represents the SqlAlchemyModel Model
|
||||
"""
|
||||
|
||||
session: Session
|
||||
@@ -467,7 +462,7 @@ class RepositoryGeneric(Generic[Schema, Model]):
|
||||
return search_filter.filter_query_by_search(query, schema, self.model)
|
||||
|
||||
|
||||
class GroupRepositoryGeneric(RepositoryGeneric[Schema, Model]):
|
||||
class GroupRepositoryGeneric[Schema: MealieModel, Model: SqlAlchemyBase](RepositoryGeneric[Schema, Model]):
|
||||
def __init__(
|
||||
self,
|
||||
session: Session,
|
||||
@@ -483,7 +478,7 @@ class GroupRepositoryGeneric(RepositoryGeneric[Schema, Model]):
|
||||
self._group_id = group_id if group_id else None
|
||||
|
||||
|
||||
class HouseholdRepositoryGeneric(RepositoryGeneric[Schema, Model]):
|
||||
class HouseholdRepositoryGeneric[Schema: MealieModel, Model: SqlAlchemyBase](RepositoryGeneric[Schema, Model]):
|
||||
def __init__(
|
||||
self,
|
||||
session: Session,
|
||||
|
||||
@@ -6,20 +6,18 @@ See their repository for details -> https://github.com/dmontagu/fastapi-utils
|
||||
|
||||
import inspect
|
||||
from collections.abc import Callable
|
||||
from typing import Any, ClassVar, ForwardRef, TypeVar, cast, get_origin, get_type_hints
|
||||
from typing import Any, ClassVar, ForwardRef, cast, get_origin, get_type_hints
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi.routing import APIRoute
|
||||
from starlette.routing import Route, WebSocketRoute
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
CBV_CLASS_KEY = "__cbv_class__"
|
||||
INCLUDE_INIT_PARAMS_KEY = "__include_init_params__"
|
||||
RETURN_TYPES_FUNC_KEY = "__return_types_func__"
|
||||
|
||||
|
||||
def controller(router: APIRouter, *urls: str) -> Callable[[type[T]], type[T]]:
|
||||
def controller[T](router: APIRouter, *urls: str) -> Callable[[type[T]], type[T]]:
|
||||
"""
|
||||
This function returns a decorator that converts the decorated into a class-based view for the provided router.
|
||||
Any methods of the decorated class that are decorated as endpoints using the router provided to this function
|
||||
@@ -36,7 +34,7 @@ def controller(router: APIRouter, *urls: str) -> Callable[[type[T]], type[T]]:
|
||||
return decorator
|
||||
|
||||
|
||||
def _cbv(router: APIRouter, cls: type[T], *urls: str, instance: Any | None = None) -> type[T]:
|
||||
def _cbv[T](router: APIRouter, cls: type[T], *urls: str, instance: Any | None = None) -> type[T]:
|
||||
"""
|
||||
Replaces any methods of the provided class `cls` that are endpoints of routes in `router` with updated
|
||||
function calls that will properly inject an instance of `cls`.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from collections.abc import Callable
|
||||
from logging import Logger
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
import sqlalchemy.exc
|
||||
from fastapi import HTTPException, status
|
||||
@@ -9,12 +8,8 @@ from pydantic import UUID4, BaseModel
|
||||
from mealie.repos.repository_generic import RepositoryGeneric
|
||||
from mealie.schema.response import ErrorResponse
|
||||
|
||||
C = TypeVar("C", bound=BaseModel)
|
||||
R = TypeVar("R", bound=BaseModel)
|
||||
U = TypeVar("U", bound=BaseModel)
|
||||
|
||||
|
||||
class HttpRepo(Generic[C, R, U]):
|
||||
class HttpRepo[C: BaseModel, R: BaseModel, U: BaseModel]:
|
||||
"""
|
||||
The HttpRepo[C, R, U] class is a mixin class that provides a common set of methods for CRUD operations.
|
||||
This class is intended to be used in a composition pattern where a class has a mixin property. For example:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -82,7 +80,7 @@ class MealieModel(BaseModel):
|
||||
Adds UTC timezone information to all datetimes in the model.
|
||||
The server stores everything in UTC without timezone info.
|
||||
"""
|
||||
for field in self.model_fields:
|
||||
for field in self.__class__.model_fields:
|
||||
val = getattr(self, field)
|
||||
if not isinstance(val, datetime):
|
||||
continue
|
||||
@@ -91,23 +89,25 @@ 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
|
||||
"""
|
||||
create_data = {field: getattr(self, field) for field in self.model_fields if field in cls.model_fields}
|
||||
create_data = {
|
||||
field: getattr(self, field) for field in self.__class__.model_fields if field in cls.model_fields
|
||||
}
|
||||
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.
|
||||
"""
|
||||
|
||||
for field in self.model_fields:
|
||||
if field in dest.model_fields:
|
||||
for field in self.__class__.model_fields:
|
||||
if field in dest.__class__.model_fields:
|
||||
setattr(dest, field, getattr(self, field))
|
||||
|
||||
return dest
|
||||
@@ -117,18 +117,18 @@ class MealieModel(BaseModel):
|
||||
Map matching values from another model to the current model.
|
||||
"""
|
||||
|
||||
for field in src.model_fields:
|
||||
if field in self.model_fields:
|
||||
for field in src.__class__.model_fields:
|
||||
if field in self.__class__.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.
|
||||
"""
|
||||
|
||||
for field in src.model_fields:
|
||||
for field in src.__class__.model_fields:
|
||||
val = getattr(src, field)
|
||||
if field in self.model_fields and (val is not None or replace_null):
|
||||
if field in self.__class__.model_fields and (val is not None or replace_null):
|
||||
setattr(self, field, val)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
from typing import TypeVar
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
U = TypeVar("U", bound=BaseModel)
|
||||
|
||||
|
||||
def mapper(source: U, dest: T, **_) -> T:
|
||||
def mapper[U: BaseModel, T: BaseModel](source: U, dest: T, **_) -> T:
|
||||
"""
|
||||
Map a source model to a destination model. Only top-level fields are mapped.
|
||||
"""
|
||||
|
||||
for field in source.model_fields:
|
||||
if field in dest.model_fields:
|
||||
for field in source.__class__.model_fields:
|
||||
if field in dest.__class__.model_fields:
|
||||
setattr(dest, field, getattr(source, field))
|
||||
|
||||
return dest
|
||||
|
||||
|
||||
def cast(source: U, dest: type[T], **kwargs) -> T:
|
||||
create_data = {field: getattr(source, field) for field in source.model_fields if field in dest.model_fields}
|
||||
def cast[U: BaseModel, T: BaseModel](source: U, dest: type[T], **kwargs) -> T:
|
||||
create_data = {
|
||||
field: getattr(source, field) for field in source.__class__.model_fields if field in dest.model_fields
|
||||
}
|
||||
create_data.update(kwargs or {})
|
||||
return dest(**create_data)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import enum
|
||||
from typing import Annotated, Any, Generic, TypeVar
|
||||
from typing import Annotated, Any
|
||||
from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit
|
||||
|
||||
from humps import camelize
|
||||
@@ -8,8 +8,6 @@ from pydantic_core.core_schema import ValidationInfo
|
||||
|
||||
from mealie.schema._mealie import MealieModel
|
||||
|
||||
DataT = TypeVar("DataT", bound=BaseModel)
|
||||
|
||||
|
||||
class OrderDirection(str, enum.Enum):
|
||||
asc = "asc"
|
||||
@@ -50,7 +48,7 @@ class PaginationQuery(RequestQuery):
|
||||
per_page: int = 50
|
||||
|
||||
|
||||
class PaginationBase(BaseModel, Generic[DataT]):
|
||||
class PaginationBase[DataT: BaseModel](BaseModel):
|
||||
page: int = 1
|
||||
per_page: int = 10
|
||||
total: int = 0
|
||||
|
||||
@@ -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:
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from pathlib import Path
|
||||
from typing import Annotated, Any, Generic, TypeVar
|
||||
from typing import Annotated, Any
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import UUID4, BaseModel, ConfigDict, Field, StringConstraints, field_validator
|
||||
@@ -20,7 +20,6 @@ from mealie.schema.response.pagination import PaginationBase
|
||||
from ...db.models.group import Group
|
||||
from ..recipe import CategoryBase
|
||||
|
||||
DataT = TypeVar("DataT", bound=BaseModel)
|
||||
DEFAULT_INTEGRATION_ID = "generic"
|
||||
settings = get_app_settings()
|
||||
|
||||
@@ -102,7 +101,7 @@ class UserRatingOut(UserRatingCreate):
|
||||
]
|
||||
|
||||
|
||||
class UserRatings(BaseModel, Generic[DataT]):
|
||||
class UserRatings[DataT: BaseModel](BaseModel):
|
||||
ratings: list[DataT]
|
||||
|
||||
|
||||
|
||||
@@ -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]:
|
||||
"""
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user