mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-08 00:43:12 -05:00
refactor: move dependencies to controllers (#1550)
* Moves dependencies directly to controllers * Reduces use of @cached_property - (I have a suspicion that this is a factor in memory usage) * reduce duplicate ways to access the same property on a controller.
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
from .base_controllers import *
|
||||
from .controller import *
|
||||
from .dependencies import *
|
||||
from .mixins import *
|
||||
|
||||
@@ -1,70 +1,107 @@
|
||||
from abc import ABC
|
||||
from functools import cached_property
|
||||
from logging import Logger
|
||||
|
||||
from fastapi import Depends
|
||||
from pydantic import UUID4
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from mealie.core.config import get_app_dirs, get_app_settings
|
||||
from mealie.core.dependencies.dependencies import get_admin_user, get_current_user
|
||||
from mealie.core.exceptions import mealie_registered_exceptions
|
||||
from mealie.core.root_logger import get_logger
|
||||
from mealie.core.settings.directories import AppDirectories
|
||||
from mealie.core.settings.settings import AppSettings
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.lang import local_provider
|
||||
from mealie.lang.providers import Translator
|
||||
from mealie.repos.all_repositories import AllRepositories
|
||||
from mealie.routes._base.checks import OperationChecks
|
||||
from mealie.routes._base.dependencies import SharedDependencies
|
||||
from mealie.schema.user.user import GroupInDB, PrivateUser
|
||||
|
||||
|
||||
class BasePublicController(ABC):
|
||||
class _BaseController(ABC):
|
||||
session: Session = Depends(generate_session)
|
||||
translator: Translator = Depends(local_provider)
|
||||
|
||||
_repos: AllRepositories | None
|
||||
_logger: Logger | None
|
||||
_settings: AppSettings | None
|
||||
_folders: AppDirectories | None
|
||||
|
||||
@property
|
||||
def t(self):
|
||||
return self.translator.t if self.translator else local_provider().t
|
||||
|
||||
@property
|
||||
def repos(self):
|
||||
if not self._repos:
|
||||
self._repos = AllRepositories(self.session)
|
||||
return self._repos
|
||||
|
||||
@property
|
||||
def logger(self) -> Logger:
|
||||
if not self._logger:
|
||||
self._logger = get_logger()
|
||||
return self._logger
|
||||
|
||||
@property
|
||||
def settings(self) -> AppSettings:
|
||||
if not self._settings:
|
||||
self._settings = get_app_settings()
|
||||
return self._settings
|
||||
|
||||
@property
|
||||
def folders(self) -> AppDirectories:
|
||||
if not self._folders:
|
||||
self._folders = get_app_dirs()
|
||||
return self._folders
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
class BasePublicController(_BaseController):
|
||||
"""
|
||||
This is a public class for all User restricted controllers in the API.
|
||||
It includes the common SharedDependencies and some common methods used
|
||||
by all Admin controllers.
|
||||
"""
|
||||
|
||||
deps: SharedDependencies = Depends(SharedDependencies.public)
|
||||
translator: Translator = Depends(local_provider)
|
||||
|
||||
def __init__(self):
|
||||
self.t = self.translator.t if self.translator else local_provider().t
|
||||
...
|
||||
|
||||
|
||||
class BaseUserController(ABC):
|
||||
class BaseUserController(_BaseController):
|
||||
"""
|
||||
This is a base class for all User restricted controllers in the API.
|
||||
It includes the common SharedDependencies and some common methods used
|
||||
by all Admin controllers.
|
||||
"""
|
||||
|
||||
deps: SharedDependencies = Depends(SharedDependencies.user)
|
||||
user: PrivateUser = Depends(get_current_user)
|
||||
translator: Translator = Depends(local_provider)
|
||||
|
||||
def __init__(self):
|
||||
self.t = self.translator.t if self.translator else local_provider().t
|
||||
# Manual Cache
|
||||
_checks: OperationChecks
|
||||
|
||||
def registered_exceptions(self, ex: type[Exception]) -> str:
|
||||
registered = {
|
||||
**mealie_registered_exceptions(self.deps.t),
|
||||
**mealie_registered_exceptions(self.translator),
|
||||
}
|
||||
return registered.get(ex, "An unexpected error occurred.")
|
||||
|
||||
@cached_property
|
||||
def repos(self):
|
||||
return AllRepositories(self.deps.session)
|
||||
|
||||
@property
|
||||
def group_id(self) -> UUID4:
|
||||
return self.deps.acting_user.group_id
|
||||
|
||||
@property
|
||||
def user(self) -> PrivateUser:
|
||||
return self.deps.acting_user
|
||||
return self.user.group_id
|
||||
|
||||
@property
|
||||
def group(self) -> GroupInDB:
|
||||
return self.deps.repos.groups.get_one(self.group_id)
|
||||
return self.repos.groups.get_one(self.group_id)
|
||||
|
||||
@cached_property
|
||||
@property
|
||||
def checks(self) -> OperationChecks:
|
||||
return OperationChecks(self.deps.acting_user)
|
||||
if not self._checks:
|
||||
self._checks = OperationChecks(self.user)
|
||||
return self._checks
|
||||
|
||||
|
||||
class BaseAdminController(BaseUserController):
|
||||
@@ -74,8 +111,4 @@ class BaseAdminController(BaseUserController):
|
||||
by all Admin controllers.
|
||||
"""
|
||||
|
||||
deps: SharedDependencies = Depends(SharedDependencies.admin)
|
||||
translator: Translator = Depends(local_provider)
|
||||
|
||||
def __init__(self):
|
||||
self.t = self.translator.t if self.translator else local_provider().t
|
||||
user: PrivateUser = Depends(get_admin_user)
|
||||
|
||||
@@ -51,6 +51,7 @@ def _init_cbv(cls: type[Any], instance: Any = None) -> None:
|
||||
Idempotently modifies the provided `cls`, performing the following modifications:
|
||||
* The `__init__` function is updated to set any class-annotated dependencies as instance attributes
|
||||
* The `__signature__` attribute is updated to indicate to FastAPI what arguments should be passed to the initializer
|
||||
* Variables starting with `_` are NOT included in the `__signature__` and will be set to None.
|
||||
"""
|
||||
if getattr(cls, CBV_CLASS_KEY, False): # pragma: no cover
|
||||
return # Already initialized
|
||||
@@ -61,10 +62,17 @@ def _init_cbv(cls: type[Any], instance: Any = None) -> None:
|
||||
x for x in old_parameters if x.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)
|
||||
]
|
||||
|
||||
private_attributes = []
|
||||
|
||||
dependency_names: list[str] = []
|
||||
for name, hint in get_type_hints(cls).items():
|
||||
if is_classvar(hint):
|
||||
continue
|
||||
|
||||
if name.startswith("_"):
|
||||
private_attributes.append(name)
|
||||
continue
|
||||
|
||||
parameter_kwargs = {"default": getattr(cls, name, Ellipsis)}
|
||||
dependency_names.append(name)
|
||||
new_parameters.append(
|
||||
@@ -88,6 +96,9 @@ def _init_cbv(cls: type[Any], instance: Any = None) -> None:
|
||||
setattr(cls, "__init__", new_init)
|
||||
setattr(cls, CBV_CLASS_KEY, True)
|
||||
|
||||
for name in private_attributes:
|
||||
setattr(cls, name, None)
|
||||
|
||||
|
||||
def _register_endpoints(router: APIRouter, cls: type[Any], *urls: str) -> None:
|
||||
cbv_router = APIRouter()
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
from functools import cached_property
|
||||
from logging import Logger
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from mealie.core.config import get_app_dirs, get_app_settings
|
||||
from mealie.core.dependencies.dependencies import get_admin_user, get_current_user
|
||||
from mealie.core.root_logger import get_logger
|
||||
from mealie.core.settings.directories import AppDirectories
|
||||
from mealie.core.settings.settings import AppSettings
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.lang import Translator, local_provider
|
||||
from mealie.repos import AllRepositories
|
||||
from mealie.schema.user.user import PrivateUser
|
||||
|
||||
|
||||
class SharedDependencies:
|
||||
session: Session
|
||||
t: Translator
|
||||
acting_user: PrivateUser | None
|
||||
|
||||
def __init__(self, session: Session, acting_user: PrivateUser | None, provider: Translator | None = None) -> None:
|
||||
self.t = provider or local_provider()
|
||||
self.session = session
|
||||
self.acting_user = acting_user
|
||||
|
||||
@classmethod
|
||||
def public(
|
||||
cls,
|
||||
session: Session = Depends(generate_session),
|
||||
translator: Translator = Depends(local_provider),
|
||||
) -> "SharedDependencies":
|
||||
return cls(session, None, translator)
|
||||
|
||||
@classmethod
|
||||
def user(
|
||||
cls,
|
||||
session: Session = Depends(generate_session),
|
||||
user: PrivateUser = Depends(get_current_user),
|
||||
translator: Translator = Depends(local_provider),
|
||||
) -> "SharedDependencies":
|
||||
return cls(session, user, translator)
|
||||
|
||||
@classmethod
|
||||
def admin(
|
||||
cls,
|
||||
session: Session = Depends(generate_session),
|
||||
admin: PrivateUser = Depends(get_admin_user),
|
||||
translator: Translator = Depends(local_provider),
|
||||
) -> "SharedDependencies":
|
||||
return cls(session, admin, translator)
|
||||
|
||||
@cached_property
|
||||
def logger(self) -> Logger:
|
||||
return get_logger()
|
||||
|
||||
@cached_property
|
||||
def settings(self) -> AppSettings:
|
||||
return get_app_settings()
|
||||
|
||||
@cached_property
|
||||
def folders(self) -> AppDirectories:
|
||||
return get_app_dirs()
|
||||
|
||||
@cached_property
|
||||
def repos(self) -> AllRepositories:
|
||||
return AllRepositories(self.session)
|
||||
Reference in New Issue
Block a user