Commits

Mike Bayer committed a702126

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

  • Participants
  • Parent commits 77084a5

Comments (0)

Files changed (5)

File lib/sqlalchemy/attributes.py

 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."""
         pass
         
-    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))
 

File lib/sqlalchemy/mapping/mapper.py

     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)

File lib/sqlalchemy/mapping/objectstore.py

 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)
             get_session(obj).register_dirty(obj)
         else:
             get_session(obj).register_new(obj)
+            
+    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):
     pass
-        
+
 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)
 

File lib/sqlalchemy/mapping/properties.py

         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(self.parent.table.name), repr(self.parent.primarytable.name), repr(self.foreignkey.table.name)
         if self.parent.table is self.target:
             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.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
 
         def getlist(obj, passive=True):

File test/mapper.py

         self.assert_result(l, User, *[{'user_id':8}])
 
         l = m.select_by(User.c.user_name=='fred', addresses.c.email_address!='ed@bettyboop.com', 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_(User.addresses.property is m.props['addresses'])
         
     def testload(self):
         """tests loading rows with a mapper and producing object instances"""