Skip to content

MySQL Enum conversion issue #147

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

Closed
wants to merge 1 commit into from

Conversation

sebastiandev
Copy link

@sebastiandev sebastiandev commented Jul 24, 2018

When using reflection to build the models (instead of declarative) the Enum conversion fails because the ENUM column is treated as string so doing type.name returns None.

CREATE TABLE `foos` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `status` ENUM('open', 'closed') DEFAULT 'open',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
class Foo(Base):

    __table__ = Table('foos', metadata, autoload=True)

For some reason these kind of enums are returned as Strings so in the type definition we have to specify the field as string

class FooType(SQLAlchemyObjectType):
    class Meta:
        model = Foo
        interfaces = (relay.Node, )
  
    status = String()

When using reflection to build the models (instead of declarative) the Enum conversion fails because the ENUM column is treated as string so doing type.name returns None.

```sql
CREATE TABLE `foos` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `status` ENUM('open', 'closed') DEFAULT 'open',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

```python
class Foo(Base):

    __table__ = Table('foos', metadata, autoload=True)

```
@coveralls
Copy link

coveralls commented Jul 24, 2018

Coverage Status

Coverage increased (+0.02%) to 91.877% when pulling 9a45d60 on sebastiandev:patch-1 into 8872577 on graphql-python:master.

@syrusakbary
Copy link
Member

This PR is great. I will happily merge it once it have tests (so we don't incur on the same issue in the future).

@sebastiandev
Copy link
Author

Yeah, the thing is that we can only test this by inspecting a database to create the models. Is gonna be a tricky test to build, but the last PR fixing enums might include my fix.

@Ravi-Mobilution
Copy link

Ravi-Mobilution commented Sep 25, 2018

Is the fix merged? I am still getting the same error while creating a graphql object while autoloading the tables with Enum type columns from SQL DB using sqlalchemy.

Name: graphene
Version: 2.1.3
Summary: GraphQL Framework for Python

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-15-55dededbbd09> in <module>()
     20         model = DBConnect.Base.classes.guide_place
     21 
---> 22 class GuideObject(SQLAlchemyObjectType):
     23     class Meta:
     24         model = DBConnect.Base.classes.guide

~/anaconda3/envs/sage_mule/lib/python3.6/site-packages/graphene/utils/subclass_with_meta.py in __init_subclass__(cls, **meta_options)
     50             super_class = super(cls, cls)
     51             if hasattr(super_class, "__init_subclass_with_meta__"):
---> 52                 super_class.__init_subclass_with_meta__(**options)
     53 
     54     @classmethod

~/anaconda3/envs/sage_mule/lib/python3.6/site-packages/graphene_sqlalchemy/types.py in __init_subclass_with_meta__(cls, model, registry, skip_registry, only_fields, exclude_fields, connection, connection_class, use_connection, interfaces, id, _meta, **options)
    117 
    118         sqla_fields = yank_fields_from_attrs(
--> 119             construct_fields(model, registry, only_fields, exclude_fields), _as=Field
    120         )
    121 

~/anaconda3/envs/sage_mule/lib/python3.6/site-packages/graphene_sqlalchemy/types.py in construct_fields(model, registry, only_fields, exclude_fields)
     33             # in there. Or when we exclude this field in exclude_fields
     34             continue
---> 35         converted_column = convert_sqlalchemy_column(column, registry)
     36         fields[name] = converted_column
     37 

~/anaconda3/envs/sage_mule/lib/python3.6/site-packages/graphene_sqlalchemy/converter.py in convert_sqlalchemy_column(column, registry)
     78 
     79 def convert_sqlalchemy_column(column, registry=None):
---> 80     return convert_sqlalchemy_type(getattr(column, "type", None), column, registry)
     81 
     82 

~/anaconda3/envs/sage_mule/lib/python3.6/site-packages/singledispatch.py in wrapper(*args, **kw)
    208 
    209     def wrapper(*args, **kw):
--> 210         return dispatch(args[0].__class__)(*args, **kw)
    211 
    212     registry[object] = func

~/anaconda3/envs/sage_mule/lib/python3.6/site-packages/graphene_sqlalchemy/converter.py in convert_enum_to_enum(type, column, registry)
    152         items = zip(type.enums, type.enums)
    153     return Field(
--> 154         Enum(type.name, items),
    155         description=get_column_doc(column),
    156         required=not (is_column_nullable(column)),

~/anaconda3/envs/sage_mule/lib/python3.6/site-packages/graphene/types/enum.py in __call__(cls, *args, **kwargs)
     47         if cls is Enum:
     48             description = kwargs.pop("description", None)
---> 49             return cls.from_enum(PyEnum(*args, **kwargs), description=description)
     50         return super(EnumMeta, cls).__call__(*args, **kwargs)
     51         # return cls._meta.enum(*args, **kwargs)

~/anaconda3/envs/sage_mule/lib/python3.6/enum.py in __call__(cls, value, names, module, qualname, type, start)
    291             return cls.__new__(cls, value)
    292         # otherwise, functional API: we're creating a new Enum type
--> 293         return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
    294 
    295     def __contains__(cls, member):

~/anaconda3/envs/sage_mule/lib/python3.6/enum.py in _create_(cls, class_name, names, module, qualname, type, start)
    397                 member_name, member_value = item
    398             classdict[member_name] = member_value
--> 399         enum_class = metacls.__new__(metacls, class_name, bases, classdict)
    400 
    401         # TODO: replace the frame hack if a blessed way to know the calling

~/anaconda3/envs/sage_mule/lib/python3.6/enum.py in __new__(metacls, cls, bases, classdict)
    151 
    152         # create our new Enum type
--> 153         enum_class = super().__new__(metacls, cls, bases, classdict)
    154         enum_class._member_names_ = []               # names in definition order
    155         enum_class._member_map_ = OrderedDict()      # name->value map

TypeError: type.__new__() argument 1 must be str, not None

@erikwrede
Copy link
Member

Do you know if this is still an issue? Enum conversion has changed considerably since your original PR, including an enum registry and fallback names if no type name was specified. However, convert_enum_to_enum now calls enum_for_sa_enum. The underlying conversion method is called without a fallback name. I would expect an exception to still be thrown in this case, but it would be great if you could confirm this or adjust your fix!

@erikwrede erikwrede closed this Oct 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants