initial commit

This commit is contained in:
bit 2022-05-29 14:06:43 +02:00
commit 28caa06771
7 changed files with 103 additions and 0 deletions

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# pydantic_uuid_model
Add support for deserialization of pydantic child models by saving class unique ids in the serialized data.

3
pyproject.toml Normal file
View File

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=40.8.0", "wheel"]
build-backend = "setuptools.build_meta"

22
setup.cfg Normal file
View File

@ -0,0 +1,22 @@
[metadata]
name = pydantic_uuid_model
version = attr: pydantic_uuid_model.__version__
description = Add support for deserialization of pydantic child models.
long_description = file: README.md
long_description_content_type = text/markdown
classifiers =
Development Status :: 2 - Pre-Alpha
Intended Audience :: Science/Research
Programming Language :: Python :: 3
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
[options]
install_requires =
pydantic
package_dir=
=src
packages=find:
[options.packages.find]
where=src

View File

@ -0,0 +1,12 @@
__version__ = "1.1.0"
__all__ = [
"UUIDAlreadyExistsException",
"UUIDModelMetaclass",
"UUIDBaseModel",
]
from .error import UUIDAlreadyExistsException
from .meta import UUIDModelMetaclass
from .model import UUIDBaseModel

View File

@ -0,0 +1,16 @@
from typing import Optional
class UUIDAlreadyExistsException(Exception):
uuid: str
name: Optional[str]
def __init__(self, uuid: str, name: Optional[str] = None):
if name is not None:
msg = f"Cannot register class '{name}' with UUID '{uuid}', as another class with this UUID is already registered"
else:
msg = f"Cannot register class with UUID '{uuid}' as another class with this UUID is already registered"
super().__init__(msg)
self.uuid = uuid
self.name = name

View File

@ -0,0 +1,36 @@
from typing import Any, Optional
from pydantic.main import ModelMetaclass
from .error import UUIDAlreadyExistsException
class UUIDModelMetaclass(ModelMetaclass):
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
uuid_name = cls.__sub_classes__[None]
if uuid_name not in kwargs:
return super().__call__(*args, **kwargs)
uuid = kwargs.pop(uuid_name)
if uuid is not None:
cls = cls.__sub_classes__.get(str(uuid), cls)
return cls(*args, **kwargs)
def __new__(mcs, name, bases, namespace, uuid_name: Optional[str] = None, base: bool = False, **kwargs):
return super().__new__(mcs, name, bases, namespace, **kwargs)
def __init__(cls, name, bases, namespace, uuid_name: Optional[str] = None, base: bool = False, **kwargs):
if hasattr(cls, "__sub_classes__") and uuid_name is None and not base:
uuid_name = cls.__sub_classes__[None]
uuid = namespace.get(uuid_name, None)
if uuid is not None:
uuid = str(uuid)
if uuid in cls.__sub_classes__:
raise UUIDAlreadyExistsException(uuid, name)
cls.__sub_classes__[uuid] = cls
else:
uuid_name = uuid_name or "muuid"
d = dict()
d[None] = uuid_name
setattr(cls, "__sub_classes__", d)

View File

@ -0,0 +1,11 @@
from typing import ClassVar, Dict, Optional, Union
from pydantic import BaseModel
from .meta import UUIDModelMetaclass
class UUIDBaseModel(BaseModel, metaclass=UUIDModelMetaclass):
muuid: Optional[str]
__sub_classes__: ClassVar[Dict[Optional[str], Union[str, "UUIDBaseModel"]]]