diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-05-10 11:05:30 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-05-10 11:05:30 -0400 |
| commit | 743e9d4589946f1a29cdec7f2f1a2e4ec0853db7 (patch) | |
| tree | 5d0575514ae23d74f48478f71e1478336ccca803 /lib | |
| parent | 9bdd6f2b1f6b34a82b77849ec05811aa0279931d (diff) | |
| download | sqlalchemy-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.py | 18 |
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, |
