diff options
Diffstat (limited to 'lib/sqlalchemy/orm/properties.py')
-rw-r--r-- | lib/sqlalchemy/orm/properties.py | 173 |
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): |