class_registry issue with multiple classes of the same name

Issue #3492 resolved
Kevin Thompson created an issue

In my specific use case, I have several postgresql schemas that have a table with the same name. I find that only the first 2 appear to be correctly registered in the class_registry. In add_class in clsregistry.py, it detects if the name already exists and switches it to a _MultipleClassMarker. However, when subsequent classes are added with the same name, they aren't registered. One fix is to change add_class to look like this:

    if classname in cls._decl_class_registry:
        # class already exists.
        existing = cls._decl_class_registry[classname]
        if not isinstance(existing, _MultipleClassMarker):
            existing = \
                cls._decl_class_registry[classname] = \
                _MultipleClassMarker([cls, existing])
        else:
            existing.add_item(cls)    # Add the new class in this new else clause
    else:
        cls._decl_class_registry[classname] = cls

I'm pretty new to sqlalchemy, so it's possible this solution is shooting myself in the foot somewhere else.

Comments (7)

  1. Mike Bayer repo owner

    can you show me a few of these classes so I can understand specifically what you're doing and I can see for myself the name not going where its expected? thanks.

  2. Kevin Thompson reporter

    Hey Mike. Thanks for getting back so quickly. Here is an example of 3 classes that will hit this problem. Put each class in its own file. Then import all 3 files. Then iterate through Base._decl_class_registry['Count'] and you'll see there are only 2 classes in there. I'd expect all 3 classes to be present. I'm running SQLAlchemy==1.0.7

    class Count(Base):
        """Count sorted by date"""
    
        __tablename__ = 'Count'
        __table_args__ = {'schema': 'schema 1'}
    
        date = Column('Date', Date, primary_key=True)
        count = Column('Count', Integer)
    
    class Count(Base):
        """Count sorted by date"""
    
        __tablename__ = 'Count'
        __table_args__ = {'schema': 'schema 2'}
    
        date = Column('Date', Date, primary_key=True)
        count = Column('Count', Integer)
    
    
    class Count(Base):
        """Count sorted by date"""
    
        __tablename__ = 'Count'
        __table_args__ = {'schema': 'schema 3'}
    
        date = Column('Date', Date, primary_key=True)
        count = Column('Count', Integer)
    

    Cheers

  3. Mike Bayer repo owner

    so, when you have classes of the same name, they must be referred to by module fully when you refer to them in a relationship. Run the following code with your three modules, assuming they are named "foo.a", "foo.b", and "foo.c", and you'll see they are all there:

    from . import a, b, c
    
    from . import base
    
    registry = base.Base._decl_class_registry['_sa_module_registry']
    print registry.resolve_attr("foo").a.Count
    print registry.resolve_attr("foo").b.Count
    print registry.resolve_attr("foo").c.Count
    
    #!
    
    classics-MacBook-Pro:tmp classic$ python -m foo
    {'Count': <sqlalchemy.ext.declarative.clsregistry._MultipleClassMarker object at 0x10441ebd8>, '_sa_module_registry': <sqlalchemy.ext.declarative.clsregistry._ModuleMarker object at 0x104406350>}
    <class 'foo.a.Count'>
    <class 'foo.b.Count'>
    <class 'foo.c.Count'>
    
  4. Mike Bayer repo owner

    yeah, these are all private APIs, we can at some point add a public API for all of this, if you have the need to refer to the registry outside of the usual way

  5. Kevin Thompson reporter

    It would be useful for me, but I have a fairly obscure use case so I understand if it's not on the roadmap.

  6. Log in to comment