diff --git a/graphene/types/definitions.py b/graphene/types/definitions.py index 32516229..6a34c97f 100644 --- a/graphene/types/definitions.py +++ b/graphene/types/definitions.py @@ -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) diff --git a/graphene/types/enum.py b/graphene/types/enum.py index a6150c0d..261b0bfe 100644 --- a/graphene/types/enum.py +++ b/graphene/types/enum.py @@ -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) diff --git a/graphene/types/tests/test_enum.py b/graphene/types/tests/test_enum.py index 2ef8214f..599e162b 100644 --- a/graphene/types/tests/test_enum.py +++ b/graphene/types/tests/test_enum.py @@ -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): diff --git a/graphene/types/tests/test_resolver_enum_arg.py b/graphene/types/tests/test_resolver_enum_arg.py index 8d871a6e..7db9bd01 100644 --- a/graphene/types/tests/test_resolver_enum_arg.py +++ b/graphene/types/tests/test_resolver_enum_arg.py @@ -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): diff --git a/graphene/types/tests/test_resolver_enum_arg_legacy.py b/graphene/types/tests/test_resolver_enum_arg_legacy.py index 3f259e5f..5ffdc845 100644 --- a/graphene/types/tests/test_resolver_enum_arg_legacy.py +++ b/graphene/types/tests/test_resolver_enum_arg_legacy.py @@ -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): diff --git a/graphene/types/tests/test_typemap.py b/graphene/types/tests/test_typemap.py index bcac529b..c6635a10 100644 --- a/graphene/types/tests/test_typemap.py +++ b/graphene/types/tests/test_typemap.py @@ -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"), ] diff --git a/graphene/types/typemap.py b/graphene/types/typemap.py index 36485427..3b4b1caf 100644 --- a/graphene/types/typemap.py +++ b/graphene/types/typemap.py @@ -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, )