summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/attributes.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-03-03 13:51:54 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-03-03 13:51:54 -0500
commit75a3f84e5f9c3be645be2ec8906e63b27e9847e5 (patch)
tree6185577783e17e8c73dc208af62552f05a57cb1b /lib/sqlalchemy/orm/attributes.py
parentb83dd4dc2200bece2896a125be6d4f0911669d15 (diff)
downloadsqlalchemy-75a3f84e5f9c3be645be2ec8906e63b27e9847e5.tar.gz
- Improved checking for an existing backref name conflict during
mapper configuration; will now test for name conflicts on superclasses and subclasses, in addition to the current mapper, as these conflicts break things just as much. This is new for 0.8, but see below for a warning that will also be triggered in 0.7.11. - Improved the error message emitted when a "backref loop" is detected, that is when an attribute event triggers a bidirectional assignment between two other attributes with no end. This condition can occur not just when an object of the wrong type is assigned, but also when an attribute is mis-configured to backref into an existing backref pair. Also in 0.7.11. - A warning is emitted when a MapperProperty is assigned to a mapper that replaces an existing property, if the properties in question aren't plain column-based properties. Replacement of relationship properties is rarely (ever?) what is intended and usually refers to a mapper mis-configuration. Also in 0.7.11. [ticket:2674]
Diffstat (limited to 'lib/sqlalchemy/orm/attributes.py')
-rw-r--r--lib/sqlalchemy/orm/attributes.py24
1 files changed, 18 insertions, 6 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index c9385daaa..b281fabec 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -433,6 +433,9 @@ class AttributeImpl(object):
self.expire_missing = expire_missing
+ def __str__(self):
+ return "%s.%s" % (self.class_.__name__, self.key)
+
def _get_active_history(self):
"""Backwards compat for impl.active_history"""
@@ -1043,11 +1046,18 @@ def backref_listeners(attribute, key, uselist):
parent_token = attribute.impl.parent_token
- def _acceptable_key_err(child_state, initiator):
+ def _acceptable_key_err(child_state, initiator, child_impl):
raise ValueError(
- "Object %s not associated with attribute of "
- "type %s" % (orm_util.state_str(child_state),
- manager_of_class(initiator.class_)[initiator.key]))
+ "Bidirectional attribute conflict detected: "
+ 'Passing object %s to attribute "%s" '
+ 'triggers a modify event on attribute "%s" '
+ 'via the backref "%s".' % (
+ orm_util.state_str(child_state),
+ initiator.parent_token,
+ child_impl.parent_token,
+ attribute.impl.parent_token
+ )
+ )
def emit_backref_from_scalar_set_event(state, child, oldchild, initiator):
if oldchild is child:
@@ -1069,7 +1079,7 @@ def backref_listeners(attribute, key, uselist):
child_impl = child_state.manager[key].impl
if initiator.parent_token is not parent_token and \
initiator.parent_token is not child_impl.parent_token:
- _acceptable_key_err(state, initiator)
+ _acceptable_key_err(state, initiator, child_impl)
child_impl.append(
child_state,
child_dict,
@@ -1085,9 +1095,11 @@ def backref_listeners(attribute, key, uselist):
child_state, child_dict = instance_state(child), \
instance_dict(child)
child_impl = child_state.manager[key].impl
+
+ print initiator.parent_token, parent_token, child_impl.parent_token
if initiator.parent_token is not parent_token and \
initiator.parent_token is not child_impl.parent_token:
- _acceptable_key_err(state, initiator)
+ _acceptable_key_err(state, initiator, child_impl)
child_impl.append(
child_state,
child_dict,