From 5f573c87e4214d27634ecf4782356bbe3a583837 Mon Sep 17 00:00:00 2001 From: Markus Padourek Date: Tue, 16 Aug 2016 19:10:46 +0100 Subject: [PATCH] WIP: Also inherit interfaces from abstract type. --- graphene/types/abstracttype.py | 48 +++++++++++++++++++++---- graphene/types/objecttype.py | 18 ++++++++++ graphene/types/tests/test_objecttype.py | 28 +++++++++++++++ graphene/types/utils.py | 4 +++ 4 files changed, 91 insertions(+), 7 deletions(-) diff --git a/graphene/types/abstracttype.py b/graphene/types/abstracttype.py index 94ed303e..b15e683d 100644 --- a/graphene/types/abstracttype.py +++ b/graphene/types/abstracttype.py @@ -1,3 +1,4 @@ +from collections import OrderedDict import six from ..utils.is_base_type import is_base_type @@ -9,26 +10,59 @@ from .utils import (get_fields_in_type, get_base_fields, class AbstractTypeMeta(type): def __new__(cls, name, bases, attrs): + from .interface import Interface # Also ensure initialization is only performed for subclasses of # AbstractType if not is_base_type(bases, AbstractTypeMeta): return type.__new__(cls, name, bases, attrs) + print('-----> in AbstractTypeMeta') + print(attrs.get('_meta')) + print(attrs.get('Meta')) + print(dir(attrs.get('Meta'))) + for base in bases: if not issubclass(base, AbstractType) and issubclass(type(base), AbstractTypeMeta): # raise Exception('You can only extend AbstractTypes after the base definition.') return type.__new__(cls, name, 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=merge(base_fields, fields) + _meta = attrs.pop('_meta', None) + options = _meta or Options( + attrs.pop('Meta', None), + interfaces=(), + fields=() ) + print('options:') + print(options) + + options.base_fields = get_base_fields(AbstractType, bases) + + options.local_fields = get_fields_in_type(AbstractType, 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 = merge( + options.interface_fields, + options.base_fields, + options.local_fields + ) + + # options = Options( + # fields=merge(base_fields, fields), + # interfaces=(), + # ) cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) + for interface in options.interfaces: + interface.implements(cls) + return cls diff --git a/graphene/types/objecttype.py b/graphene/types/objecttype.py index d9361204..1024acca 100644 --- a/graphene/types/objecttype.py +++ b/graphene/types/objecttype.py @@ -19,6 +19,10 @@ class ObjectTypeMeta(AbstractTypeMeta): return type.__new__(cls, name, bases, attrs) _meta = attrs.pop('_meta', None) + base_interfaces = () + for base in bases: + if hasattr(base, '_meta') and hasattr(base._meta, 'interfaces'): + base_interfaces = base_interfaces + base._meta.interfaces options = _meta or Options( attrs.pop('Meta', None), name=name, @@ -26,13 +30,27 @@ class ObjectTypeMeta(AbstractTypeMeta): interfaces=(), local_fields=OrderedDict(), ) + options.interfaces = options.interfaces + base_interfaces + print('OPTIONS', options) options.base_fields = get_base_fields(ObjectType, bases) + print('-----> base fields: ', options.base_fields) + # from ..types import AbstractType + # inherited_bases = (AbstractType, Interface) + # for base in bases: + # if base in inherited_bases or not issubclass(base, inherited_bases): + # continue + # print(base) + # print(base()) + # print(dir(base())) + # print(dir(base()._meta)) 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() + print('interfaces') + print(options.interfaces) for interface in options.interfaces: assert issubclass(interface, Interface), ( 'All interfaces of {} must be a subclass of Interface. Received "{}".' diff --git a/graphene/types/tests/test_objecttype.py b/graphene/types/tests/test_objecttype.py index d0ecbace..e008a997 100644 --- a/graphene/types/tests/test_objecttype.py +++ b/graphene/types/tests/test_objecttype.py @@ -2,6 +2,7 @@ import pytest from ..abstracttype import AbstractType from ..field import Field +from ..scalars import String from ..interface import Interface from ..objecttype import ObjectType from ..unmountedtype import UnmountedType @@ -57,6 +58,19 @@ def test_generate_objecttype_with_meta(): assert MyObjectType._meta.interfaces == (MyType, ) +def test_generate_objecttype_with_interface(): + class MyObjectType(ObjectType): + + class Meta: + interfaces = (MyInterface, ) + + great_field = String() + + assert MyObjectType._meta.interfaces == (MyInterface, ) + assert list(MyObjectType._meta.fields.keys()) == ['ifield', 'great_field'] + assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field] + + def test_generate_objecttype_with_fields(): class MyObjectType(ObjectType): field = Field(MyType) @@ -96,6 +110,20 @@ def test_generate_objecttype_inherit_abstracttype_reversed(): assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field] +def test_generate_objecttype_inherit_abstracttype_with_interface(): + class MyAbstractType(AbstractType): + class Meta: + interfaces = (MyInterface, ) + field1 = MyScalar() + + class MyObjectType(ObjectType, MyAbstractType): + field2 = MyScalar() + + assert MyObjectType._meta.interfaces == (MyInterface, ) + assert list(MyObjectType._meta.fields.keys()) == ['ifield', 'field1', 'field2'] + assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field, Field] + + def test_generate_objecttype_unmountedtype(): class MyObjectType(ObjectType): field = MyScalar() diff --git a/graphene/types/utils.py b/graphene/types/utils.py index 9f950678..410a8724 100644 --- a/graphene/types/utils.py +++ b/graphene/types/utils.py @@ -12,6 +12,10 @@ def merge_fields_in_attrs(bases, attrs): for base in bases: if base in inherited_bases or not issubclass(base, inherited_bases): continue + print('!!!!!!!!!!!') + print(base._meta) + print(dir(base._meta)) + print(base._meta.fields.items()) for name, field in base._meta.fields.items(): if name in attrs: continue