Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

graphene3: enum doesn't resolve to value #1277

Closed
Speedy1991 opened this issue Oct 19, 2020 · 10 comments
Closed

graphene3: enum doesn't resolve to value #1277

Speedy1991 opened this issue Oct 19, 2020 · 10 comments
Labels

Comments

@Speedy1991
Copy link

Speedy1991 commented Oct 19, 2020

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

@jkimbo
Copy link
Member

jkimbo commented Oct 19, 2020

@Speedy1991 What does your query look like?

@Speedy1991
Copy link
Author

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

@jkimbo
Copy link
Member

jkimbo commented Oct 21, 2020

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 #1153 To get the enum value you will have to access .value on the member in your mutation.

Does that make sense?

@Speedy1991
Copy link
Author

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)

@jkimbo
Copy link
Member

jkimbo commented Oct 21, 2020

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

Anyway closing this issue.

@jkimbo jkimbo closed this as completed Oct 21, 2020
@Speedy1991
Copy link
Author

Speedy1991 commented Oct 27, 2020

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

@jkimbo
Copy link
Member

jkimbo commented Oct 27, 2020

@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",
    }

@Speedy1991
Copy link
Author

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

@DenisseRR
Copy link

@jkimbo
I am migrating to graphene 3 and I am finding myself blocked by this.

There are a lot of places where I am using MyObjectType._meta.fields["my_enum_field"].type to give type to my graphene inputs, and even in some places I have something like

MyGeneratedEnum = MyObjectType._meta.fields["my_enum_field"].type

class MyMutation(graphene.Mutation):
    class Meta:
        enum_input = graphene.List(MyGeneratedEnum)

this will give me a list of the enums, not a list of the values, which forces me add extra code that was previously done automatically.

Do I now have to transform the list of enums into a list of values for every case or is there a better alternative?

@Eraldo
Copy link

Eraldo commented Feb 8, 2023

I also upgrading to v3 and running into a similar challenge as @DenisseRR.

By default when I inspect the schema type that is auto-generated for the enum Char fields, it does use the same type as MyObjectType._meta.fields["my_enum_field"].type. And as such I thought it might be nice to use the same as my input type. However then get an error when actually passing it to my MyModelSerializer, as it is neither a value nor the same enum as I am actually using in the model field (graphene somehow turns my MyEnum enum into MyAppMyModelMyEnumChoices.

Any ideas or instructions on what to do?
How is this intended?

karisal-anders added a commit to City-of-Helsinki/kukkuu that referenced this issue Jun 20, 2024
might be useful because Graphene 3 has changed from using enum values to
enums, for example:

```python
class TestEnum(graphene.Enum):
  FIRST = 'first'
  SECOND = 'second'
```

would've been serialized previously using the enum values, i.e.
'first' and 'second'. But with Graphene 3 they are serialized as
'TestEnum.FIRST' and 'TestEnum.SECOND'. This breaks functionality as
parts of the codebase are expecting the enum values as per Graphene 2.

Related https://github.com/graphql-python/graphene issues & PRs:
 - "Improve enum compatibility" PR:
   - graphql-python/graphene#1153
 - "graphene3: enum doesn't resolve to value" issue:
   - graphql-python/graphene#1277
 - "I would like my enum input values to be the enum instance instead
   of the enum values" issue:
   - graphql-python/graphene#1151

refs KK-1108
karisal-anders added a commit to City-of-Helsinki/kukkuu that referenced this issue Jul 8, 2024
might be useful because Graphene 3 has changed from using enum values to
enums, for example:

```python
class TestEnum(graphene.Enum):
  FIRST = 'first'
  SECOND = 'second'
```

would've been serialized previously using the enum values, i.e.
'first' and 'second'. But with Graphene 3 they are serialized as
'TestEnum.FIRST' and 'TestEnum.SECOND'. This breaks functionality as
parts of the codebase are expecting the enum values as per Graphene 2.

Related https://github.com/graphql-python/graphene issues & PRs:
 - "Improve enum compatibility" PR:
   - graphql-python/graphene#1153
 - "graphene3: enum doesn't resolve to value" issue:
   - graphql-python/graphene#1277
 - "I would like my enum input values to be the enum instance instead
   of the enum values" issue:
   - graphql-python/graphene#1151

refs KK-1108
karisal-anders added a commit to City-of-Helsinki/kukkuu that referenced this issue Jul 11, 2024
might be useful because Graphene 3 has changed from using enum values to
enums, for example:

```python
class TestEnum(graphene.Enum):
  FIRST = 'first'
  SECOND = 'second'
```

would've been serialized previously using the enum values, i.e.
'first' and 'second'. But with Graphene 3 they are serialized as
'TestEnum.FIRST' and 'TestEnum.SECOND'. This breaks functionality as
parts of the codebase are expecting the enum values as per Graphene 2.

Related https://github.com/graphql-python/graphene issues & PRs:
 - "Improve enum compatibility" PR:
   - graphql-python/graphene#1153
 - "graphene3: enum doesn't resolve to value" issue:
   - graphql-python/graphene#1277
 - "I would like my enum input values to be the enum instance instead
   of the enum values" issue:
   - graphql-python/graphene#1151

refs KK-1108
karisal-anders added a commit to City-of-Helsinki/kukkuu that referenced this issue Jul 15, 2024
might be useful because Graphene 3 has changed from using enum values to
enums, for example:

```python
class TestEnum(graphene.Enum):
  FIRST = 'first'
  SECOND = 'second'
```

would've been serialized previously using the enum values, i.e.
'first' and 'second'. But with Graphene 3 they are serialized as
'TestEnum.FIRST' and 'TestEnum.SECOND'. This breaks functionality as
parts of the codebase are expecting the enum values as per Graphene 2.

Related https://github.com/graphql-python/graphene issues & PRs:
 - "Improve enum compatibility" PR:
   - graphql-python/graphene#1153
 - "graphene3: enum doesn't resolve to value" issue:
   - graphql-python/graphene#1277
 - "I would like my enum input values to be the enum instance instead
   of the enum values" issue:
   - graphql-python/graphene#1151

refs KK-1108
karisal-anders added a commit to City-of-Helsinki/palvelutarjotin that referenced this issue Oct 9, 2024
Done:
 - Upgrade all dependencies
 - Upgrade postgresql from v10 to v13 (v13 is used in production)
 - Use ruff instead of black/isort/flake8, remove noqa's, reformat
 - Use pyproject.toml instead of setup.cfg

Background for @map_enums_to_values_in_kwargs decorator:

Graphene 3 changed from using enum values to enums, for example:
```python
class TestEnum(graphene.Enum):
  FIRST = 'first'
  SECOND = 'second'
```
would've been serialized previously using the enum values, i.e.
'first' and 'second'. But with Graphene 3 they are serialized as
'TestEnum.FIRST' and 'TestEnum.SECOND'. This broke functionality as
parts of the codebase were expecting the enum values as per Graphene 2.

Forced backwards compatibility by forcefully mapping enums to their
values.

Related https://github.com/graphql-python/graphene issues & PRs:
 - "Improve enum compatibility" PR:
   - graphql-python/graphene#1153
 - "graphene3: enum doesn't resolve to value" issue:
   - graphql-python/graphene#1277
 - "I would like my enum input values to be the enum instance instead
   of the enum values" issue:
   - graphql-python/graphene#1151

See https://github.com/graphql-python/graphene/wiki/v3-release-notes
for Graphene v3's breaking changes,

refs PT-1730
karisal-anders added a commit to City-of-Helsinki/palvelutarjotin that referenced this issue Oct 11, 2024
Done:
 - Upgrade all dependencies
 - Upgrade postgresql from v10 to v13 (v13 is used in production)
 - Use ruff instead of black/isort/flake8, remove noqa's, reformat
 - Use pyproject.toml instead of setup.cfg

Background for @map_enums_to_values_in_kwargs decorator:

Graphene 3 changed from using enum values to enums, for example:
```python
class TestEnum(graphene.Enum):
  FIRST = 'first'
  SECOND = 'second'
```
would've been serialized previously using the enum values, i.e.
'first' and 'second'. But with Graphene 3 they are serialized as
'TestEnum.FIRST' and 'TestEnum.SECOND'. This broke functionality as
parts of the codebase were expecting the enum values as per Graphene 2.

Forced backwards compatibility by forcefully mapping enums to their
values.

Related https://github.com/graphql-python/graphene issues & PRs:
 - "Improve enum compatibility" PR:
   - graphql-python/graphene#1153
 - "graphene3: enum doesn't resolve to value" issue:
   - graphql-python/graphene#1277
 - "I would like my enum input values to be the enum instance instead
   of the enum values" issue:
   - graphql-python/graphene#1151

See https://github.com/graphql-python/graphene/wiki/v3-release-notes
for Graphene v3's breaking changes,

refs PT-1730
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants