From: Mike Bayer Date: Sun, 19 Feb 2006 01:25:56 +0000 (+0000) Subject: some comments, changed SmartProperty to be smarter, UOW X-Git-Tag: rel_0_1_1~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=36383494b512143328d3c14022d4db3ccedfdf06;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git some comments, changed SmartProperty to be smarter, UOW version has "property" accessor which returns MapperProperty at the class level --- diff --git a/lib/sqlalchemy/attributes.py b/lib/sqlalchemy/attributes.py index 7a9f13c57c..bea125371b 100644 --- a/lib/sqlalchemy/attributes.py +++ b/lib/sqlalchemy/attributes.py @@ -27,7 +27,7 @@ The package includes functions for managing "bi-directional" object relationship 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 @@ -35,22 +35,21 @@ class SmartProperty(object): 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 @@ -254,10 +253,10 @@ class AttributeManager(object): 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.""" @@ -411,5 +410,5 @@ class AttributeManager(object): 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)) diff --git a/lib/sqlalchemy/mapping/mapper.py b/lib/sqlalchemy/mapping/mapper.py index 5fed7c7f29..88b803b37e 100644 --- a/lib/sqlalchemy/mapping/mapper.py +++ b/lib/sqlalchemy/mapping/mapper.py @@ -178,6 +178,11 @@ class Mapper(object): 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) diff --git a/lib/sqlalchemy/mapping/objectstore.py b/lib/sqlalchemy/mapping/objectstore.py index 8f5f4eb0be..94e2f966b0 100644 --- a/lib/sqlalchemy/mapping/objectstore.py +++ b/lib/sqlalchemy/mapping/objectstore.py @@ -243,6 +243,12 @@ def instance_key(instance): 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) @@ -269,6 +275,9 @@ class UOWAttributeManager(attributes.AttributeManager): 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) @@ -991,15 +1000,17 @@ class UOWTask(object): 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) -global_attributes = UOWAttributeManager() +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) diff --git a/lib/sqlalchemy/mapping/properties.py b/lib/sqlalchemy/mapping/properties.py index 65f9cbdc26..3a2aaab2fd 100644 --- a/lib/sqlalchemy/mapping/properties.py +++ b/lib/sqlalchemy/mapping/properties.py @@ -219,6 +219,7 @@ class PropertyLoader(MapperProperty): 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: @@ -391,6 +392,9 @@ class PropertyLoader(MapperProperty): 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): diff --git a/test/mapper.py b/test/mapper.py index 2dabc8b670..38c168dfe7 100644 --- a/test/mapper.py +++ b/test/mapper.py @@ -99,6 +99,13 @@ class MapperTest(MapperSuperTest): 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"""