diff --git a/graphene/core/classtypes/base.py b/graphene/core/classtypes/base.py index 5e338ebe..c6d4dc58 100644 --- a/graphene/core/classtypes/base.py +++ b/graphene/core/classtypes/base.py @@ -1,6 +1,7 @@ from collections import OrderedDict import inspect import six +import copy from ..exceptions import SkipField from .options import Options @@ -81,6 +82,38 @@ class FieldsOptions(Options): class FieldsClassTypeMeta(ClassTypeMeta): options_class = FieldsOptions + def extend_fields(cls, bases): + new_fields = cls._meta.local_fields + field_names = {f.name: f for f in new_fields} + + for base in bases: + if not issubclass(base, FieldsClassType): + continue + + parent_fields = base._meta.local_fields + for field in parent_fields: + if field.name in field_names and field.type.__class__ != field_names[ + field.name].type.__class__: + raise Exception( + 'Local field %r in class %r (%r) clashes ' + 'with field with similar name from ' + 'Interface %s (%r)' % ( + field.name, + cls.__name__, + field.__class__, + base.__name__, + field_names[field.name].__class__) + ) + new_field = copy.copy(field) + cls.add_to_class(field.attname, new_field) + + + def construct(cls, bases, attrs): + cls = super(FieldsClassTypeMeta, cls).construct(bases, attrs) + if not cls._meta.abstract: + cls.extend_fields(bases) + return cls + class FieldsClassType(six.with_metaclass(FieldsClassTypeMeta, ClassType)): class Meta: @@ -96,26 +129,3 @@ class FieldsClassType(six.with_metaclass(FieldsClassTypeMeta, ClassType)): continue return OrderedDict(fields) - -# class NamedClassType(ClassType): -# pass - - -# class UnionType(NamedClassType): -# class Meta: -# abstract = True - - -# class ObjectType(NamedClassType): -# class Meta: -# abstract = True - - -# class InputObjectType(NamedClassType): -# class Meta: -# abstract = True - - -# class Mutation(ObjectType): -# class Meta: -# abstract = True diff --git a/graphene/core/classtypes/objecttype.py b/graphene/core/classtypes/objecttype.py index 93d2286e..13e93cb3 100644 --- a/graphene/core/classtypes/objecttype.py +++ b/graphene/core/classtypes/objecttype.py @@ -89,7 +89,7 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta, FieldsClassType)): return GraphQLObjectType( cls._meta.type_name, description=cls._meta.description, - interfaces=[schema.T(i) for i in cls._meta.interfaces], + interfaces=map(schema.T, cls._meta.interfaces), fields=partial(cls.fields_internal_types, schema), is_type_of=getattr(cls, 'is_type_of', None) ) diff --git a/graphene/core/classtypes/tests/test_base.py b/graphene/core/classtypes/tests/test_base.py index 2564a606..546cd943 100644 --- a/graphene/core/classtypes/tests/test_base.py +++ b/graphene/core/classtypes/tests/test_base.py @@ -25,6 +25,7 @@ def test_classtype_definition_list(): '''Character description''' pass assert isinstance(Character.List, List) + assert Character.List.of_type == Character def test_classtype_definition_nonnull(): @@ -32,6 +33,7 @@ def test_classtype_definition_nonnull(): '''Character description''' pass assert isinstance(Character.NonNull, NonNull) + assert Character.NonNull.of_type == Character def test_fieldsclasstype(): @@ -52,3 +54,16 @@ def test_fieldsclasstype_fieldtype(): schema = Schema(query=Character) assert Character.fields_internal_types(schema)['fieldName'] == schema.T(f) assert Character._meta.fields_map['field_name'] == f + + +def test_fieldsclasstype_inheritfields(): + name_field = Field(String()) + last_name_field = Field(String()) + + class Fields1(FieldsClassType): + name = name_field + + class Fields2(Fields1): + last_name = last_name_field + + assert list(Fields2._meta.fields_map.keys()) == ['name', 'last_name'] diff --git a/graphene/core/classtypes/tests/test_interface.py b/graphene/core/classtypes/tests/test_interface.py index 43e9e503..3a07f172 100644 --- a/graphene/core/classtypes/tests/test_interface.py +++ b/graphene/core/classtypes/tests/test_interface.py @@ -71,10 +71,10 @@ def test_interface_inheritance(): def test_interface_inheritance_non_objects(): - class ComonClass(object): + class CommonClass(object): common_attr = True - class Character(ComonClass, Interface): + class Character(CommonClass, Interface): pass class ShouldBeObjectType(Character):