Skip to content

AssertionError: Found different types with the same name in the schema #211

Description

@Rafik-Belkadi

I have two Classes Products and SalableProducts in my Models (SalableProducts inherits from Products so it has every field of it's database), in my Schema here is what i did

class  Product(SQLAlchemyObjectType):
    class Meta:
        model = ProductModel
        interfaces = (relay.Node, )
        
class ProductConnections(relay.Connection):
    class Meta:
        node = Product
class  SalableProduct(SQLAlchemyObjectType):
    class Meta:
        model = SalableProductModel
        interfaces = (relay.Node, )

class  SalableProductConnections(relay.Connection):
    class Meta:
        node = SalableProduct

and here is my Query class :

class Query(graphene.ObjectType):
    node = relay.Node.Field()
    all_products = SQLAlchemyConnectionField(ProductConnections)
    all_salable_products = SQLAlchemyConnectionField(SalableProductConnections)  

When i run my server i got this error :

AssertionError: Found different types with the same name in the schema: product_status, product_status.

Activity

  1. Cito commented on Apr 30, 2019

    @Cito
    Member

    Is product_status an enum?

  2. Rafik-Belkadi commented on Apr 30, 2019

    @Rafik-Belkadi
    Author

    Is product_status an enum?

    Yes it is in my mixin

  3. Cito commented on Apr 30, 2019

    @Cito
    Member

    Then it's the known problem for which I have proposed a solution in #210. It happens when you use the same enum in different columns (or maybe in your case, in a class and a subclass). The enum type is not reused, but created twice with the same name.

  4. Rafik-Belkadi commented on May 2, 2019

    @Rafik-Belkadi
    Author

    I really could not get to apply your solutions, could you please provide some details, saw your latest commits on improving Enum type creation but can't use it at the moment. is there a quick fix i can try ?

    Then it's the known problem for which I have proposed a solution in #210. It happens when you use the same enum in different columns (or maybe in your case, in a class and a subclass). The enum type is not reused, but created twice with the same name.

  5. Cito commented on May 2, 2019

    @Cito
    Member

    You would probably need to somehow patch the SalableProduct to make it use the same enum, when using the current version of graphene-sqlalchemy. I expect the fix will be merged and released soon.

  6. rdemetrescu commented on Jun 13, 2019

    @rdemetrescu

    I use this monkey-patch on my projects:

    from functools import lru_cache
    
    graphene.Enum.from_enum = lru_cache(maxsize=None)(graphene.Enum.from_enum)
  7. allardhoeve commented on Jun 13, 2019

    @allardhoeve
  8. lungati commented on Oct 8, 2019

    @lungati

    Your code is not in release 2.2.0..

  9. richin13 commented on Oct 29, 2019

    @richin13
    Contributor

    I'm running into this issue. I defined my model like this:

    class MyModel(db.Model):
        status_before = db.Column(db.Enum(AdStatus), nullable=False)
        status_during = db.Column(db.Enum(AdStatus), nullable=False)

    Which fails with:

    AssertionError
    
    AssertionError: Found different types with the same name in the schema: AdStatus, AdStatus.
    

    Versions:

    flask-graphql       2.0.0   Adds GraphQL support to your Flask application
    graphene            2.1.8   GraphQL Framework for Python
    graphene-sqlalchemy 2.2.2   Graphene SQLAlchemy integration
    graphql-core        2.2.1   GraphQL implementation for Python
    graphql-relay       2.0.0   Relay implementation for Python
    graphql-server-core 1.1.1   GraphQL Server tools for powering your server
    
  10. danjenson commented on Feb 11, 2020

    @danjenson

    I am also getting this error using the same Enum in various SQLAlchemy models.

  11. danjenson commented on Feb 11, 2020

    @danjenson

    So, for the record, I solved this by making global SQLAlchemy types, so @richin13 , your code would become:

    SA_AdStatus = db.Enum(AdStatus)
    
    class MyModel(db.Model):
        status_before = db.Column(SA_AdStatus, nullable=False)
        status_during = db.Column(SA_AdStatus, nullable=False)
    
  12. spacether commented on May 14, 2020

    @spacether

    This problem is caused by multiple enum classes being created with the same definition.
    Graphene sees them as different classes with the same name.
    You can solve it in one of two ways:

    1. by defining the enum class once, then using that defined class at all locations.
    2. use the suggested lru_cache as a wrapper around the class creation to do the same thing

    We ran into this problem when creating a custom scalar type and using it in multiple locations.
    lru_cache wrapping around our returned class solved the problem for us.

  13. rdemetrescu commented on Jun 20, 2020

    @rdemetrescu

    This problem is caused by multiple enum classes being created with the same definition.
    Graphene sees them as different classes with the same name.
    You can solve it in one of two ways:

    1. by defining the enum class once, then using that defined class at all locations.
    2. use the suggested lru_cache as a wrapper around the class creation to do the same thing

    We ran into this problem when creating a custom scalar type and using it in multiple locations.
    lru_cache wrapping around our returned class solved the problem for us.

    when you say "wrapping around our returned class" you don't mean you are using the lru_cache multiple times in your project, right?

    The lru_cache hack I suggested should be used only once before your SQLAlchemy models are declared. If your model declarations are spread among multiple files, you don't need to write graphene.Enum.from_enum = lru_cache(maxsize=None)(graphene.Enum.from_enum) on each file.

  14. spacether commented on Jun 20, 2020

    @spacether

    Yes, I mean one code location for both solutions.
    Not multiple locations. Only one location uses lru_cache.

  15. lungati commented on Jan 6, 2021

    @lungati

    I notice sqlalchemy_utils enum is being converted to graphene enum type.

      1. This section of code is triggered multiple times:
        def from_enum( cls, enum, description=None, deprecation_reason=None ): # noqa: N805 description = description or enum.__doc__ meta_dict = { "enum": enum, "description": description, "deprecation_reason": deprecation_reason, } meta_class = type("Meta", (object,), meta_dict) return type(meta_class.enum.__name__, (Enum,), {"Meta": meta_class})

    -2 Here.. Not sure if this is triggered automatically:
    @convert_sqlalchemy_type.register(types.Enum) def convert_enum_to_enum(type, column, registry=None): return lambda: enum_for_sa_enum(type, registry or get_global_registry())

    N.B: My models include this section: business_domain = Column(Enum(BusinessDomain), nullable=False)

    -3 And here... I trigger the same code here because I need to list the values of the enum. Commenting out this section resolves the issue but I need this list of values!
    graphene.List(graphene.Enum.from_enum(BusinessDomain))

    Noticed the LRU cache fix above won't help if you have different enums

  16. lungati commented on Jan 7, 2021

    @lungati

    You can turn off the automatic conversion of your enums #98 (comment) This is the solution!!! Spent a day and a half finding it

  17. cglacet commented on Apr 18, 2021

    @cglacet

    I feel like sqlalchemy is building things every time it reads Enum(e). So if we use two columns with this type it will fail the second time.

    class MyModel(db.Model):
        status_before = db.Column(db.Enum(AdStatus), nullable=False)
        status_during = db.Column(db.Enum(AdStatus), nullable=False)

    Does crash. While

    StatusColumn = db.Enum(AdStatus)
    
    class MyModel(db.Model):
        status_before = db.Column(StatusColumn, nullable=False)
        status_during = db.Column(StatusColumn, nullable=False)

    Works fine. If you have an enum declaration next to your model you can even do:

    import enum
    from sqlalchemy import Column, Enum
    
    @Enum
    class Status(enum.Enum):
        STARTED = 1
        CANCELED = 2
        
       
    class TagType(Base):
        status_before = Column(Status, nullable=False)
        status_during = Column(Status, nullable=False)
  18. yesthesoup commented on Apr 11, 2022

    @yesthesoup

    To solve this issue I created a separate type and imported it in both places I want to use it:

    import graphene
    
    from my_project.models.core import MyEnum
    
    my_enum = graphene.Enum.from_enum(MyEnum)

    and then in the query/mutation:

    from my_project.routes.graphql.types.common import my_enum
    
    class MyMutation(graphene.Mutation)
    
        ...
    
        class Arguments:
           ...
           paramName = my_enum(required=True)
           ...
  19. ddlima-roku commented on Jul 18, 2022

    @ddlima-roku

    @rdemetrescu great solution - I hope this can be merged into graphene

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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