diff --git a/graphene/tests/issues/test_425.py b/graphene/tests/issues/test_425.py new file mode 100644 index 00000000..95a1d79d --- /dev/null +++ b/graphene/tests/issues/test_425.py @@ -0,0 +1,53 @@ +# https://github.com/graphql-python/graphene/issues/425 +import six + +from graphene.utils.is_base_type import is_base_type + +from graphene.types.objecttype import ObjectTypeMeta, ObjectType +from graphene.types.options import Options + +class SpecialObjectTypeMeta(ObjectTypeMeta): + + @staticmethod + def __new__(cls, name, bases, attrs): + # Also ensure initialization is only performed for subclasses of + # DjangoObjectType + if not is_base_type(bases, SpecialObjectTypeMeta): + return type.__new__(cls, name, bases, attrs) + + options = Options( + attrs.pop('Meta', None), + other_attr='default', + ) + + return ObjectTypeMeta.__new__(cls, name, bases, dict(attrs, _meta=options)) + + return cls + + +class SpecialObjectType(six.with_metaclass(SpecialObjectTypeMeta, ObjectType)): + pass + + +def test_special_objecttype_could_be_subclassed(): + class MyType(SpecialObjectType): + class Meta: + other_attr = 'yeah!' + + assert MyType._meta.other_attr == 'yeah!' + + +def test_special_objecttype_could_be_subclassed_default(): + class MyType(SpecialObjectType): + pass + + assert MyType._meta.other_attr == 'default' + + +def test_special_objecttype_inherit_meta_options(): + class MyType(SpecialObjectType): + pass + + assert MyType._meta.name == 'MyType' + assert MyType._meta.default_resolver == None + assert MyType._meta.interfaces == () diff --git a/graphene/types/objecttype.py b/graphene/types/objecttype.py index b59256c7..b92af9e5 100644 --- a/graphene/types/objecttype.py +++ b/graphene/types/objecttype.py @@ -19,7 +19,7 @@ class ObjectTypeMeta(AbstractTypeMeta): if not is_base_type(bases, ObjectTypeMeta): return type.__new__(cls, name, bases, attrs) - attrs.pop('_meta', None) + _meta = attrs.pop('_meta', None) options = Options( attrs.pop('Meta', None), name=name, @@ -28,6 +28,7 @@ class ObjectTypeMeta(AbstractTypeMeta): default_resolver=None, local_fields=OrderedDict(), ) + options.extend_with_meta(_meta) options.base_fields = get_base_fields(bases, _as=Field) if not options.local_fields: diff --git a/graphene/types/options.py b/graphene/types/options.py index 0002db68..43f7154b 100644 --- a/graphene/types/options.py +++ b/graphene/types/options.py @@ -30,6 +30,13 @@ class Options(object): ) ) + def extend_with_meta(self, meta): + if not meta: + return + meta_attrs = props(meta) + for attr_name, value in meta_attrs.items(): + setattr(self, attr_name, value) + def __repr__(self): options_props = props(self) props_as_attrs = ' '.join(['{}={}'.format(key, value) for key, value in options_props.items()])