mirror of
https://github.com/graphql-python/graphene.git
synced 2025-09-21 11:22:33 +03:00
Dual mode enums - legacy and new style
This commit is contained in:
parent
40ba414bd5
commit
9f3d386b89
|
@ -37,8 +37,9 @@ class GrapheneScalarType(GrapheneGraphQLType, GraphQLScalarType):
|
|||
|
||||
class GrapheneEnumType(GrapheneGraphQLType, GraphQLEnumType):
|
||||
def serialize(self, value):
|
||||
if value in self.graphene_type._meta.enum:
|
||||
return value.name
|
||||
if not self.graphene_type._meta.legacy_enum_resolver:
|
||||
if value in self.graphene_type._meta.enum:
|
||||
return value.name
|
||||
return super(GrapheneEnumType, self).serialize(value)
|
||||
|
||||
|
||||
|
|
|
@ -36,7 +36,15 @@ def _filter_magic_members(classdict):
|
|||
|
||||
class EnumMeta(SubclassWithMeta_Meta):
|
||||
def __new__(cls, name, bases, classdict, **options):
|
||||
meta_class = classdict.get("Meta")
|
||||
if meta_class is None or not hasattr(meta_class, "legacy_enum_resolver"):
|
||||
is_legacy = True
|
||||
else:
|
||||
is_legacy = meta_class.legacy_enum_resolver
|
||||
|
||||
enum_members = _filter_magic_members(classdict)
|
||||
if is_legacy:
|
||||
enum_members["__eq__"] = eq_enum
|
||||
enum = PyEnum(name, enum_members)
|
||||
return SubclassWithMeta_Meta.__new__(
|
||||
cls, name, bases, OrderedDict(classdict, __enum__=enum), **options
|
||||
|
@ -57,12 +65,13 @@ class EnumMeta(SubclassWithMeta_Meta):
|
|||
return cls.from_enum(PyEnum(*args, **kwargs), description=description)
|
||||
return super(EnumMeta, cls).__call__(*args, **kwargs)
|
||||
|
||||
def from_enum(cls, enum, description=None, deprecation_reason=None): # noqa: N805
|
||||
def from_enum(cls, enum, description=None, deprecation_reason=None, legacy_enum_resolver=True): # noqa: N805
|
||||
description = description or enum.__doc__
|
||||
meta_dict = {
|
||||
"enum": enum,
|
||||
"description": description,
|
||||
"deprecation_reason": deprecation_reason,
|
||||
"legacy_enum_resolver": legacy_enum_resolver,
|
||||
}
|
||||
meta_class = type("Meta", (object,), meta_dict)
|
||||
return type(meta_class.enum.__name__, (Enum,), {"Meta": meta_class})
|
||||
|
@ -75,6 +84,7 @@ class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)):
|
|||
_meta = EnumOptions(cls)
|
||||
_meta.enum = enum or cls.__enum__
|
||||
_meta.deprecation_reason = options.pop("deprecation_reason", None)
|
||||
_meta.legacy_enum_resolver = options.pop("legacy_enum_resolver", True)
|
||||
for key, value in _meta.enum.__members__.items():
|
||||
setattr(cls, key, value)
|
||||
|
||||
|
|
|
@ -182,6 +182,29 @@ def test_enum_value_as_unmounted_argument():
|
|||
assert isinstance(unmounted_field, Argument)
|
||||
assert unmounted_field.type == RGB
|
||||
|
||||
def test_legacy_enum_can_be_compared():
|
||||
class RGB(Enum):
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
BLUE = 3
|
||||
|
||||
assert RGB.RED == 1
|
||||
assert RGB.GREEN == 2
|
||||
assert RGB.BLUE == 3
|
||||
|
||||
def test_new_enum_only_compare_to_enum_instances():
|
||||
class RGBBase(PyEnum):
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
BLUE = 3
|
||||
RGB = Enum.from_enum(RGBBase, legacy_enum_resolver=False)
|
||||
|
||||
assert RGB.RED == RGBBase.RED
|
||||
assert RGB.GREEN == RGBBase.GREEN
|
||||
assert RGB.BLUE == RGBBase.BLUE
|
||||
assert RGB.RED != 1
|
||||
assert RGB.GREEN != 2
|
||||
assert RGB.BLUE != 3
|
||||
|
||||
def test_enum_can_be_initialzied():
|
||||
class RGB(Enum):
|
||||
|
|
|
@ -46,8 +46,10 @@ def _call_and_get_arg(mocker, resolver_name, query):
|
|||
|
||||
def test_resolve_enum_python(mocker):
|
||||
arg = _call_and_get_arg(mocker, "resolve_python", "{python(v:P2)}")
|
||||
assert arg == PythonBaseEnum.P2
|
||||
assert arg == PythonEnum.P2
|
||||
assert arg is PythonBaseEnum.P2
|
||||
assert arg is not PythonBaseEnum.P2.value
|
||||
assert arg is PythonEnum.P2
|
||||
assert arg is not PythonEnum.P2.value
|
||||
|
||||
|
||||
def test_resolve_enum_default_value_python(mocker):
|
||||
|
|
|
@ -69,7 +69,7 @@ def _call_and_get_arg(mocker, resolver_name, query):
|
|||
|
||||
def test_resolve_simple_enum(mocker):
|
||||
arg = _call_and_get_arg(mocker, "resolve_simple", "{simple(v:S2)}")
|
||||
assert arg == SimpleEnum.S2
|
||||
assert arg == SimpleEnum.S2.value
|
||||
|
||||
|
||||
def test_resolve_enum_python(mocker):
|
||||
|
|
|
@ -13,6 +13,7 @@ from graphql.type import (
|
|||
|
||||
from ..dynamic import Dynamic
|
||||
from ..enum import Enum
|
||||
from enum import Enum as PyEnum
|
||||
from ..field import Field
|
||||
from ..inputfield import InputField
|
||||
from ..inputobjecttype import InputObjectType
|
||||
|
@ -23,7 +24,7 @@ from ..structures import List, NonNull
|
|||
from ..typemap import TypeMap, resolve_type
|
||||
|
||||
|
||||
def test_enum():
|
||||
def test_enum_legacy():
|
||||
class MyEnum(Enum):
|
||||
"""Description"""
|
||||
|
||||
|
@ -49,11 +50,46 @@ def test_enum():
|
|||
assert values == [
|
||||
GraphQLEnumValue(
|
||||
name="foo",
|
||||
value=MyEnum.foo,
|
||||
value=1,
|
||||
description="Description foo=1",
|
||||
deprecation_reason="Is deprecated",
|
||||
),
|
||||
GraphQLEnumValue(name="bar", value=MyEnum.bar, description="Description bar=2"),
|
||||
GraphQLEnumValue(name="bar", value=2, description="Description bar=2"),
|
||||
]
|
||||
|
||||
def test_enum_new():
|
||||
class MyEnumBase(PyEnum):
|
||||
"""Description"""
|
||||
|
||||
foo = 1
|
||||
bar = 2
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return "Description {}={}".format(self.name, self.value)
|
||||
|
||||
@property
|
||||
def deprecation_reason(self):
|
||||
if self == MyEnum.foo:
|
||||
return "Is deprecated"
|
||||
|
||||
MyEnum = Enum.from_enum(MyEnumBase, legacy_enum_resolver=False)
|
||||
|
||||
typemap = TypeMap([MyEnum])
|
||||
assert "MyEnumBase" in typemap
|
||||
graphql_enum = typemap["MyEnumBase"]
|
||||
assert isinstance(graphql_enum, GraphQLEnumType)
|
||||
assert graphql_enum.name == "MyEnumBase"
|
||||
assert graphql_enum.description == "Description"
|
||||
values = graphql_enum.values
|
||||
assert values == [
|
||||
GraphQLEnumValue(
|
||||
name="foo",
|
||||
value=MyEnumBase.foo,
|
||||
description="Description foo=1",
|
||||
deprecation_reason="Is deprecated",
|
||||
),
|
||||
GraphQLEnumValue(name="bar", value=MyEnumBase.bar, description="Description bar=2"),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -149,9 +149,14 @@ class TypeMap(GraphQLTypeMap):
|
|||
if not deprecation_reason and callable(type._meta.deprecation_reason):
|
||||
deprecation_reason = type._meta.deprecation_reason(value)
|
||||
|
||||
if type._meta.legacy_enum_resolver:
|
||||
gql_value = value.value
|
||||
else:
|
||||
gql_value = value
|
||||
|
||||
values[name] = GraphQLEnumValue(
|
||||
name=name,
|
||||
value=value,
|
||||
value=gql_value,
|
||||
description=description,
|
||||
deprecation_reason=deprecation_reason,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user