]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
a few changes to attributes.py to allow faster initialization of object attributes...
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 21 Mar 2006 04:38:54 +0000 (04:38 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 21 Mar 2006 04:38:54 +0000 (04:38 +0000)
lib/sqlalchemy/attributes.py
lib/sqlalchemy/mapping/mapper.py
lib/sqlalchemy/mapping/properties.py

index b03ead1c2ebf3d845f71efe1167b2eaf00be2780..437baeea8480f14200fe8123a7b49b41c9c0c49b 100644 (file)
@@ -72,6 +72,8 @@ class PropHistory(object):
         self.key = key
         self.orig = PropHistory.NONE
         self.extension = extension
+    def plain_init(self, *args):
+        pass
     def gethistory(self, *args, **kwargs):
         return self
     def clear(self):
@@ -152,7 +154,8 @@ class ListElement(util.HistoryArraySet):
             obj.__dict__[key] = []
             
         util.HistoryArraySet.__init__(self, list_, readonly=kwargs.get('readonly', False))
-
+    def plain_init(self, *args):
+        pass
     def gethistory(self, *args, **kwargs):
         return self
     def list_value_changed(self, obj, key, item, listval, isdelete):
@@ -194,6 +197,14 @@ class CallableProp(object):
         self.live = live
         self.kwargs = kwargs
 
+    def plain_init(self, attrhist):
+        if not self.uselist:
+            p = PropHistory(self.obj, self.key, **self.kwargs)
+            self.obj.__dict__[self.key] = None
+        else:
+            p = self.manager.create_list(self.obj, self.key, None, readonly=self.live, **self.kwargs)
+        attrhist[self.key] = p
+            
     def gethistory(self, passive=False, *args, **kwargs):
         if not self.uselist:
             if self.obj.__dict__.get(self.key, None) is None:
@@ -337,12 +348,21 @@ class AttributeManager(object):
         self.attribute_history(obj)[key] = p
         return p
 
+    def init_attr(self, obj):
+        """sets up the _managed_attributes dictionary on an object.  this happens anyway regardless
+        of this method being called, but saves on KeyErrors being thrown in get_history()."""
+        d = {}
+        obj.__dict__['_managed_attributes'] = d
+        cls_managed = self.class_managed(obj.__class__)
+        for value in cls_managed.values():
+            value(obj, d).plain_init(d)
+
     def get_history(self, obj, key, passive=False, **kwargs):
         """returns the "history" container for the given attribute on the given object.
         If the container does not exist, it will be created based on the class-level
         history container definition."""
         try:
-            return self.attribute_history(obj)[key].gethistory(passive=passive, **kwargs)
+            return obj.__dict__['_managed_attributes'][key].gethistory(passive=passive, **kwargs)
         except KeyError, e:
             return self.class_managed(obj.__class__)[key](obj, **kwargs).gethistory(passive=passive, **kwargs)
 
@@ -351,14 +371,14 @@ class AttributeManager(object):
         this dictionary is attached to the object via the attribute '_managed_attributes'.
         If the dictionary does not exist, it will be created."""
         try:
-            attr = obj.__dict__['_managed_attributes']
+            return obj.__dict__['_managed_attributes']
         except KeyError:
             trigger = obj.__dict__.pop('_managed_trigger', None)
             if trigger:
                 trigger()
             attr = {}
             obj.__dict__['_managed_attributes'] = attr
-        return attr
+            return attr
 
     def trigger_history(self, obj, callable):
         try:
@@ -424,13 +444,15 @@ class AttributeManager(object):
         the new object instance as an argument to create the new history container.  
         Extra keyword arguments can be sent which
         will be passed along to newly created history containers."""
-        def createprop(obj):
+        def createprop(obj, attrhist=None):
             if callable_ is not None: 
                 func = callable_(obj)
             else:
                 func = None
             p = self.create_history_container(obj, key, uselist, callable_=func, **kwargs)
-            self.attribute_history(obj)[key] = p
+            if attrhist is None:
+                attrhist = self.attribute_history(obj)
+            attrhist[key] = p
             return p
         
         self.class_managed(class_)[key] = createprop
index 32271aff5cd00852466e662c975f5cffeb92d887..a46064e6f46b64aa31e4954c5f6f69f49402f03f 100644 (file)
@@ -239,6 +239,10 @@ class Mapper(object):
         if not self.class_.__dict__.has_key('_mapper'):
             oldinit = self.class_.__init__
             def init(self, *args, **kwargs):
+                # this gets the AttributeManager to do some pre-initialization,
+                # in order to save on KeyErrors later on
+                objectstore.global_attributes.init_attr(self)
+                
                 nohist = kwargs.pop('_mapper_nohistory', False)
                 session = kwargs.pop('_sa_session', objectstore.get_session())
                 if not nohist:
index 4d04997a65dce25967220acf6a56da89390c4e05..ff3d1548c1a1ef875f8bbf4193b21825fce84f8c 100644 (file)
@@ -714,6 +714,9 @@ class EagerLoader(PropertyLoader):
                     #print "new eagertqarget", p.eagertarget.name, (p.secondary and p.secondary.name or "none"), p.parent.table.name
             finally:
                 del recursion_stack[self.parent.table]
+
+        self._row_decorator = self._create_decorator_row()
+        
         self._eager_chained = True
                 
     def _aliasize_orderby(self, orderby, copy=True):
@@ -758,7 +761,6 @@ class EagerLoader(PropertyLoader):
         for key, value in self.mapper.props.iteritems():
             value.setup(key, statement, eagertable=self.eagertarget)
             
-        self._decorator_row = self._create_decorator_row()
         
     def execute(self, instance, row, identitykey, imap, isnew):
         """receive a row.  tell our mapper to look for a new object instance in the row, and attach
@@ -809,7 +811,7 @@ class EagerLoader(PropertyLoader):
         # (neither do any MapperExtensions).  The row is keyed off the Column object
         # (which is what mappers use) as well as its "label" (which might be what
         # user-defined code is using)
-        row = self._decorator_row(row)
+        row = self._row_decorator(row)
         return self.mapper._instance(row, imap, result_list)
 
 class GenericOption(MapperOption):