Made fields logic more clear

This commit is contained in:
Syrus Akbary 2016-08-15 23:19:18 -07:00
parent 030fde2cff
commit fd0b9223cf
5 changed files with 80 additions and 47 deletions

View File

@ -2,8 +2,8 @@ import six
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, merge_fields_in_attrs, from .utils import (get_fields_in_type, get_base_fields,
yank_fields_from_attrs) yank_fields_from_attrs, merge)
class AbstractTypeMeta(type): class AbstractTypeMeta(type):
@ -19,12 +19,13 @@ class AbstractTypeMeta(type):
# raise Exception('You can only extend AbstractTypes after the base definition.') # raise Exception('You can only extend AbstractTypes after the base definition.')
return type.__new__(cls, name, bases, attrs) return type.__new__(cls, name, bases, attrs)
attrs = merge_fields_in_attrs(bases, attrs) base_fields = get_base_fields(AbstractType, bases)
fields = get_fields_in_type(AbstractType, attrs) fields = get_fields_in_type(AbstractType, attrs)
yank_fields_from_attrs(attrs, fields) yank_fields_from_attrs(attrs, fields)
options = Options( options = Options(
fields=fields fields=merge(base_fields, fields)
) )
cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) cls = type.__new__(cls, name, bases, dict(attrs, _meta=options))

View File

@ -4,8 +4,8 @@ from ..utils.is_base_type import is_base_type
from .abstracttype import AbstractTypeMeta from .abstracttype import AbstractTypeMeta
from .options import Options from .options import Options
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
from .utils import (get_fields_in_type, merge_fields_in_attrs, from .utils import (get_fields_in_type, yank_fields_from_attrs,
yank_fields_from_attrs) get_base_fields, merge)
class InputObjectTypeMeta(AbstractTypeMeta): class InputObjectTypeMeta(AbstractTypeMeta):
@ -20,14 +20,19 @@ class InputObjectTypeMeta(AbstractTypeMeta):
attrs.pop('Meta', None), attrs.pop('Meta', None),
name=name, name=name,
description=attrs.get('__doc__'), description=attrs.get('__doc__'),
fields=None, local_fields=None,
) )
attrs = merge_fields_in_attrs(bases, attrs) options.base_fields = get_base_fields(InputObjectType, bases)
if not options.fields:
options.fields = get_fields_in_type(InputObjectType, attrs)
yank_fields_from_attrs(attrs, options.fields)
if not options.local_fields:
options.local_fields = get_fields_in_type(InputObjectType, attrs)
yank_fields_from_attrs(attrs, options.local_fields)
options.fields = merge(
options.base_fields,
options.local_fields
)
return type.__new__(cls, name, bases, dict(attrs, _meta=options)) return type.__new__(cls, name, bases, dict(attrs, _meta=options))
def __str__(cls): # noqa: N802 def __str__(cls): # noqa: N802

View File

@ -3,8 +3,8 @@ import six
from ..utils.is_base_type import is_base_type from ..utils.is_base_type import is_base_type
from .abstracttype import AbstractTypeMeta from .abstracttype import AbstractTypeMeta
from .options import Options from .options import Options
from .utils import (get_fields_in_type, merge_fields_in_attrs, from .utils import (get_fields_in_type, yank_fields_from_attrs,
yank_fields_from_attrs) get_base_fields, merge)
class InterfaceMeta(AbstractTypeMeta): class InterfaceMeta(AbstractTypeMeta):
@ -19,13 +19,19 @@ class InterfaceMeta(AbstractTypeMeta):
attrs.pop('Meta', None), attrs.pop('Meta', None),
name=name, name=name,
description=attrs.get('__doc__'), description=attrs.get('__doc__'),
fields=None, local_fields=None,
) )
attrs = merge_fields_in_attrs(bases, attrs) options.base_fields = get_base_fields(Interface, bases)
if not options.fields:
options.fields = get_fields_in_type(Interface, attrs) if not options.local_fields:
yank_fields_from_attrs(attrs, options.fields) options.local_fields = get_fields_in_type(Interface, attrs)
yank_fields_from_attrs(attrs, options.local_fields)
options.fields = merge(
options.base_fields,
options.local_fields
)
return type.__new__(cls, name, bases, dict(attrs, _meta=options)) return type.__new__(cls, name, bases, dict(attrs, _meta=options))

View File

@ -6,8 +6,8 @@ from ..utils.is_base_type import is_base_type
from .abstracttype import AbstractTypeMeta from .abstracttype import AbstractTypeMeta
from .interface import Interface from .interface import Interface
from .options import Options from .options import Options
from .utils import (get_fields_in_type, merge_fields_in_attrs, from .utils import (get_fields_in_type, yank_fields_from_attrs,
yank_fields_from_attrs) get_base_fields, merge)
class ObjectTypeMeta(AbstractTypeMeta): class ObjectTypeMeta(AbstractTypeMeta):
@ -24,23 +24,29 @@ class ObjectTypeMeta(AbstractTypeMeta):
name=name, name=name,
description=attrs.get('__doc__'), description=attrs.get('__doc__'),
interfaces=(), interfaces=(),
fields=None, local_fields=OrderedDict(),
) )
options.base_fields = get_base_fields(ObjectType, bases)
attrs = merge_fields_in_attrs(bases, attrs) if not options.local_fields:
if not options.fields:
options.local_fields = get_fields_in_type(ObjectType, attrs) options.local_fields = get_fields_in_type(ObjectType, attrs)
yank_fields_from_attrs(attrs, options.local_fields) yank_fields_from_attrs(attrs, options.local_fields)
options.interface_fields = OrderedDict() options.interface_fields = OrderedDict()
for interface in options.interfaces: for interface in options.interfaces:
assert issubclass(interface, Interface), ( assert issubclass(interface, Interface), (
'All interfaces of {} must be a subclass of Interface. Received "{}".' 'All interfaces of {} must be a subclass of Interface. Received "{}".'
).format(name, interface) ).format(name, interface)
options.interface_fields.update(interface._meta.fields) options.interface_fields.update(interface._meta.fields)
options.fields = OrderedDict(options.interface_fields)
options.fields.update(options.local_fields) options.fields = merge(
options.interface_fields,
options.base_fields,
options.local_fields
)
cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) cls = type.__new__(cls, name, bases, dict(attrs, _meta=options))
for interface in options.interfaces: for interface in options.interfaces:
interface.implements(cls) interface.implements(cls)

View File

@ -19,7 +19,20 @@ def merge_fields_in_attrs(bases, attrs):
return attrs return attrs
def unmounted_field_in_type(attname, unmounted_field, type): def merge(*dicts):
merged = OrderedDict()
for _dict in dicts:
merged.update(_dict)
return merged
def get_base_fields(in_type, bases):
fields = OrderedDict()
fields = merge_fields_in_attrs(bases, fields)
return get_fields_in_type(in_type, fields, order=False)
def unmounted_field_in_type(unmounted_field, type):
''' '''
Mount the UnmountedType dinamically as Field or InputField Mount the UnmountedType dinamically as Field or InputField
depending on where mounted in. depending on where mounted in.
@ -42,27 +55,29 @@ def unmounted_field_in_type(attname, unmounted_field, type):
return unmounted_field.InputField() return unmounted_field.InputField()
raise Exception( raise Exception(
'Unmounted field "{}" cannot be mounted in {}.{}.'.format( 'Unmounted field "{}" cannot be mounted in {}.'.format(
unmounted_field, type, attname unmounted_field, type
) )
) )
def get_fields_in_type(in_type, attrs): def get_field(in_type, value):
if isinstance(value, (Field, InputField, Dynamic)):
return value
elif isinstance(value, UnmountedType):
return unmounted_field_in_type(value, in_type)
def get_fields_in_type(in_type, attrs, order=True):
fields_with_names = [] fields_with_names = []
for attname, value in list(attrs.items()): for attname, value in list(attrs.items()):
if isinstance(value, (Field, InputField, Dynamic)): field = get_field(in_type, value)
fields_with_names.append( if not field:
(attname, value) continue
) fields_with_names.append((attname, field))
elif isinstance(value, UnmountedType):
try: if not order:
value = unmounted_field_in_type(attname, value, in_type) return OrderedDict(fields_with_names)
fields_with_names.append(
(attname, value)
)
except Exception as e:
raise Exception('Exception while mounting the field "{}": {}'.format(attname, str(e)))
return OrderedDict(sorted(fields_with_names, key=lambda f: f[1])) return OrderedDict(sorted(fields_with_names, key=lambda f: f[1]))