mirror of
https://github.com/graphql-python/graphene.git
synced 2025-09-21 19:32:33 +03:00
Dual mode enums - legacy and new style
This commit is contained in:
parent
40ba414bd5
commit
9f3d386b89
|
@ -37,6 +37,7 @@ class GrapheneScalarType(GrapheneGraphQLType, GraphQLScalarType):
|
||||||
|
|
||||||
class GrapheneEnumType(GrapheneGraphQLType, GraphQLEnumType):
|
class GrapheneEnumType(GrapheneGraphQLType, GraphQLEnumType):
|
||||||
def serialize(self, value):
|
def serialize(self, value):
|
||||||
|
if not self.graphene_type._meta.legacy_enum_resolver:
|
||||||
if value in self.graphene_type._meta.enum:
|
if value in self.graphene_type._meta.enum:
|
||||||
return value.name
|
return value.name
|
||||||
return super(GrapheneEnumType, self).serialize(value)
|
return super(GrapheneEnumType, self).serialize(value)
|
||||||
|
|
|
@ -36,7 +36,15 @@ def _filter_magic_members(classdict):
|
||||||
|
|
||||||
class EnumMeta(SubclassWithMeta_Meta):
|
class EnumMeta(SubclassWithMeta_Meta):
|
||||||
def __new__(cls, name, bases, classdict, **options):
|
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)
|
enum_members = _filter_magic_members(classdict)
|
||||||
|
if is_legacy:
|
||||||
|
enum_members["__eq__"] = eq_enum
|
||||||
enum = PyEnum(name, enum_members)
|
enum = PyEnum(name, enum_members)
|
||||||
return SubclassWithMeta_Meta.__new__(
|
return SubclassWithMeta_Meta.__new__(
|
||||||
cls, name, bases, OrderedDict(classdict, __enum__=enum), **options
|
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 cls.from_enum(PyEnum(*args, **kwargs), description=description)
|
||||||
return super(EnumMeta, cls).__call__(*args, **kwargs)
|
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__
|
description = description or enum.__doc__
|
||||||
meta_dict = {
|
meta_dict = {
|
||||||
"enum": enum,
|
"enum": enum,
|
||||||
"description": description,
|
"description": description,
|
||||||
"deprecation_reason": deprecation_reason,
|
"deprecation_reason": deprecation_reason,
|
||||||
|
"legacy_enum_resolver": legacy_enum_resolver,
|
||||||
}
|
}
|
||||||
meta_class = type("Meta", (object,), meta_dict)
|
meta_class = type("Meta", (object,), meta_dict)
|
||||||
return type(meta_class.enum.__name__, (Enum,), {"Meta": meta_class})
|
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 = EnumOptions(cls)
|
||||||
_meta.enum = enum or cls.__enum__
|
_meta.enum = enum or cls.__enum__
|
||||||
_meta.deprecation_reason = options.pop("deprecation_reason", None)
|
_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():
|
for key, value in _meta.enum.__members__.items():
|
||||||
setattr(cls, key, value)
|
setattr(cls, key, value)
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,29 @@ def test_enum_value_as_unmounted_argument():
|
||||||
assert isinstance(unmounted_field, Argument)
|
assert isinstance(unmounted_field, Argument)
|
||||||
assert unmounted_field.type == RGB
|
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():
|
def test_enum_can_be_initialzied():
|
||||||
class RGB(Enum):
|
class RGB(Enum):
|
||||||
|
|
|
@ -46,8 +46,10 @@ def _call_and_get_arg(mocker, resolver_name, query):
|
||||||
|
|
||||||
def test_resolve_enum_python(mocker):
|
def test_resolve_enum_python(mocker):
|
||||||
arg = _call_and_get_arg(mocker, "resolve_python", "{python(v:P2)}")
|
arg = _call_and_get_arg(mocker, "resolve_python", "{python(v:P2)}")
|
||||||
assert arg == PythonBaseEnum.P2
|
assert arg is PythonBaseEnum.P2
|
||||||
assert arg == PythonEnum.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):
|
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):
|
def test_resolve_simple_enum(mocker):
|
||||||
arg = _call_and_get_arg(mocker, "resolve_simple", "{simple(v:S2)}")
|
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):
|
def test_resolve_enum_python(mocker):
|
||||||
|
|
|
@ -13,6 +13,7 @@ from graphql.type import (
|
||||||
|
|
||||||
from ..dynamic import Dynamic
|
from ..dynamic import Dynamic
|
||||||
from ..enum import Enum
|
from ..enum import Enum
|
||||||
|
from enum import Enum as PyEnum
|
||||||
from ..field import Field
|
from ..field import Field
|
||||||
from ..inputfield import InputField
|
from ..inputfield import InputField
|
||||||
from ..inputobjecttype import InputObjectType
|
from ..inputobjecttype import InputObjectType
|
||||||
|
@ -23,7 +24,7 @@ from ..structures import List, NonNull
|
||||||
from ..typemap import TypeMap, resolve_type
|
from ..typemap import TypeMap, resolve_type
|
||||||
|
|
||||||
|
|
||||||
def test_enum():
|
def test_enum_legacy():
|
||||||
class MyEnum(Enum):
|
class MyEnum(Enum):
|
||||||
"""Description"""
|
"""Description"""
|
||||||
|
|
||||||
|
@ -49,11 +50,46 @@ def test_enum():
|
||||||
assert values == [
|
assert values == [
|
||||||
GraphQLEnumValue(
|
GraphQLEnumValue(
|
||||||
name="foo",
|
name="foo",
|
||||||
value=MyEnum.foo,
|
value=1,
|
||||||
description="Description foo=1",
|
description="Description foo=1",
|
||||||
deprecation_reason="Is deprecated",
|
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):
|
if not deprecation_reason and callable(type._meta.deprecation_reason):
|
||||||
deprecation_reason = type._meta.deprecation_reason(value)
|
deprecation_reason = type._meta.deprecation_reason(value)
|
||||||
|
|
||||||
|
if type._meta.legacy_enum_resolver:
|
||||||
|
gql_value = value.value
|
||||||
|
else:
|
||||||
|
gql_value = value
|
||||||
|
|
||||||
values[name] = GraphQLEnumValue(
|
values[name] = GraphQLEnumValue(
|
||||||
name=name,
|
name=name,
|
||||||
value=value,
|
value=gql_value,
|
||||||
description=description,
|
description=description,
|
||||||
deprecation_reason=deprecation_reason,
|
deprecation_reason=deprecation_reason,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user