Name conflict on instantiation of inherited class

Issue #2377 resolved
Florian Schulze created an issue

In certain cases when a class is instanciated, there can be a name conflict which causes wrong values on attributes. Here is a diff with a test case against current head (should apply to at least 0.7.x):

diff -r cd6e5d6dea83d5d5317765f14b15641fdf54ecc0 test/orm/inheritance/test_polymorph2.py
--- a/test/orm/inheritance/test_polymorph2.py   Tue Jan 17 19:35:55 2012 -0500
+++ b/test/orm/inheritance/test_polymorph2.py   Wed Jan 18 14:05:42 2012 +0100
@@ -1263,4 +1263,43 @@
             }
         )
         assert Dude.supervisor.property.direction is MANYTOONE
-        self._dude_roundtrip()
\ No newline at end of file
+        self._dude_roundtrip()
+
+class NameConflictTest(fixtures.TestBase):
+    def test_name_conflict(self):
+        from sqlalchemy.ext.declarative import declarative_base
+        metadata = MetaData(testing.db)
+        Base = declarative_base(metadata=metadata)
+
+        class Content(Base):
+            __tablename__ = u'content'
+
+            id = Column(Integer, primary_key=True,
+                                test_needs_autoincrement=True)
+
+            type = Column(String(30))
+
+            __mapper_args__ = dict(polymorphic_on=type)
+
+        class Foo(Content):
+            __tablename__ = u'foo'
+            __mapper_args__ = dict(polymorphic_identity='foo')
+
+            id = Column(Integer, ForeignKey('content.id'),
+                                primary_key=True)
+
+            content_type = Column(String(30))
+
+        configure_mappers()
+        metadata.create_all()
+
+        sess = create_session()
+        f = Foo()
+        f.content_type = u'bar'
+        sess.add(f)
+        sess.flush()
+        f_id = f.id
+        print f.content_type
+        del f
+        sess.expunge_all()
+        assert sess.query(Content).get(f_id).content_type == u'bar'

Comments (7)

  1. Florian Schulze reporter

    A standalone version of the test:

    from sqlalchemy import create_engine
    from sqlalchemy import Column, ForeignKey, Integer, String
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker
    
    
    engine = create_engine('sqlite:///:memory:', echo=True)
    
    Base = declarative_base(engine)
    metadata = Base.metadata
    Session = sessionmaker(bind=engine)
    
    
    class Content(Base):
        __tablename__ = u'content'
    
        id = Column(Integer, primary_key=True)
    
        type = Column(String(30))
    
        __mapper_args__ = dict(polymorphic_on=type)
    
    
    class Foo(Content):
        __tablename__ = u'foo'
        __mapper_args__ = dict(polymorphic_identity='foo')
    
        id = Column(Integer, ForeignKey('content.id'),
                            primary_key=True)
    
        content_type = Column(String(30))
    
    #configure_mappers()
    metadata.create_all()
    
    sess = Session()
    f = Foo()
    f.content_type = u'bar'
    sess.add(f)
    sess.flush()
    f_id = f.id
    print f.content_type
    del f
    sess.expunge_all()
    assert sess.query(Content).get(f_id).content_type == u'bar'
    
  2. Mike Bayer repo owner

    ugh....OK...this is not the fix but this confirms it's the key_fallback that's doing this:

    diff -r 8c05a3bf6599f92bbf8d2246123597e8966f3a52 lib/sqlalchemy/engine/base.py
    --- a/lib/sqlalchemy/engine/base.py Wed Jan 18 12:42:54 2012 -0500
    +++ b/lib/sqlalchemy/engine/base.py Wed Jan 18 14:42:27 2012 -0500
    @@ -2642,7 +2642,7 @@
             # fallback for targeting a ColumnElement to a textual expression
             # this is a rare use case which only occurs when matching text()
             # constructs to ColumnElements, and after a pickle/unpickle roundtrip
    -        elif isinstance(key, expression.ColumnElement):
    +        elif False: #isinstance(key, expression.ColumnElement):
                 if key._label and key._label.lower() in map:
                     result = map[key._label.lower()](key._label.lower())
                 elif hasattr(key, 'name') and key.name.lower() in map:
    

    this is a high priority issue.

  3. Mike Bayer repo owner

    the fix is very involved. not sure when I can have all the edge cases worked out, general idea is attached.

  4. Mike Bayer repo owner

    that patch gets everything plus adds tests to orm and sql. a little more review and it'll be good.

  5. Log in to comment