Allow fast ObjectType creation based on dataclasses

This commit is contained in:
Syrus 2020-03-14 13:40:30 -07:00
parent 1cf303a27b
commit 9b28a7f182
4 changed files with 1212 additions and 6 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
from typing import Type from typing import Type
from ..utils.subclass_with_meta import SubclassWithMeta from ..utils.subclass_with_meta import SubclassWithMeta, SubclassWithMeta_Meta
from ..utils.trim_docstring import trim_docstring from ..utils.trim_docstring import trim_docstring
@ -26,6 +26,8 @@ class BaseOptions:
return "<{} name={}>".format(self.__class__.__name__, repr(self.name)) return "<{} name={}>".format(self.__class__.__name__, repr(self.name))
BaseTypeMeta = SubclassWithMeta_Meta
class BaseType(SubclassWithMeta): class BaseType(SubclassWithMeta):
@classmethod @classmethod
def create_type(cls, class_name, **options): def create_type(cls, class_name, **options):

View File

@ -1,8 +1,10 @@
from .base import BaseOptions, BaseType from .base import BaseOptions, BaseType, BaseTypeMeta
from .field import Field from .field import Field
from .interface import Interface from .interface import Interface
from .utils import yank_fields_from_attrs from .utils import yank_fields_from_attrs
from ..pyutils.dataclasses import make_dataclass, field
# For static type checking with Mypy # For static type checking with Mypy
MYPY = False MYPY = False
if MYPY: if MYPY:
@ -14,7 +16,24 @@ class ObjectTypeOptions(BaseOptions):
interfaces = () # type: Iterable[Type[Interface]] interfaces = () # type: Iterable[Type[Interface]]
class ObjectType(BaseType): class ObjectTypeMeta(BaseTypeMeta):
def __new__(cls, name, bases, namespace):
# We create this type, to then overload it with the dataclass attrs
class InterObjectType:
pass
base_cls = super().__new__(cls, name, (InterObjectType, ) + bases, namespace)
if base_cls._meta:
fields = [
(key, 'typing.Any', field(default=field_value.default_value if isinstance(field_value, Field) else None))
for key, field_value in base_cls._meta.fields.items()
]
dataclass = make_dataclass(name, fields, bases=())
InterObjectType.__init__ = dataclass.__init__
return base_cls
class ObjectType(BaseType, metaclass=ObjectTypeMeta):
""" """
Object Type Definition Object Type Definition

View File

@ -83,6 +83,10 @@ def test_generate_objecttype_with_fields():
def test_generate_objecttype_with_private_attributes(): def test_generate_objecttype_with_private_attributes():
class MyObjectType(ObjectType): class MyObjectType(ObjectType):
def __init__(self, _private_state=None, **kwargs):
self._private_state = _private_state
super().__init__(**kwargs)
_private_state = None _private_state = None
assert "_private_state" not in MyObjectType._meta.fields assert "_private_state" not in MyObjectType._meta.fields
@ -173,17 +177,17 @@ def test_objecttype_as_container_all_kwargs():
def test_objecttype_as_container_extra_args(): def test_objecttype_as_container_extra_args():
with raises(IndexError) as excinfo: with raises(TypeError) as excinfo:
Container("1", "2", "3") Container("1", "2", "3")
assert "Number of args exceeds number of fields" == str(excinfo.value) assert "__init__() takes from 1 to 3 positional arguments but 4 were given" == str(excinfo.value)
def test_objecttype_as_container_invalid_kwargs(): def test_objecttype_as_container_invalid_kwargs():
with raises(TypeError) as excinfo: with raises(TypeError) as excinfo:
Container(unexisting_field="3") Container(unexisting_field="3")
assert "'unexisting_field' is an invalid keyword argument for Container" == str( assert "__init__() got an unexpected keyword argument 'unexisting_field'" == str(
excinfo.value excinfo.value
) )