Skip to content

Enum choice order and input type not working #134

Closed
@kaglowka

Description

@kaglowka

I detected various more and less serious issues with current Enum implementation. I place them here in one issue as I think they are closely related. Should I split it, maybe?

Currently, if any field converted from django Model to graphene.Field has choices defined, the field is converted to graphene.Enum with corresponding value-label pairs.

1) Choice order

Django choices (value, label) order is different from python Enum (label, value) underlying graphene.Enum. Tests have passed as they contained only (string, string) case. While (string, int) throws no exception, (int, string), required by Django field choices, does:

from graphene.contrib.django import DjangoNode

class OneFieldNode(DjangoNode):
    class Meta:
        model = OneFieldModel
from django.db import models

class OneFieldModel(models.Model):
    field = models.IntegerField(u'Poziom stanowiska',
                                choices=[(1, u'First choice'), (2, u'Second choice')])
class OneFieldNode(DjangoNode):
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/graphene/core/classtypes/base.py", line 31, in __new__
    return mcs.construct(new_class, bases, attrs)
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/graphene/contrib/django/types.py", line 45, in construct
    cls.construct_fields()
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/graphene/contrib/django/types.py", line 32, in construct_fields
    converted_field = convert_django_field_with_choices(field)
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/graphene/contrib/django/converter.py", line 16, in convert_django_field_with_choices
    return Enum(name.upper(), choices, description=field.help_text)
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/graphene/core/classtypes/enum.py", line 22, in __call__
    '__enum__': PyEnum(name, names)
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/enum/__init__.py", line 332, in __call__
    return cls._create_(value, names, module=module, type=type)
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/enum/__init__.py", line 442, in _create_
    classdict[member_name] = member_value
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/enum/__init__.py", line 123, in __setitem__
    if _is_sunder(key):
  File "/home/tomek/htdocs/isivi/env/local/lib/python2.7/site-packages/enum/__init__.py", line 80, in _is_sunder
    return (name[0] == name[-1] == '_' and 
TypeError: Error when calling the metaclass bases
    'int' object has no attribute '__getitem__'

2) contribute_to_class
Even when the order issue is fixed, fields converted in this way won't be included in the schema as graphene.Enum class, which is a ClassType (unlike all other FieldType types, into which Django fields are converted), doesn't implement contribute_to_class.

My quick fix for this was (in contrib.django.converter):
return Field(Enum(name.upper(), choices, description=field.help_text))
instead of
return Enum(name.upper(), choices, description=field.help_text)

3) Optional conversion
Finally, automatic conversion to Enum might be optional, as I, for example, have used Django field choices as a kind of label used in frontend, which means that it is not a strict constant name and typically contains spaces. Unfortunately, spaces used in constant names are not supported in python Enum. Thus, obligatory conversion to Enum makes me unable to use my pre-GraphQL Django schema.

4) Enum as InputType
The implementation of Enum is still incomplete, as it cannot be used as InputType which is a major drawback. For me, using constant names in relay code would seem to be the most important advantage of graphQL Enum over simple Integer. Below an example that is visibly not implemented

class MyEnum(graphene.Enum):
    FIRST = 1
    SECOND = 2

class OneFieldMutation(ClientIDMutation):
    class Input:
        one = MyEnum # not working
        two = Field(MyEnum) # not working


    @classmethod
    def mutate_and_get_payload(cls, input, info):
        pass

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions