Mike Bayer committed a702126

some comments, changed SmartProperty to be smarter, UOW
version has "property" accessor which returns MapperProperty at
the class level

Comments (0)

Files changed (5)


 via the GenericBackrefExtension object.
-import sqlalchemy.util as util
+import util
 class SmartProperty(object):
     """Provides a property object that will communicate set/get/delete operations
     create_prop method on AttributeManger, which can be overridden to provide
     subclasses of SmartProperty.
-    def __init__(self, manager):
+    def __init__(self, manager, key, uselist):
         self.manager = manager
-    def attribute_registry(self):
-        return self.manager
-    def property(self, key, uselist):
-        def set_prop(obj, value):
-            self.attribute_registry().set_attribute(obj, key, value)
-        def del_prop(obj):
-            self.attribute_registry().delete_attribute(obj, key)
-        def get_prop(obj):
-            if uselist:
-                return self.attribute_registry().get_list_attribute(obj, key)
-            else:
-                return self.attribute_registry().get_attribute(obj, key)
-        return property(get_prop, set_prop, del_prop)
+        self.key = key
+        self.uselist = uselist
+    def __set__(self, obj, value):
+        self.manager.set_attribute(obj, self.key, value)
+    def __delete__(self, obj):
+        self.manager.delete_attribute(obj, self.key)
+    def __get__(self, obj, owner):
+        if obj is None:
+            return self
+        if self.uselist:
+            return self.manager.get_list_attribute(obj, self.key)
+        else:
+            return self.manager.get_attribute(obj, self.key)
 class PropHistory(object):
     """Used by AttributeManager to track the history of a scalar attribute
         upon an attribute change of value."""
-    def create_prop(self, key, uselist, **kwargs):
+    def create_prop(self, class_, key, uselist, **kwargs):
         """creates a scalar property object, defaulting to SmartProperty, which 
         will communicate change events back to this AttributeManager."""
-        return SmartProperty(self).property(key, uselist)
+        return SmartProperty(self, key, uselist)
     def create_list(self, obj, key, list_, **kwargs):
         """creates a history-aware list property, defaulting to a ListElement which
         is a subclass of HistoryArrayList."""
             return p
         self.class_managed(class_)[key] = createprop
-        setattr(class_, key, self.create_prop(key, uselist))
+        setattr(class_, key, self.create_prop(class_, key, uselist))


     engines = property(lambda s: [t.engine for t in s.tables])
     def add_property(self, key, prop):
+        """adds an additional property to this mapper.  this is the same as if it were 
+        specified within the 'properties' argument to the constructor.  if the named
+        property already exists, this will replace it.  Useful for
+        circular relationships, or overriding the parameters of auto-generated properties
+        such as backreferences."""
         if sql.is_column(prop):
             self.columns[key] = prop
             prop = ColumnProperty(prop)


 def import_instance(instance):
     return get_session().import_instance(instance)
+class UOWProperty(attributes.SmartProperty):
+    def __init__(self, class_, *args, **kwargs):
+        super(UOWProperty, self).__init__(*args, **kwargs)
+        self.class_ = class_
+    property = property(lambda s:class_mapper(s.class_).props[s.key], doc="returns the MapperProperty object associated with this property")
 class UOWListElement(attributes.ListElement):
     def __init__(self, obj, key, data=None, deleteremoved=False, **kwargs):
         attributes.ListElement.__init__(self, obj, key, data=data, **kwargs)
+    def create_prop(self, class_, key, uselist, **kwargs):
+        return UOWProperty(class_, self, key, uselist)
     def create_list(self, obj, key, list_, **kwargs):
         return UOWListElement(obj, key, list_, **kwargs)
 class DependencySorter(topological.QueueDependencySorter):
 def mapper(*args, **params):
     return sqlalchemy.mapperlib.mapper(*args, **params)
 def object_mapper(obj):
     return sqlalchemy.mapperlib.object_mapper(obj)
+def class_mapper(class_):
+    return sqlalchemy.mapperlib.class_mapper(class_)
 global_attributes = UOWAttributeManager()
 session_registry = util.ScopedRegistry(Session) # Default session registry
 _sessions = weakref.WeakValueDictionary() # all referenced sessions (including user-created)


         objectstore.uow().register_attribute(class_, key, uselist = self.uselist, deleteremoved = self.private, extension=self.attributeext)
     def _get_direction(self):
+        """determines our 'direction', i.e. do we represent one to many, many to many, etc."""
 #        print self.key, repr(, repr(, repr(
         if self.parent.table is
             if self.foreignkey.primary_key:
             return (obj2, obj1)
     def process_dependencies(self, task, deplist, uowcommit, delete = False):
+        """this method is called during a commit operation to synchronize data between a parent and child object.  
+        it also can establish child or parent objects within the unit of work as "to be saved" or "deleted" 
+        in some cases."""
         #print + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
         def getlist(obj, passive=True):
         self.assert_result(l, User, *[{'user_id':8}])
         l = m.select_by(User.c.user_name=='fred', addresses.c.email_address!='', user_id=9)
+    def testprops(self):
+        """tests the various attributes of the properties attached to classes"""
+        m = mapper(User, users, properties = {
+            'addresses' : relation(mapper(Address, addresses))
+        })
+        self.assert_( is m.props['addresses'])
     def testload(self):
         """tests loading rows with a mapper and producing object instances"""