From eb62c876799643197e7cfc4cab69ba41da339298 Mon Sep 17 00:00:00 2001 From: Conrad Date: Fri, 24 Jan 2025 18:58:39 +0100 Subject: [PATCH] feat: added experimental init and annotation mixins --- creyPY/fastapi/models/__init__.py | 1 + creyPY/fastapi/models/base.py | 4 +++- creyPY/fastapi/models/mixins.py | 35 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 creyPY/fastapi/models/mixins.py diff --git a/creyPY/fastapi/models/__init__.py b/creyPY/fastapi/models/__init__.py index 4b40b38..8a9b3ae 100644 --- a/creyPY/fastapi/models/__init__.py +++ b/creyPY/fastapi/models/__init__.py @@ -1 +1,2 @@ from .base import * # noqa +from .mixins import * # noqa diff --git a/creyPY/fastapi/models/base.py b/creyPY/fastapi/models/base.py index 4319a6c..0a5109f 100644 --- a/creyPY/fastapi/models/base.py +++ b/creyPY/fastapi/models/base.py @@ -7,9 +7,11 @@ from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.orm import as_declarative from sqlalchemy.sql import func +from .mixins import AutoAnnotateMixin, AutoInitMixin + @as_declarative() -class Base: +class Base(AutoAnnotateMixin, AutoInitMixin): __abstract__ = True # Primary key as uuid id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) diff --git a/creyPY/fastapi/models/mixins.py b/creyPY/fastapi/models/mixins.py new file mode 100644 index 0000000..04e381a --- /dev/null +++ b/creyPY/fastapi/models/mixins.py @@ -0,0 +1,35 @@ +from sqlalchemy import Column + + +class AutoAnnotateMixin: + @classmethod + def __init_subclass__(cls) -> None: + super().__init_subclass__() + annotations = {} + for key, value in cls.__dict__.items(): + if isinstance(value, Column): + annotations[key] = value.type.python_type + cls.__annotations__ = annotations + + +class AutoInitMixin: + @classmethod + def __init_subclass__(cls) -> None: + super().__init_subclass__() + init_params = [] + for key, value in cls.__dict__.items(): + if isinstance(value, Column): + if not value.nullable and not value.default and not value.server_default: + init_params.append((key, value.type.python_type)) + + def __init__(self, **kwargs): + super(cls, self).__init__() + for key, _ in init_params: + if key not in kwargs: + raise TypeError(f"Missing required argument: {key}") + setattr(self, key, kwargs[key]) + for key, value in kwargs.items(): + if key not in init_params and hasattr(self.__class__, key): + setattr(self, key, value) + + cls.__init__ = __init__