diff --git a/graphene/types/base.py b/graphene/types/base.py index ad8869b9..d9c3bdd4 100644 --- a/graphene/types/base.py +++ b/graphene/types/base.py @@ -26,6 +26,10 @@ class BaseOptions(object): class BaseType(SubclassWithMeta): + @classmethod + def create_type(cls, class_name, **options): + return type(class_name, (cls, ), {'Meta': options}) + @classmethod def __init_subclass_with_meta__(cls, name=None, description=None, _meta=None): assert "_meta" not in cls.__dict__, "Can't assign directly meta" diff --git a/graphene/types/tests/test_base.py b/graphene/types/tests/test_base.py new file mode 100644 index 00000000..2ea3dcce --- /dev/null +++ b/graphene/types/tests/test_base.py @@ -0,0 +1,63 @@ +import pytest + +from ..base import BaseType, BaseOptions + + +class CustomOptions(BaseOptions): + pass + + +class CustomType(BaseType): + @classmethod + def __init_subclass_with_meta__(cls, **options): + _meta = CustomOptions(cls) + super(CustomType, cls).__init_subclass_with_meta__(_meta=_meta, **options) + + +def test_basetype(): + class MyBaseType(CustomType): + pass + + assert isinstance(MyBaseType._meta, CustomOptions) + assert MyBaseType._meta.name == "MyBaseType" + assert MyBaseType._meta.description is None + + +def test_basetype_nones(): + class MyBaseType(CustomType): + '''Documentation''' + class Meta: + name = None + description = None + + assert isinstance(MyBaseType._meta, CustomOptions) + assert MyBaseType._meta.name == "MyBaseType" + assert MyBaseType._meta.description == "Documentation" + + +def test_basetype_custom(): + class MyBaseType(CustomType): + '''Documentation''' + class Meta: + name = 'Base' + description = 'Desc' + + assert isinstance(MyBaseType._meta, CustomOptions) + assert MyBaseType._meta.name == "Base" + assert MyBaseType._meta.description == "Desc" + + +def test_basetype_create(): + MyBaseType = CustomType.create_type('MyBaseType') + + assert isinstance(MyBaseType._meta, CustomOptions) + assert MyBaseType._meta.name == "MyBaseType" + assert MyBaseType._meta.description is None + + +def test_basetype_create_extra(): + MyBaseType = CustomType.create_type('MyBaseType', name='Base', description='Desc') + + assert isinstance(MyBaseType._meta, CustomOptions) + assert MyBaseType._meta.name == "Base" + assert MyBaseType._meta.description == "Desc" diff --git a/graphene/utils/subclass_with_meta.py b/graphene/utils/subclass_with_meta.py index d6d33cb6..f1ebfce9 100644 --- a/graphene/utils/subclass_with_meta.py +++ b/graphene/utils/subclass_with_meta.py @@ -1,4 +1,5 @@ import six +from inspect import isclass from ..pyutils.init_subclass import InitSubclassMeta from .props import props @@ -18,7 +19,12 @@ class SubclassWithMeta(six.with_metaclass(SubclassWithMeta_Meta)): _Meta = getattr(cls, "Meta", None) _meta_props = {} if _Meta: - _meta_props = props(_Meta) + if isinstance(_Meta, dict): + _meta_props = _Meta + elif isclass(_Meta): + _meta_props = props(_Meta) + else: + raise Exception("Meta have to be either a class or a dict. Received {}".format(_Meta)) delattr(cls, "Meta") options = dict(meta_options, **_meta_props) super_class = super(cls, cls)