mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-02 20:54:16 +03:00
Added abstract types simplification
This commit is contained in:
parent
550ad386f0
commit
cd0be62993
|
@ -1,33 +1,30 @@
|
||||||
import six
|
import six
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from ..utils.is_base_type import is_base_type
|
from ..utils.is_base_type import is_base_type
|
||||||
from .options import Options
|
from .options import Options
|
||||||
|
|
||||||
from .utils import get_fields_in_type, attrs_without_fields
|
from .utils import get_fields_in_type, yank_fields_from_attrs, merge_fields_in_attrs
|
||||||
|
|
||||||
|
|
||||||
def merge_fields_in_attrs(bases, attrs):
|
|
||||||
for base in bases:
|
|
||||||
if not issubclass(base, AbstractType):
|
|
||||||
continue
|
|
||||||
for name, field in base._meta.fields.items():
|
|
||||||
if name in attrs:
|
|
||||||
continue
|
|
||||||
attrs[name] = field
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractTypeMeta(type):
|
class AbstractTypeMeta(type):
|
||||||
|
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs):
|
||||||
options = attrs.get('_meta', Options())
|
# Also ensure initialization is only performed for subclasses of
|
||||||
|
# ObjectType
|
||||||
|
if not is_base_type(bases, AbstractTypeMeta):
|
||||||
|
return type.__new__(cls, name, bases, attrs)
|
||||||
|
|
||||||
|
for base in bases:
|
||||||
|
if not issubclass(base, AbstractType) and issubclass(type(base), AbstractTypeMeta):
|
||||||
|
# raise Exception('You can only')
|
||||||
|
return type.__new__(cls, name, bases, attrs)
|
||||||
|
|
||||||
attrs = merge_fields_in_attrs(bases, attrs)
|
attrs = merge_fields_in_attrs(bases, attrs)
|
||||||
fields = get_fields_in_type(cls, attrs)
|
fields = get_fields_in_type(cls, attrs)
|
||||||
options.fields = OrderedDict(sorted(fields, key=lambda f: f[1]))
|
yank_fields_from_attrs(attrs, fields)
|
||||||
|
|
||||||
attrs = attrs_without_fields(attrs, fields)
|
options = attrs.get('_meta', Options())
|
||||||
|
options.fields = fields
|
||||||
cls = type.__new__(cls, name, bases, dict(attrs, _meta=options))
|
cls = type.__new__(cls, name, bases, dict(attrs, _meta=options))
|
||||||
|
|
||||||
return cls
|
return cls
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import six
|
import six
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from ..utils.is_base_type import is_base_type
|
from ..utils.is_base_type import is_base_type
|
||||||
from .options import Options
|
from .options import Options
|
||||||
|
|
||||||
from .utils import get_fields_in_type, attrs_without_fields
|
from .abstracttype import AbstractTypeMeta
|
||||||
|
from .utils import get_fields_in_type, yank_fields_from_attrs, merge_fields_in_attrs
|
||||||
|
|
||||||
|
|
||||||
class InterfaceMeta(type):
|
class InterfaceMeta(AbstractTypeMeta):
|
||||||
|
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs):
|
||||||
# Also ensure initialization is only performed for subclasses of
|
# Also ensure initialization is only performed for subclasses of
|
||||||
# ObjectType
|
# Interface
|
||||||
if not is_base_type(bases, InterfaceMeta):
|
if not is_base_type(bases, InterfaceMeta):
|
||||||
return type.__new__(cls, name, bases, attrs)
|
return type.__new__(cls, name, bases, attrs)
|
||||||
|
|
||||||
|
@ -19,15 +19,14 @@ class InterfaceMeta(type):
|
||||||
attrs.pop('Meta', None),
|
attrs.pop('Meta', None),
|
||||||
name=name,
|
name=name,
|
||||||
description=attrs.get('__doc__'),
|
description=attrs.get('__doc__'),
|
||||||
|
interfaces=(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fields = get_fields_in_type(Interface, attrs)
|
attrs = merge_fields_in_attrs(bases, attrs)
|
||||||
options.fields = OrderedDict(sorted(fields, key=lambda f: f[1]))
|
options.fields = get_fields_in_type(cls, attrs)
|
||||||
|
yank_fields_from_attrs(attrs, options.fields)
|
||||||
|
|
||||||
attrs = attrs_without_fields(attrs, fields)
|
return type.__new__(cls, name, bases, dict(attrs, _meta=options))
|
||||||
cls = super(InterfaceMeta, cls).__new__(cls, name, bases, dict(attrs, _meta=options))
|
|
||||||
|
|
||||||
return cls
|
|
||||||
|
|
||||||
|
|
||||||
class Interface(six.with_metaclass(InterfaceMeta)):
|
class Interface(six.with_metaclass(InterfaceMeta)):
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import six
|
import six
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from ..utils.is_base_type import is_base_type
|
from ..utils.is_base_type import is_base_type
|
||||||
from .options import Options
|
from .options import Options
|
||||||
|
|
||||||
from .utils import get_fields_in_type, attrs_without_fields
|
from .abstracttype import AbstractTypeMeta
|
||||||
|
from .utils import get_fields_in_type, yank_fields_from_attrs, merge_fields_in_attrs
|
||||||
|
|
||||||
|
|
||||||
class ObjectTypeMeta(type):
|
class ObjectTypeMeta(AbstractTypeMeta):
|
||||||
|
|
||||||
def __new__(cls, name, bases, attrs):
|
def __new__(cls, name, bases, attrs):
|
||||||
# Also ensure initialization is only performed for subclasses of
|
# Also ensure initialization is only performed for subclasses of
|
||||||
|
@ -22,13 +22,11 @@ class ObjectTypeMeta(type):
|
||||||
interfaces=(),
|
interfaces=(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fields = get_fields_in_type(ObjectType, attrs)
|
attrs = merge_fields_in_attrs(bases, attrs)
|
||||||
options.fields = OrderedDict(sorted(fields, key=lambda f: f[1]))
|
options.fields = get_fields_in_type(cls, attrs)
|
||||||
|
yank_fields_from_attrs(attrs, options.fields)
|
||||||
|
|
||||||
attrs = attrs_without_fields(attrs, fields)
|
return type.__new__(cls, name, bases, dict(attrs, _meta=options))
|
||||||
cls = super(ObjectTypeMeta, cls).__new__(cls, name, bases, dict(attrs, _meta=options))
|
|
||||||
|
|
||||||
return cls
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectType(six.with_metaclass(ObjectTypeMeta)):
|
class ObjectType(six.with_metaclass(ObjectTypeMeta)):
|
||||||
|
|
|
@ -38,7 +38,8 @@ def test_generate_abstracttype_inheritance():
|
||||||
field2 = UnmountedType(MyType)
|
field2 = UnmountedType(MyType)
|
||||||
|
|
||||||
assert MyAbstractType2._meta.fields.keys() == ['field1', 'field2']
|
assert MyAbstractType2._meta.fields.keys() == ['field1', 'field2']
|
||||||
|
assert not hasattr(MyAbstractType1, 'field1')
|
||||||
|
assert not hasattr(MyAbstractType2, 'field2')
|
||||||
|
|
||||||
# def test_ordered_fields_in_objecttype():
|
# def test_ordered_fields_in_objecttype():
|
||||||
# class MyObjectType(ObjectType):
|
# class MyObjectType(ObjectType):
|
||||||
|
|
|
@ -3,6 +3,7 @@ import pytest
|
||||||
from ..field import Field
|
from ..field import Field
|
||||||
from ..objecttype import ObjectType
|
from ..objecttype import ObjectType
|
||||||
from ..unmountedtype import UnmountedType
|
from ..unmountedtype import UnmountedType
|
||||||
|
from ..abstracttype import AbstractType
|
||||||
|
|
||||||
|
|
||||||
class MyType(object):
|
class MyType(object):
|
||||||
|
@ -59,6 +60,27 @@ def test_ordered_fields_in_objecttype():
|
||||||
assert list(MyObjectType._meta.fields.keys()) == ['b', 'a', 'field', 'asa']
|
assert list(MyObjectType._meta.fields.keys()) == ['b', 'a', 'field', 'asa']
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_objecttype_inherit_abstracttype():
|
||||||
|
class MyAbstractType(AbstractType):
|
||||||
|
field1 = MyScalar(MyType)
|
||||||
|
|
||||||
|
class MyObjectType(ObjectType, MyAbstractType):
|
||||||
|
field2 = MyScalar(MyType)
|
||||||
|
|
||||||
|
assert MyObjectType._meta.fields.keys() == ['field1', 'field2']
|
||||||
|
assert [type(x) for x in MyObjectType._meta.fields.values()] == [Field, Field]
|
||||||
|
|
||||||
|
def test_generate_objecttype_inherit_abstracttype_reversed():
|
||||||
|
class MyAbstractType(AbstractType):
|
||||||
|
field1 = MyScalar(MyType)
|
||||||
|
|
||||||
|
class MyObjectType(MyAbstractType, ObjectType):
|
||||||
|
field2 = MyScalar(MyType)
|
||||||
|
|
||||||
|
assert MyObjectType._meta.fields.keys() == ['field1', 'field2']
|
||||||
|
assert [type(x) for x in MyObjectType._meta.fields.values()] == [Field, Field]
|
||||||
|
|
||||||
|
|
||||||
def test_generate_objecttype_unmountedtype():
|
def test_generate_objecttype_unmountedtype():
|
||||||
class MyObjectType(ObjectType):
|
class MyObjectType(ObjectType):
|
||||||
field = MyScalar(MyType)
|
field = MyScalar(MyType)
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from .unmountedtype import UnmountedType
|
from .unmountedtype import UnmountedType
|
||||||
from .field import Field
|
from .field import Field
|
||||||
|
|
||||||
|
|
||||||
|
def merge_fields_in_attrs(bases, attrs):
|
||||||
|
from ..new_types.abstracttype import AbstractType
|
||||||
|
for base in bases:
|
||||||
|
if base == AbstractType or not issubclass(base, AbstractType):
|
||||||
|
continue
|
||||||
|
for name, field in base._meta.fields.items():
|
||||||
|
if name in attrs:
|
||||||
|
continue
|
||||||
|
attrs[name] = field
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
def unmounted_field_in_type(attname, unmounted_field, type):
|
def unmounted_field_in_type(attname, unmounted_field, type):
|
||||||
'''
|
'''
|
||||||
Mount the UnmountedType dinamically as Field or InputField
|
Mount the UnmountedType dinamically as Field or InputField
|
||||||
|
@ -12,10 +26,10 @@ def unmounted_field_in_type(attname, unmounted_field, type):
|
||||||
'''
|
'''
|
||||||
# from ..types.inputobjecttype import InputObjectType
|
# from ..types.inputobjecttype import InputObjectType
|
||||||
from ..new_types.objecttype import ObjectTypeMeta
|
from ..new_types.objecttype import ObjectTypeMeta
|
||||||
from ..new_types.interface import Interface
|
from ..new_types.interface import InterfaceMeta
|
||||||
from ..new_types.abstracttype import AbstractTypeMeta
|
from ..new_types.abstracttype import AbstractTypeMeta
|
||||||
|
|
||||||
if issubclass(type, (ObjectTypeMeta, Interface)):
|
if issubclass(type, (ObjectTypeMeta, InterfaceMeta)):
|
||||||
return unmounted_field.as_field()
|
return unmounted_field.as_field()
|
||||||
|
|
||||||
elif issubclass(type, (AbstractTypeMeta)):
|
elif issubclass(type, (AbstractTypeMeta)):
|
||||||
|
@ -31,12 +45,23 @@ def unmounted_field_in_type(attname, unmounted_field, type):
|
||||||
|
|
||||||
|
|
||||||
def get_fields_in_type(in_type, attrs):
|
def get_fields_in_type(in_type, attrs):
|
||||||
|
fields_with_names = []
|
||||||
for attname, value in list(attrs.items()):
|
for attname, value in list(attrs.items()):
|
||||||
if isinstance(value, (Field)): # , InputField
|
if isinstance(value, (Field)): # , InputField
|
||||||
yield attname, value
|
fields_with_names.append(
|
||||||
|
(attname, value)
|
||||||
|
)
|
||||||
elif isinstance(value, UnmountedType):
|
elif isinstance(value, UnmountedType):
|
||||||
yield attname, unmounted_field_in_type(attname, value, in_type)
|
fields_with_names.append(
|
||||||
|
(attname, unmounted_field_in_type(attname, value, in_type))
|
||||||
|
)
|
||||||
|
|
||||||
|
return OrderedDict(sorted(fields_with_names, key=lambda f: f[1]))
|
||||||
|
|
||||||
|
|
||||||
def attrs_without_fields(attrs, fields):
|
def yank_fields_from_attrs(attrs, fields):
|
||||||
return {k: v for k, v in attrs.items() if k not in fields}
|
for name, field in fields.items():
|
||||||
|
# attrs.pop(name, None)
|
||||||
|
del attrs[name]
|
||||||
|
# return attrs
|
||||||
|
# return {k: v for k, v in attrs.items() if k not in fields}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user