summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/changelog_08.rst13
-rw-r--r--lib/sqlalchemy/ext/declarative/base.py5
-rw-r--r--test/ext/declarative/test_mixin.py27
3 files changed, 44 insertions, 1 deletions
diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst
index 25accc8aa..6978162c2 100644
--- a/doc/build/changelog/changelog_08.rst
+++ b/doc/build/changelog/changelog_08.rst
@@ -12,6 +12,19 @@
: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
:tickets: 3044
diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py
index eb66f12b6..0e68faa03 100644
--- a/lib/sqlalchemy/ext/declarative/base.py
+++ b/lib/sqlalchemy/ext/declarative/base.py
@@ -73,7 +73,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 d8ec484e1..dab627596 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):