summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-05-10 11:05:30 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2016-05-10 11:05:30 -0400
commit743e9d4589946f1a29cdec7f2f1a2e4ec0853db7 (patch)
tree5d0575514ae23d74f48478f71e1478336ccca803 /lib
parent9bdd6f2b1f6b34a82b77849ec05811aa0279931d (diff)
downloadsqlalchemy-743e9d4589946f1a29cdec7f2f1a2e4ec0853db7.tar.gz
Check for duplicate calls to register_attribute_impl
Fixed bug whereby the event listeners used for backrefs could be inadvertently applied multiple times, when using a deep class inheritance hierarchy in conjunction with mutiple mapper configuration steps. Change-Id: I712beaf4674e2323bf5b282922658020a6d00b53 Fixes: #3710
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/orm/strategies.py18
1 files changed, 15 insertions, 3 deletions
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 3c03a681d..37cecb079 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -71,8 +71,20 @@ def _register_attribute(
)
)
+ # a single MapperProperty is shared down a class inheritance
+ # hierarchy, so we set up attribute instrumentation and backref event
+ # for each mapper down the hierarchy.
+
+ # typically, "mapper" is the same as prop.parent, due to the way
+ # the configure_mappers() process runs, however this is not strongly
+ # enforced, and in the case of a second configure_mappers() run the
+ # mapper here might not be prop.parent; also, a subclass mapper may
+ # be called here before a superclass mapper. That is, can't depend
+ # on mappers not already being set up so we have to check each one.
+
for m in mapper.self_and_descendants:
- if prop is m._props.get(prop.key):
+ if prop is m._props.get(prop.key) and \
+ not m.class_manager._attr_has_impl(prop.key):
desc = attributes.register_attribute_impl(
m.class_,
@@ -83,8 +95,8 @@ def _register_attribute(
useobject=useobject,
extension=attribute_ext,
trackparent=useobject and (
- prop.single_parent
- or prop.direction is interfaces.ONETOMANY),
+ prop.single_parent or
+ prop.direction is interfaces.ONETOMANY),
typecallable=typecallable,
callable_=callable_,
active_history=active_history,