From: Mike Bayer Date: Fri, 30 May 2014 19:36:13 +0000 (-0400) Subject: - The ``__mapper_args__`` dictionary is copied from a declarative X-Git-Tag: rel_0_8_7~15 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=01eb52b516f19bb9b8aef4b8657a27c14063aad5;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - The ``__mapper_args__`` dictionary is copied from a declarative mixin or abstract class when accessed, so that modifications made to this dictionary by declarative itself won't conflict with that of other mappings. The dictionary is modified regarding the ``version_id_col`` and ``polymorphic_on`` arguments, replacing the column within with the one that is officially mapped to the local class/table. fixes #3062 --- diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 8b00ce1faa..7736f77996 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -11,6 +11,19 @@ .. changelog:: :version: 0.8.7 + .. change:: + :tags: bug, declarative + :versions: 1.0.0, 0.9.5 + :tickets: 3062 + + The ``__mapper_args__`` dictionary is copied from a declarative + mixin or abstract class when accessed, so that modifications made + to this dictionary by declarative itself won't conflict with that + of other mappings. The dictionary is modified regarding the + ``version_id_col`` and ``polymorphic_on`` arguments, replacing the + column within with the one that is officially mapped to the local + class/table. + .. change:: :tags: bug, sql :versions: 0.9.5, 1.0.0 diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py index cfcd13a181..9da2ed7271 100644 --- a/lib/sqlalchemy/ext/declarative/base.py +++ b/lib/sqlalchemy/ext/declarative/base.py @@ -66,7 +66,10 @@ def _as_declarative(cls, classname, dict_): # don't even invoke __mapper_args__ until # after we've determined everything about the # mapped table. - mapper_args_fn = lambda: cls.__mapper_args__ + # make a copy of it so a class-level dictionary + # is not overwritten when we update column-based + # arguments. + mapper_args_fn = lambda: dict(cls.__mapper_args__) elif name == '__tablename__': if not tablename and ( not class_mapped or diff --git a/test/ext/declarative/test_mixin.py b/test/ext/declarative/test_mixin.py index fb674f27a2..70fe115fb5 100644 --- a/test/ext/declarative/test_mixin.py +++ b/test/ext/declarative/test_mixin.py @@ -1173,6 +1173,33 @@ class DeclarativeMixinPropertyTest(DeclarativeTestBase): eq_(col.name, 'type_') assert col.table is not None + def test_column_in_mapper_args_used_multiple_times(self): + + class MyMixin(object): + + version_id = Column(Integer) + __mapper_args__ = {'version_id_col': version_id} + + class ModelOne(Base, MyMixin): + + __tablename__ = 'm1' + id = Column(Integer, primary_key=True) + + class ModelTwo(Base, MyMixin): + + __tablename__ = 'm2' + id = Column(Integer, primary_key=True) + + is_( + ModelOne.__mapper__.version_id_col, + ModelOne.__table__.c.version_id + ) + is_( + ModelTwo.__mapper__.version_id_col, + ModelTwo.__table__.c.version_id + ) + + def test_deferred(self): class MyMixin(object):