From fd0b9223cf69039d9a434eeff9ff17ffb18bf15c Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 15 Aug 2016 23:19:18 -0700 Subject: [PATCH] Made fields logic more clear --- graphene/types/abstracttype.py | 9 +++--- graphene/types/inputobjecttype.py | 19 ++++++++----- graphene/types/interface.py | 20 ++++++++----- graphene/types/objecttype.py | 32 ++++++++++++--------- graphene/types/utils.py | 47 ++++++++++++++++++++----------- 5 files changed, 80 insertions(+), 47 deletions(-) diff --git a/graphene/types/abstracttype.py b/graphene/types/abstracttype.py index 3948215a..94ed303e 100644 --- a/graphene/types/abstracttype.py +++ b/graphene/types/abstracttype.py @@ -2,8 +2,8 @@ import six from ..utils.is_base_type import is_base_type from .options import Options -from .utils import (get_fields_in_type, merge_fields_in_attrs, - yank_fields_from_attrs) +from .utils import (get_fields_in_type, get_base_fields, + yank_fields_from_attrs, merge) class AbstractTypeMeta(type): @@ -19,12 +19,13 @@ class AbstractTypeMeta(type): # raise Exception('You can only extend AbstractTypes after the base definition.') 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) yank_fields_from_attrs(attrs, fields) options = Options( - fields=fields + fields=merge(base_fields, fields) ) cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) diff --git a/graphene/types/inputobjecttype.py b/graphene/types/inputobjecttype.py index 4606cf9f..c850fa3f 100644 --- a/graphene/types/inputobjecttype.py +++ b/graphene/types/inputobjecttype.py @@ -4,8 +4,8 @@ from ..utils.is_base_type import is_base_type from .abstracttype import AbstractTypeMeta from .options import Options from .unmountedtype import UnmountedType -from .utils import (get_fields_in_type, merge_fields_in_attrs, - yank_fields_from_attrs) +from .utils import (get_fields_in_type, yank_fields_from_attrs, + get_base_fields, merge) class InputObjectTypeMeta(AbstractTypeMeta): @@ -20,14 +20,19 @@ class InputObjectTypeMeta(AbstractTypeMeta): attrs.pop('Meta', None), name=name, description=attrs.get('__doc__'), - fields=None, + local_fields=None, ) - attrs = merge_fields_in_attrs(bases, attrs) - if not options.fields: - options.fields = get_fields_in_type(InputObjectType, attrs) - yank_fields_from_attrs(attrs, options.fields) + options.base_fields = get_base_fields(InputObjectType, bases) + 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)) def __str__(cls): # noqa: N802 diff --git a/graphene/types/interface.py b/graphene/types/interface.py index 27e2346c..a4cd9703 100644 --- a/graphene/types/interface.py +++ b/graphene/types/interface.py @@ -3,8 +3,8 @@ import six from ..utils.is_base_type import is_base_type from .abstracttype import AbstractTypeMeta from .options import Options -from .utils import (get_fields_in_type, merge_fields_in_attrs, - yank_fields_from_attrs) +from .utils import (get_fields_in_type, yank_fields_from_attrs, + get_base_fields, merge) class InterfaceMeta(AbstractTypeMeta): @@ -19,13 +19,19 @@ class InterfaceMeta(AbstractTypeMeta): attrs.pop('Meta', None), name=name, description=attrs.get('__doc__'), - fields=None, + local_fields=None, ) - attrs = merge_fields_in_attrs(bases, attrs) - if not options.fields: - options.fields = get_fields_in_type(Interface, attrs) - yank_fields_from_attrs(attrs, options.fields) + options.base_fields = get_base_fields(Interface, bases) + + if not options.local_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)) diff --git a/graphene/types/objecttype.py b/graphene/types/objecttype.py index b2cc5960..d9361204 100644 --- a/graphene/types/objecttype.py +++ b/graphene/types/objecttype.py @@ -6,8 +6,8 @@ from ..utils.is_base_type import is_base_type from .abstracttype import AbstractTypeMeta from .interface import Interface from .options import Options -from .utils import (get_fields_in_type, merge_fields_in_attrs, - yank_fields_from_attrs) +from .utils import (get_fields_in_type, yank_fields_from_attrs, + get_base_fields, merge) class ObjectTypeMeta(AbstractTypeMeta): @@ -24,23 +24,29 @@ class ObjectTypeMeta(AbstractTypeMeta): name=name, description=attrs.get('__doc__'), interfaces=(), - fields=None, + local_fields=OrderedDict(), ) + options.base_fields = get_base_fields(ObjectType, bases) - attrs = merge_fields_in_attrs(bases, attrs) - if not options.fields: + if not options.local_fields: options.local_fields = get_fields_in_type(ObjectType, attrs) yank_fields_from_attrs(attrs, options.local_fields) - options.interface_fields = OrderedDict() - for interface in options.interfaces: - assert issubclass(interface, Interface), ( - 'All interfaces of {} must be a subclass of Interface. Received "{}".' - ).format(name, interface) - options.interface_fields.update(interface._meta.fields) - options.fields = OrderedDict(options.interface_fields) - options.fields.update(options.local_fields) + + options.interface_fields = OrderedDict() + for interface in options.interfaces: + assert issubclass(interface, Interface), ( + 'All interfaces of {} must be a subclass of Interface. Received "{}".' + ).format(name, interface) + options.interface_fields.update(interface._meta.fields) + + options.fields = merge( + options.interface_fields, + options.base_fields, + options.local_fields + ) cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) + for interface in options.interfaces: interface.implements(cls) diff --git a/graphene/types/utils.py b/graphene/types/utils.py index 9716a9e4..9f950678 100644 --- a/graphene/types/utils.py +++ b/graphene/types/utils.py @@ -19,7 +19,20 @@ def merge_fields_in_attrs(bases, 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 depending on where mounted in. @@ -42,27 +55,29 @@ def unmounted_field_in_type(attname, unmounted_field, type): return unmounted_field.InputField() raise Exception( - 'Unmounted field "{}" cannot be mounted in {}.{}.'.format( - unmounted_field, type, attname + 'Unmounted field "{}" cannot be mounted in {}.'.format( + 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 = [] for attname, value in list(attrs.items()): - if isinstance(value, (Field, InputField, Dynamic)): - fields_with_names.append( - (attname, value) - ) - elif isinstance(value, UnmountedType): - try: - value = unmounted_field_in_type(attname, value, in_type) - fields_with_names.append( - (attname, value) - ) - except Exception as e: - raise Exception('Exception while mounting the field "{}": {}'.format(attname, str(e))) + field = get_field(in_type, value) + if not field: + continue + fields_with_names.append((attname, field)) + + if not order: + return OrderedDict(fields_with_names) return OrderedDict(sorted(fields_with_names, key=lambda f: f[1]))