]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- move the "descriptor" properties into a separate module.
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 20 Dec 2010 21:04:05 +0000 (16:04 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 20 Dec 2010 21:04:05 +0000 (16:04 -0500)
lib/sqlalchemy/orm/descriptor_props.py [new file with mode: 0644]
lib/sqlalchemy/orm/properties.py

diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
new file mode 100644 (file)
index 0000000..f9df470
--- /dev/null
@@ -0,0 +1,302 @@
+# descriptor_props.py
+# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Michael Bayer
+# mike_mp@zzzcomputing.com
+#
+# This module is part of SQLAlchemy and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""Descriptor proprerties are more "auxilliary" properties
+that exist as configurational elements, but don't participate
+as actively in the load/persist ORM loop.   They all
+build on the "hybrid" extension to produce class descriptors.
+
+"""
+
+from sqlalchemy.orm.interfaces import \
+    MapperProperty, PropComparator, StrategizedProperty
+from sqlalchemy.orm import attributes
+from sqlalchemy import util, sql, exc as sa_exc
+from sqlalchemy.sql import expression
+properties = util.importlater('sqlalchemy.orm', 'properties')
+
+class DescriptorProperty(MapperProperty):
+    """:class:`MapperProperty` which proxies access to a 
+        user-defined descriptor."""
+
+    def instrument_class(self, mapper):
+        from sqlalchemy.ext import hybrid
+        
+        prop = self
+        
+        # hackety hack hack
+        class _ProxyImpl(object):
+            accepts_scalar_loader = False
+            expire_missing = True
+
+            def __init__(self, key):
+                self.key = key
+            
+            if hasattr(prop, 'get_history'):
+                def get_history(self, state, dict_, **kw):
+                    return prop.get_history(state, dict_, **kw)
+                
+        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
+
+    def create_row_processor(self, selectcontext, path, mapper, row, adapter):
+        return None, None, None
+
+    def merge(self, session, source_state, source_dict, 
+                dest_state, dest_dict, load, _recursive):
+        pass
+
+class CompositeProperty(DescriptorProperty):
+    
+    def __init__(self, class_, *columns, **kwargs):
+        self.columns = columns
+        self.composite_class = class_
+        self.active_history = kwargs.get('active_history', False)
+        self.deferred = kwargs.get('deferred', False)
+        self.group = kwargs.get('group', None)
+        
+        prop = self
+        def fget(instance):
+            return prop.composite_class(
+                *[getattr(instance, prop.parent._columntoproperty[col].key) 
+                for col in prop.columns]
+            )
+        def fset(instance, value):
+            if value is None:
+                fdel(instance)
+            else:
+                for col, value in zip(prop.columns, value.__composite_values__()):
+                    setattr(instance, prop.parent._columntoproperty[col].key, value)
+        
+        def fdel(instance):
+            for col in prop.columns:
+                setattr(instance, prop.parent._columntoproperty[col].key, None)
+        self.descriptor = property(fget, fset, fdel)
+        
+    def get_history(self, state, dict_, **kw):
+        """Provided for userland code that uses attributes.get_history()."""
+        
+        added = []
+        deleted = []
+        
+        has_history = False
+        for col in self.columns:
+            key = self.parent._columntoproperty[col].key
+            hist = state.manager[key].impl.get_history(state, dict_)
+            if hist.has_changes():
+                has_history = True
+            
+            added.extend(hist.non_deleted())
+            if hist.deleted:
+                deleted.extend(hist.deleted)
+            else:
+                deleted.append(None)
+        
+        if has_history:
+            return attributes.History(
+                [self.composite_class(*added)],
+                (),
+                [self.composite_class(*deleted)]
+            )
+        else:
+            return attributes.History(
+                (),[self.composite_class(*added)], ()
+            )
+
+    def do_init(self):
+        for col in self.columns:
+            prop = self.parent._columntoproperty[col]
+            prop.active_history = self.active_history
+            if self.deferred:
+                prop.deferred = self.deferred
+                prop.strategy_class = strategies.DeferredColumnLoader
+            prop.group = self.group
+        # strategies ...
+
+    def _comparator_factory(self, mapper):
+        return CompositeProperty.Comparator(self)
+
+    class Comparator(PropComparator):
+        def __init__(self, prop, adapter=None):
+            self.prop = prop
+            self.adapter = adapter
+            
+        def __clause_element__(self):
+            if self.adapter:
+                # TODO: test coverage for adapted composite comparison
+                return expression.ClauseList(
+                            *[self.adapter(x) for x in self.prop.columns])
+            else:
+                return expression.ClauseList(*self.prop.columns)
+        
+        __hash__ = None
+        
+        def __eq__(self, other):
+            if other is None:
+                values = [None] * len(self.prop.columns)
+            else:
+                values = other.__composite_values__()
+            return sql.and_(
+                    *[a==b for a, b in zip(self.prop.columns, values)])
+            
+        def __ne__(self, other):
+            return sql.not_(self.__eq__(other))
+
+    def __str__(self):
+        return str(self.parent.class_.__name__) + "." + self.key
+
+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.
+    * When a relationship() is configured on an inherited mapper,
+      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 __init__(self):
+        def warn():
+            raise AttributeError("Concrete %s does not implement "
+                "attribute %r at the instance level.  Add this "
+                "property explicitly to %s." % 
+                (self.parent, self.key, self.parent))
+
+        class NoninheritedConcreteProp(object):
+            def __set__(s, obj, value):
+                warn()
+            def __delete__(s, obj):
+                warn()
+            def __get__(s, obj, owner):
+                if obj is None:
+                    return self.descriptor
+                warn()
+        self.descriptor = NoninheritedConcreteProp()
+        
+        
+class SynonymProperty(DescriptorProperty):
+
+    def __init__(self, name, map_column=None, 
+                            descriptor=None, comparator_factory=None,
+                            doc=None):
+        self.name = name
+        self.map_column = map_column
+        self.descriptor = descriptor
+        self.comparator_factory = comparator_factory
+        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.
+            if self.key not in parent.mapped_table.c:
+                raise sa_exc.ArgumentError(
+                    "Can't compile synonym '%s': no column on table "
+                    "'%s' named '%s'" 
+                     % (self.name, parent.mapped_table.description, self.key))
+            elif parent.mapped_table.c[self.key] in \
+                    parent._columntoproperty and \
+                    parent._columntoproperty[
+                                            parent.mapped_table.c[self.key]
+                                        ].key == self.name:
+                raise sa_exc.ArgumentError(
+                    "Can't call map_column=True for synonym %r=%r, "
+                    "a ColumnProperty already exists keyed to the name "
+                    "%r for column %r" % 
+                    (self.key, self.name, self.name, self.key)
+                )
+            p = properties.ColumnProperty(parent.mapped_table.c[self.key])
+            parent._configure_property(
+                                    self.name, p, 
+                                    init=init, 
+                                    setparent=True)
+            p._mapped_by_synonym = self.key
+    
+        self.parent = parent
+        
+class ComparableProperty(DescriptorProperty):
+    """Instruments a Python property for use in query expressions."""
+
+    def __init__(self, comparator_factory, descriptor=None, doc=None):
+        self.descriptor = descriptor
+        self.comparator_factory = comparator_factory
+        self.doc = doc or (descriptor and descriptor.__doc__) or None
+        util.set_creation_order(self)
+
+    def _comparator_factory(self, mapper):
+        return self.comparator_factory(self, mapper)
index f16376ce60f1e6a17e1999bfbb1c3f01606bcc65..c7aa0eeea4e835ea05b1209a0fa74812e94479e2 100644 (file)
@@ -27,9 +27,10 @@ mapperlib = util.importlater("sqlalchemy.orm", "mapperlib")
 NoneType = type(None)
 
 __all__ = ('ColumnProperty', 'CompositeProperty', 'SynonymProperty',
-           'ComparableProperty', 'RelationshipProperty', 'RelationProperty',
-           'BackRef')
+           'ComparableProperty', 'RelationshipProperty', 'RelationProperty')
 
+from descriptor_props import CompositeProperty, SynonymProperty, \
+            ComparableProperty,ConcreteInheritedProperty
 
 class ColumnProperty(StrategizedProperty):
     """Describes an object attribute that corresponds to a table column."""
@@ -163,287 +164,6 @@ class ColumnProperty(StrategizedProperty):
 log.class_logger(ColumnProperty)
 
 
-class DescriptorProperty(MapperProperty):
-    """:class:`MapperProperty` which proxies access to a 
-        user-defined descriptor."""
-
-    def instrument_class(self, mapper):
-        from sqlalchemy.ext import hybrid
-        
-        prop = self
-        
-        # hackety hack hack
-        class _ProxyImpl(object):
-            accepts_scalar_loader = False
-            expire_missing = True
-
-            def __init__(self, key):
-                self.key = key
-            
-            if hasattr(prop, 'get_history'):
-                def get_history(self, state, dict_, **kw):
-                    return prop.get_history(state, dict_, **kw)
-                
-        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
-
-    def create_row_processor(self, selectcontext, path, mapper, row, adapter):
-        return None, None, None
-
-    def merge(self, session, source_state, source_dict, 
-                dest_state, dest_dict, load, _recursive):
-        pass
-
-class CompositeProperty(DescriptorProperty):
-    
-    def __init__(self, class_, *columns, **kwargs):
-        self.columns = columns
-        self.composite_class = class_
-        self.active_history = kwargs.get('active_history', False)
-        self.deferred = kwargs.get('deferred', False)
-        self.group = kwargs.get('group', None)
-        
-        prop = self
-        def fget(instance):
-            return prop.composite_class(
-                *[getattr(instance, prop.parent._columntoproperty[col].key) 
-                for col in prop.columns]
-            )
-        def fset(instance, value):
-            if value is None:
-                fdel(instance)
-            else:
-                for col, value in zip(prop.columns, value.__composite_values__()):
-                    setattr(instance, prop.parent._columntoproperty[col].key, value)
-        
-        def fdel(instance):
-            for col in prop.columns:
-                setattr(instance, prop.parent._columntoproperty[col].key, None)
-        self.descriptor = property(fget, fset, fdel)
-        
-    def get_history(self, state, dict_, **kw):
-        """Provided for userland code that uses attributes.get_history()."""
-        
-        added = []
-        deleted = []
-        
-        has_history = False
-        for col in self.columns:
-            key = self.parent._columntoproperty[col].key
-            hist = state.manager[key].impl.get_history(state, dict_)
-            if hist.has_changes():
-                has_history = True
-            
-            added.extend(hist.non_deleted())
-            if hist.deleted:
-                deleted.extend(hist.deleted)
-            else:
-                deleted.append(None)
-        
-        if has_history:
-            return attributes.History(
-                [self.composite_class(*added)],
-                (),
-                [self.composite_class(*deleted)]
-            )
-        else:
-            return attributes.History(
-                (),[self.composite_class(*added)], ()
-            )
-
-    def do_init(self):
-        for col in self.columns:
-            prop = self.parent._columntoproperty[col]
-            prop.active_history = self.active_history
-            if self.deferred:
-                prop.deferred = self.deferred
-                prop.strategy_class = strategies.DeferredColumnLoader
-            prop.group = self.group
-        # strategies ...
-
-    def _comparator_factory(self, mapper):
-        return CompositeProperty.Comparator(self)
-
-    class Comparator(PropComparator):
-        def __init__(self, prop, adapter=None):
-            self.prop = prop
-            self.adapter = adapter
-            
-        def __clause_element__(self):
-            if self.adapter:
-                # TODO: test coverage for adapted composite comparison
-                return expression.ClauseList(
-                            *[self.adapter(x) for x in self.prop.columns])
-            else:
-                return expression.ClauseList(*self.prop.columns)
-        
-        __hash__ = None
-        
-        def __eq__(self, other):
-            if other is None:
-                values = [None] * len(self.prop.columns)
-            else:
-                values = other.__composite_values__()
-            return sql.and_(
-                    *[a==b for a, b in zip(self.prop.columns, values)])
-            
-        def __ne__(self, other):
-            return sql.not_(self.__eq__(other))
-
-    def __str__(self):
-        return str(self.parent.class_.__name__) + "." + self.key
-
-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.
-    * When a relationship() is configured on an inherited mapper,
-      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 __init__(self):
-        def warn():
-            raise AttributeError("Concrete %s does not implement "
-                "attribute %r at the instance level.  Add this "
-                "property explicitly to %s." % 
-                (self.parent, self.key, self.parent))
-
-        class NoninheritedConcreteProp(object):
-            def __set__(s, obj, value):
-                warn()
-            def __delete__(s, obj):
-                warn()
-            def __get__(s, obj, owner):
-                if obj is None:
-                    return self.descriptor
-                warn()
-        self.descriptor = NoninheritedConcreteProp()
-        
-        
-class SynonymProperty(DescriptorProperty):
-
-    def __init__(self, name, map_column=None, 
-                            descriptor=None, comparator_factory=None,
-                            doc=None):
-        self.name = name
-        self.map_column = map_column
-        self.descriptor = descriptor
-        self.comparator_factory = comparator_factory
-        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.
-            if self.key not in parent.mapped_table.c:
-                raise sa_exc.ArgumentError(
-                    "Can't compile synonym '%s': no column on table "
-                    "'%s' named '%s'" 
-                     % (self.name, parent.mapped_table.description, self.key))
-            elif parent.mapped_table.c[self.key] in \
-                    parent._columntoproperty and \
-                    parent._columntoproperty[
-                                            parent.mapped_table.c[self.key]
-                                        ].key == self.name:
-                raise sa_exc.ArgumentError(
-                    "Can't call map_column=True for synonym %r=%r, "
-                    "a ColumnProperty already exists keyed to the name "
-                    "%r for column %r" % 
-                    (self.key, self.name, self.name, self.key)
-                )
-            p = ColumnProperty(parent.mapped_table.c[self.key])
-            parent._configure_property(
-                                    self.name, p, 
-                                    init=init, 
-                                    setparent=True)
-            p._mapped_by_synonym = self.key
-    
-        self.parent = parent
-        
-class ComparableProperty(DescriptorProperty):
-    """Instruments a Python property for use in query expressions."""
-
-    def __init__(self, comparator_factory, descriptor=None, doc=None):
-        self.descriptor = descriptor
-        self.comparator_factory = comparator_factory
-        self.doc = doc or (descriptor and descriptor.__doc__) or None
-        util.set_creation_order(self)
-
-    def _comparator_factory(self, mapper):
-        return self.comparator_factory(self, mapper)
 
 
 class RelationshipProperty(StrategizedProperty):