summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/properties.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/properties.py')
-rw-r--r--lib/sqlalchemy/orm/properties.py173
1 files changed, 88 insertions, 85 deletions
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index edfb861f4..02e883de4 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -252,7 +252,63 @@ class CompositeProperty(ColumnProperty):
class DescriptorProperty(MapperProperty):
""":class:`MapperProperty` which proxies access to a
- plain descriptor."""
+ user-defined descriptor."""
+
+ def instrument_class(self, mapper):
+ from sqlalchemy.ext import hybrid
+
+ # hackety hack hack
+ class _ProxyImpl(object):
+ accepts_scalar_loader = False
+ expire_missing = True
+
+ def __init__(self, key):
+ self.key = key
+
+ if self.descriptor is None:
+ desc = getattr(mapper.class_, self.key, None)
+ if mapper._is_userland_descriptor(desc):
+ self.descriptor = desc
+
+ if self.descriptor is None:
+ def fset(obj, value):
+ setattr(obj, self.name, value)
+ def fdel(obj):
+ delattr(obj, self.name)
+ def fget(obj):
+ return getattr(obj, self.name)
+ fget.__doc__ = self.doc
+
+ descriptor = hybrid.property_(
+ fget=fget,
+ fset=fset,
+ fdel=fdel,
+ )
+ elif isinstance(self.descriptor, property):
+ descriptor = hybrid.property_(
+ fget=self.descriptor.fget,
+ fset=self.descriptor.fset,
+ fdel=self.descriptor.fdel,
+ )
+ else:
+ descriptor = hybrid.property_(
+ fget=self.descriptor.__get__,
+ fset=self.descriptor.__set__,
+ fdel=self.descriptor.__delete__,
+ )
+
+ proxy_attr = attributes.\
+ create_proxied_attribute(self.descriptor or descriptor)\
+ (
+ self.key,
+ self.descriptor or descriptor,
+ lambda: self._comparator_factory(mapper)
+ )
+ def get_comparator(owner):
+ return util.update_wrapper(proxy_attr, descriptor)
+ descriptor.expr = get_comparator
+ descriptor.impl = _ProxyImpl(self.key)
+ mapper.class_manager.instrument_attribute(self.key, descriptor)
def setup(self, context, entity, path, adapter, **kwargs):
pass
@@ -264,14 +320,13 @@ class DescriptorProperty(MapperProperty):
dest_state, dest_dict, load, _recursive):
pass
-
class ConcreteInheritedProperty(DescriptorProperty):
"""A 'do nothing' :class:`MapperProperty` that disables
an attribute on a concrete subclass that is only present
on the inherited mapper, not the concrete classes' mapper.
-
+
Cases where this occurs include:
-
+
* When the superclass mapper is mapped against a
"polymorphic union", which includes all attributes from
all subclasses.
@@ -279,10 +334,20 @@ class ConcreteInheritedProperty(DescriptorProperty):
but not on the subclass mapper. Concrete mappers require
that relationship() is configured explicitly on each
subclass.
-
+
"""
+
+ def _comparator_factory(self, mapper):
+ comparator_callable = None
+
+ for m in self.parent.iterate_to_root():
+ p = m._props[self.key]
+ if not isinstance(p, ConcreteInheritedProperty):
+ comparator_callable = p.comparator_factory
+ break
+ return comparator_callable
- def instrument_class(self, mapper):
+ def __init__(self):
def warn():
raise AttributeError("Concrete %s does not implement "
"attribute %r at the instance level. Add this "
@@ -295,26 +360,12 @@ class ConcreteInheritedProperty(DescriptorProperty):
def __delete__(s, obj):
warn()
def __get__(s, obj, owner):
+ if obj is None:
+ return self.descriptor
warn()
-
- comparator_callable = None
- # TODO: put this process into a deferred callable?
- for m in self.parent.iterate_to_root():
- p = m.get_property(self.key, _compile_mappers=False)
- if not isinstance(p, ConcreteInheritedProperty):
- comparator_callable = p.comparator_factory
- break
-
- attributes.register_descriptor(
- mapper.class_,
- self.key,
- comparator=comparator_callable(self, mapper),
- parententity=mapper,
- property_=self,
- proxy_property=NoninheritedConcreteProp()
- )
-
-
+ self.descriptor = NoninheritedConcreteProp()
+
+
class SynonymProperty(DescriptorProperty):
def __init__(self, name, map_column=None,
@@ -327,6 +378,15 @@ class SynonymProperty(DescriptorProperty):
self.doc = doc or (descriptor and descriptor.__doc__) or None
util.set_creation_order(self)
+ def _comparator_factory(self, mapper):
+ prop = getattr(mapper.class_, self.name).property
+
+ if self.comparator_factory:
+ comp = self.comparator_factory(prop, mapper)
+ else:
+ comp = prop.comparator_factory(prop, mapper)
+ return comp
+
def set_parent(self, parent, init):
if self.map_column:
# implement the 'map_column' option.
@@ -352,50 +412,8 @@ class SynonymProperty(DescriptorProperty):
init=init,
setparent=True)
p._mapped_by_synonym = self.key
-
+
self.parent = parent
-
- def instrument_class(self, mapper):
-
- if self.descriptor is None:
- desc = getattr(mapper.class_, self.key, None)
- if mapper._is_userland_descriptor(desc):
- self.descriptor = desc
-
- if self.descriptor is None:
- class SynonymProp(object):
- def __set__(s, obj, value):
- setattr(obj, self.name, value)
- def __delete__(s, obj):
- delattr(obj, self.name)
- def __get__(s, obj, owner):
- if obj is None:
- return s
- return getattr(obj, self.name)
-
- self.descriptor = SynonymProp()
-
- def comparator_callable(prop, mapper):
- def comparator():
- prop = mapper.get_property(
- self.name, resolve_synonyms=True,
- _compile_mappers=False)
- if self.comparator_factory:
- return self.comparator_factory(prop, mapper)
- else:
- return prop.comparator_factory(prop, mapper)
- return comparator
-
- attributes.register_descriptor(
- mapper.class_,
- self.key,
- comparator=comparator_callable(self, mapper),
- parententity=mapper,
- property_=self,
- proxy_property=self.descriptor,
- doc=self.doc
- )
-
class ComparableProperty(DescriptorProperty):
"""Instruments a Python property for use in query expressions."""
@@ -406,23 +424,8 @@ class ComparableProperty(DescriptorProperty):
self.doc = doc or (descriptor and descriptor.__doc__) or None
util.set_creation_order(self)
- def instrument_class(self, mapper):
- """Set up a proxy to the unmanaged descriptor."""
-
- if self.descriptor is None:
- desc = getattr(mapper.class_, self.key, None)
- if mapper._is_userland_descriptor(desc):
- self.descriptor = desc
-
- attributes.register_descriptor(
- mapper.class_,
- self.key,
- comparator=self.comparator_factory(self, mapper),
- parententity=mapper,
- property_=self,
- proxy_property=self.descriptor,
- doc=self.doc,
- )
+ def _comparator_factory(self, mapper):
+ return self.comparator_factory(self, mapper)
class RelationshipProperty(StrategizedProperty):