summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/attributes.py19
-rw-r--r--lib/sqlalchemy/orm/interfaces.py13
-rw-r--r--lib/sqlalchemy/orm/properties.py37
-rw-r--r--lib/sqlalchemy/orm/query.py5
-rw-r--r--lib/sqlalchemy/orm/util.py2
5 files changed, 55 insertions, 21 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py
index 86da9a61d..7effd8e58 100644
--- a/lib/sqlalchemy/orm/attributes.py
+++ b/lib/sqlalchemy/orm/attributes.py
@@ -131,7 +131,7 @@ class QueryableAttribute(interfaces._MappedAttribute,
self.key = key
self.impl = impl
self.comparator = comparator
- self.parententity = parententity
+ self._parententity = parententity
self._of_type = of_type
manager = manager_of_class(class_)
@@ -159,6 +159,10 @@ class QueryableAttribute(interfaces._MappedAttribute,
return self
@property
+ def parent(self):
+ return self._parententity
+
+ @property
def expression(self):
return self.comparator.__clause_element__()
@@ -171,7 +175,7 @@ class QueryableAttribute(interfaces._MappedAttribute,
self.key,
self.impl,
self.comparator.of_type(cls),
- self.parententity,
+ self._parententity,
of_type=cls)
def label(self, name):
@@ -191,9 +195,11 @@ class QueryableAttribute(interfaces._MappedAttribute,
return getattr(self.comparator, key)
except AttributeError:
raise AttributeError(
- 'Neither %r object nor %r object has an attribute %r' % (
+ 'Neither %r object nor %r object associated with %s '
+ 'has an attribute %r' % (
type(self).__name__,
type(self.comparator).__name__,
+ self,
key)
)
@@ -281,7 +287,7 @@ def create_proxied_attribute(descriptor):
return self.descriptor.__get__(instance, owner)
def __str__(self):
- return self.key
+ return "%s.%s" % (self.class_.__name__, self.key)
def __getattr__(self, attribute):
"""Delegate __getattr__ to the original descriptor and/or
@@ -294,12 +300,15 @@ def create_proxied_attribute(descriptor):
return getattr(self.comparator, attribute)
except AttributeError:
raise AttributeError(
- 'Neither %r object nor %r object has an attribute %r' % (
+ 'Neither %r object nor %r object associated with %s '
+ 'has an attribute %r' % (
type(descriptor).__name__,
type(self.comparator).__name__,
+ self,
attribute)
)
+
Proxy.__name__ = type(descriptor).__name__ + 'Proxy'
util.monkeypatch_proxied_specials(Proxy, type(descriptor),
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index 272d4edd5..b30630434 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -305,11 +305,12 @@ class PropComparator(operators.ColumnOperators):
"""
- def __init__(self, prop, mapper, adapter=None):
+ def __init__(self, prop, parentmapper, adapter=None):
self.prop = self.property = prop
- self.mapper = mapper
+ self._parentmapper = parentmapper
self.adapter = adapter
+
def __clause_element__(self):
raise NotImplementedError("%r" % self)
@@ -319,7 +320,7 @@ class PropComparator(operators.ColumnOperators):
"""
- return self.__class__(self.prop, self.mapper, adapter)
+ return self.__class__(self.prop, self._parentmapper, adapter)
@staticmethod
def any_op(a, b, **kwargs):
@@ -503,7 +504,7 @@ class PropertyOption(MapperOption):
d['key'] = ret = []
for token in util.to_list(self.key):
if isinstance(token, PropComparator):
- ret.append((token.mapper.class_, token.key))
+ ret.append((token._parentmapper.class_, token.key))
else:
ret.append(token)
return d
@@ -628,7 +629,7 @@ class PropertyOption(MapperOption):
# matching tokens to entities
if current_path:
if current_path[0:2] == \
- [token.parententity, prop.key]:
+ [token._parententity, prop.key]:
current_path = current_path[2:]
continue
else:
@@ -638,7 +639,7 @@ class PropertyOption(MapperOption):
entity = self._find_entity_prop_comparator(
query,
prop.key,
- token.parententity,
+ token._parententity,
raiseerr)
if not entity:
return no_result
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 048b4fad3..a0abb2743 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -189,8 +189,8 @@ class ColumnProperty(StrategizedProperty):
return self.adapter(self.prop.columns[0])
else:
return self.prop.columns[0]._annotate({
- "parententity": self.mapper,
- "parentmapper": self.mapper})
+ "parententity": self._parentmapper,
+ "parentmapper": self._parentmapper})
def __getattr__(self, key):
"""proxy attribute access down to the mapped column.
@@ -352,13 +352,13 @@ class RelationshipProperty(StrategizedProperty):
_of_type = None
- def __init__(self, prop, mapper, of_type=None, adapter=None):
+ def __init__(self, prop, parentmapper, of_type=None, adapter=None):
"""Construction of :class:`.RelationshipProperty.Comparator`
is internal to the ORM's attribute mechanics.
"""
self.prop = prop
- self.mapper = mapper
+ self._parentmapper = parentmapper
self.adapter = adapter
if of_type:
self._of_type = of_type
@@ -370,14 +370,37 @@ class RelationshipProperty(StrategizedProperty):
"""
- return self.__class__(self.property, self.mapper,
+ return self.__class__(self.property, self._parentmapper,
getattr(self, '_of_type', None),
adapter)
@util.memoized_property
- def parententity(self):
+ def mapper(self):
+ """The target :class:`.Mapper` referred to by this
+ :class:`.RelationshipProperty.Comparator.
+
+ This is the "target" or "remote" side of the
+ :func:`.relationship`.
+
+ """
+ return self.property.mapper
+
+ @util.memoized_property
+ def parent(self):
+ """The parent :class:`.Mapper` or :class:`.AliasedClass`
+ referred to by this
+ :class:`.RelationshipProperty.Comparator.
+
+ This is the "parent" or "local" side of the
+ :func:`.relationship`.
+
+ """
return self.property.parent
+ @util.memoized_property
+ def _parententity(self):
+ return self.parent
+
def _source_selectable(self):
elem = self.property.parent._with_polymorphic_selectable
if self.adapter:
@@ -412,7 +435,7 @@ class RelationshipProperty(StrategizedProperty):
"""
return RelationshipProperty.Comparator(
self.property,
- self.mapper,
+ self._parentmapper,
cls, adapter=self.adapter)
def in_(self, other):
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index a6d20a973..02fb7d4f7 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -1727,7 +1727,7 @@ class Query(object):
# and Class is that of the current joinpoint
elif from_joinpoint and \
isinstance(onclause, interfaces.PropComparator):
- left_entity = onclause.parententity
+ left_entity = onclause._parententity
info = inspect(self._joinpoint_zero())
left_mapper, left_selectable, left_is_aliased = \
@@ -1750,7 +1750,8 @@ class Query(object):
else:
right_entity = onclause.property.mapper
- left_entity = onclause.parententity
+ left_entity = onclause._parententity
+ assert left_entity is onclause.parent
prop = onclause.property
if not isinstance(onclause, attributes.QueryableAttribute):
diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py
index 2e38e0ce3..fb4197c58 100644
--- a/lib/sqlalchemy/orm/util.py
+++ b/lib/sqlalchemy/orm/util.py
@@ -464,7 +464,7 @@ class AliasedClass(object):
# used to assign a name to the RowTuple object
# returned by Query.
self._sa_label_name = aliased_insp.name
- self.__name__ = 'AliasedClass_' + str(self.__target)
+ self.__name__ = 'AliasedClass_%s' % self.__target.__name__
@util.memoized_property
def _sa_path_registry(self):