graphene3: enum doesn't resolve to value

Created on 19 Oct 2020  路  8Comments  路  Source: graphql-python/graphene

Using enums as inputFields leads to errors

SalutationEnum = graphene.Enum('SalutationEnum', [('Man', 0), ('Woman', 1)])

class MyModel(Model):
  salutation = models.IntegerField()

class SomeInput(graphene.InputObjectType):
    salutation = SalutationEnum(required=True)

class MyMutation(graphene.Mutation):
    ...
    class Arguments:
        input = SomeInput(required=True)
    ...

    mutate(self, info, input):
        ...
        myModel.salutation = input.salutation
        myModel.save()

leads to

"message": "Field 'salutation' expected a number but got <SalutationEnum.Man: 0>.",

I think the problem is, that SalutationEnum is not resolved to its value (this worked in graphene 2.x) but resolved to a SalutationEnum

salutation: SalutationEnum{
  name: 'Man'
  value: 0
}

This code would work:

 myModel.salutation = input.salutation.value
 myModel.save()

But I don't think it is intended to call value on each enum?

Edit:
Just found #1151 - looks like this is intended??

graphene: 3.0.0b5

馃悰 bug

All 8 comments

@Speedy1991 What does your query look like?

mutation MyMutation($input: SomeInput!){
  myMutation(input: $input){
    success
  }
}

variables (typescriped with codegen):
{"input": {"salutation": SalutationEnum.Man}}

Codegen generated type:

export enum SalutationEnum {
  Man = "Man",
  Woman= "Woman",
}

typescript generated with:
apollo codegen:generate --outputFlat --config apollo.config.js --target typescript --tagName=gql --globalTypesFile=src/types/graphql-global-types.ts src/types

Ah ok @Speedy1991 this is the expected behaviour. Starting in Graphene 3 enum inputs to mutations are the enum member rather than the enum value (which was the case in Graphene 2). See https://github.com/graphql-python/graphene/pull/1153 To get the enum value you will have to access .value on the member in your mutation.

Does that make sense?

Yea that makes sense.
Some magic is no more working with this approach. That's a pitty.

E.g. Django.:

def mutate(self, info, id, **kwargs):
    instance = Model.objects.get(id=id)
    for k, v in kwargs.items():
        setattr(instance, k, v)
    instance.save(update_fields=[kwargs.keys()])

My workaround is now:

    for k, v in kwargs.items():
        try:
            v = v.value
        except AttributeError:
            pass
        setattr(instance, k, v)

Ah ok I see. You can also check if the value is an enum before trying to access .value.

Anyway closing this issue.

Hey @jkimbo
Just found another issue with enums:

MemberRoleEnum = graphene.Enum('MemberRoleEnum', [('Vertrieb', 'staff'), ('Administrator', 'admin')])

class MemberType(DjangoObjectType):
    role = MemberRoleEnum(required=False)

    def resolve_role(self, info):
        return self.role  # 'admin'

Query MemberType with
{ member { role }}

Leads to

{
  "message": "Expected a value of type 'MemberRoleEnum' but received: 'MemberRoleEnum.Administrator'",
  "payload": null,
  "code": 500,
  "messages": [],
  "messageDict": {},
  "exception": [
    "TypeError"
  ],
  "trace": [
    "  File \"C:\\Users\\Speedy\\git\\proj\\_lib\\venv\\lib\\site-packages\\graphql\\execution\\execute.py\", line 631, in complete_value_catching_error\n    completed = self.complete_value(\n",
    "  File \"C:\\Users\\Speedy\\git\\proj\\_lib\\venv\\lib\\site-packages\\graphql\\execution\\execute.py\", line 730, in complete_value\n    return self.complete_leaf_value(cast(GraphQLLeafType, return_type), result)\n",
    "  File \"C:\\Users\\Speedy\\git\\proj\\_lib\\venv\\lib\\site-packages\\graphql\\execution\\execute.py\", line 815, in complete_leaf_value\n    raise TypeError(\n"
  ]
}

That worked back in graphene2. Any idea whats going wrong here?

Running
graphene==3.0.0b6
graphene_django==3.0.0b6

@Speedy1991 I can't reproduce that issue. Running this works for me:

def test_enum_issue_1277():
    MemberRoleEnum = Enum(
        "MemberRoleEnum", [("Vertrieb", "staff"), ("Administrator", "admin")]
    )

    class Query(ObjectType):
        role = MemberRoleEnum(required=False)

        def resolve_role(self, info):
            return self["role"]  # 'admin'

    schema = Schema(Query)
    result = schema.execute("{ role }", root={"role": "admin"})

    assert not result.errors
    assert result.data == {
        "role": "Administrator",
    }

Just tried your example and I can confirm this is working

Just debuged deep into this process and found that I wrote a wrong value into the DB when I tried around with the enums.

That was really confusing because the database value was MemberRoleEnum.Administrator and not admin.

Btw. great work @jkimbo & contributors - looking foward the 3.0 release

Was this page helpful?
0 / 5 - 0 ratings