Support from_enum description lambda

This commit is contained in:
Eran Kampf 2017-10-30 10:19:28 -07:00
parent 34d03a7bd2
commit 16c80c173e
3 changed files with 67 additions and 5 deletions

View File

@ -21,6 +21,7 @@ EnumType = type(PyEnum)
class EnumOptions(BaseOptions): class EnumOptions(BaseOptions):
enum = None # type: Enum enum = None # type: Enum
deprecation_reason = None
class EnumMeta(SubclassWithMeta_Meta): class EnumMeta(SubclassWithMeta_Meta):
@ -45,8 +46,9 @@ class EnumMeta(SubclassWithMeta_Meta):
return super(EnumMeta, cls).__call__(*args, **kwargs) return super(EnumMeta, cls).__call__(*args, **kwargs)
# return cls._meta.enum(*args, **kwargs) # return cls._meta.enum(*args, **kwargs)
def from_enum(cls, enum, description=None): # noqa: N805 def from_enum(cls, enum, description=None, deprecation_reason=None): # noqa: N805
meta_class = type('Meta', (object,), {'enum': enum, 'description': description}) description = description or enum.__doc__
meta_class = type('Meta', (object,), {'enum': enum, 'description': description, 'deprecation_reason': deprecation_reason})
return type(meta_class.enum.__name__, (Enum,), {'Meta': meta_class}) return type(meta_class.enum.__name__, (Enum,), {'Meta': meta_class})
@ -56,8 +58,10 @@ class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)):
def __init_subclass_with_meta__(cls, enum=None, **options): def __init_subclass_with_meta__(cls, enum=None, **options):
_meta = EnumOptions(cls) _meta = EnumOptions(cls)
_meta.enum = enum or cls.__enum__ _meta.enum = enum or cls.__enum__
_meta.deprecation_reason = options.pop('deprecation_reason', None)
for key, value in _meta.enum.__members__.items(): for key, value in _meta.enum.__members__.items():
setattr(cls, key, value) setattr(cls, key, value)
super(Enum, cls).__init_subclass_with_meta__(_meta=_meta, **options) super(Enum, cls).__init_subclass_with_meta__(_meta=_meta, **options)
@classmethod @classmethod

View File

@ -1,3 +1,6 @@
import six
from ..schema import Schema, ObjectType
from ..argument import Argument from ..argument import Argument
from ..enum import Enum, PyEnum from ..enum import Enum, PyEnum
from ..field import Field from ..field import Field
@ -66,6 +69,50 @@ def test_enum_from_builtin_enum():
assert RGB.BLUE assert RGB.BLUE
def test_enum_from_builtin_enum_accepts_lambda_description():
def custom_description(value):
if not value:
return "StarWars Episodes"
return 'New Hope Episode' if value == Episode.NEWHOPE else 'Other'
PyEpisode = PyEnum('PyEpisode', 'NEWHOPE,EMPIRE,JEDI')
Episode = Enum.from_enum(PyEpisode, description=custom_description)
class Query(ObjectType):
foo = Episode()
schema = Schema(query=Query)
GraphQLPyEpisode = schema._type_map['PyEpisode'].values
assert schema._type_map['PyEpisode'].description == "StarWars Episodes"
assert GraphQLPyEpisode[0].name == 'NEWHOPE' and GraphQLPyEpisode[0].description == 'New Hope Episode'
assert GraphQLPyEpisode[1].name == 'EMPIRE' and GraphQLPyEpisode[1].description == 'Other'
assert GraphQLPyEpisode[2].name == 'JEDI' and GraphQLPyEpisode[2].description == 'Other'
def test_enum_from_python3_enum_uses_enum_doc():
if not six.PY3:
return
from enum import Enum as PyEnum
class Color(PyEnum):
"""This is the description"""
RED = 1
GREEN = 2
BLUE = 3
RGB = Enum.from_enum(Color)
assert RGB._meta.enum == Color
assert RGB._meta.description == "This is the description"
assert RGB
assert RGB.RED
assert RGB.GREEN
assert RGB.BLUE
def test_enum_value_from_class(): def test_enum_value_from_class():
class RGB(Enum): class RGB(Enum):
RED = 1 RED = 1

View File

@ -127,16 +127,27 @@ class TypeMap(GraphQLTypeMap):
def construct_enum(self, map, type): def construct_enum(self, map, type):
values = OrderedDict() values = OrderedDict()
for name, value in type._meta.enum.__members__.items(): for name, value in type._meta.enum.__members__.items():
description = getattr(value, 'description', None)
deprecation_reason = getattr(value, 'deprecation_reason', None)
if not description and callable(type._meta.description):
description = type._meta.description(value)
if not deprecation_reason and callable(type._meta.deprecation_reason):
deprecation_reason = type._meta.deprecation_reason(value)
values[name] = GraphQLEnumValue( values[name] = GraphQLEnumValue(
name=name, name=name,
value=value.value, value=value.value,
description=getattr(value, 'description', None), description=description,
deprecation_reason=getattr(value, 'deprecation_reason', None)) deprecation_reason=deprecation_reason)
type_description = type._meta.description(None) if callable(type._meta.description) else type._meta.description
return GrapheneEnumType( return GrapheneEnumType(
graphene_type=type, graphene_type=type,
values=values, values=values,
name=type._meta.name, name=type._meta.name,
description=type._meta.description, ) description=type_description, )
def construct_objecttype(self, map, type): def construct_objecttype(self, map, type):
if type._meta.name in map: if type._meta.name in map: