]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
attempting to cut down on function call overhead
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 May 2007 16:56:11 +0000 (16:56 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 May 2007 16:56:11 +0000 (16:56 +0000)
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/strategies.py
lib/sqlalchemy/types.py
test/orm/mapper.py
test/perf/masseagerload.py

index e642bd54bfc679f46dceae30b7733138ad604976..bfddb9c994a3c7defb035b68ddf8c8ae99973597 100644 (file)
@@ -33,7 +33,7 @@ class MapperProperty(object):
         
         callables are of the following form:
         
-            def execute(instance, row, flags):
+            def execute(instance, row, **flags):
                 # process incoming instance and given row.
                 # flags is a dictionary containing at least the following attributes:
                 #   isnew - indicates if the instance was newly created as a result of reading this row
@@ -41,7 +41,7 @@ class MapperProperty(object):
                 # optional attribute:
                 #   ispostselect - indicates if this row resulted from a 'post' select of additional tables/columns
                 
-            def post_execute(instance, flags):
+            def post_execute(instance, **flags):
                 # process instance after all result rows have been processed.  this
                 # function should be used to issue additional selections in order to
                 # eagerly load additional properties.
index 24fdb8e6cce02c680c86a7ecd2ad3ce2bab00193..1017c3def46f4d7d0b1a2c1705ea9e82ca9a4a37 100644 (file)
@@ -1462,9 +1462,9 @@ class Mapper(object):
                 if not context.identity_map.has_key(identitykey):
                     context.identity_map[identitykey] = instance
                     isnew = True
-                if extension.populate_instance(self, context, row, instance, {'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
-                    self.populate_instance(context, instance, row, {'instancekey':identitykey, 'isnew':isnew})
-            if extension.append_result(self, context, row, instance, result, {'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
+                if extension.populate_instance(self, context, row, instance, **{'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
+                    self.populate_instance(context, instance, row, **{'instancekey':identitykey, 'isnew':isnew})
+            if extension.append_result(self, context, row, instance, result, **{'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
                 if result is not None:
                     result.append(instance)
             return instance
@@ -1505,9 +1505,9 @@ class Mapper(object):
 
         # call further mapper properties on the row, to pull further
         # instances from the row and possibly populate this item.
-        if extension.populate_instance(self, context, row, instance, {'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
-            self.populate_instance(context, instance, row, {'instancekey':identitykey, 'isnew':isnew})
-        if extension.append_result(self, context, row, instance, result, {'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
+        if extension.populate_instance(self, context, row, instance, **{'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
+            self.populate_instance(context, instance, row, **{'instancekey':identitykey, 'isnew':isnew})
+        if extension.append_result(self, context, row, instance, result, **{'instancekey':identitykey, 'isnew':isnew}) is EXT_PASS:
             if result is not None:
                 result.append(instance)
         return instance
@@ -1555,10 +1555,10 @@ class Mapper(object):
                 newrow[c] = row[c2]
         return newrow
 
-    def populate_instance(self, selectcontext, instance, row, flags):
+    def populate_instance(self, selectcontext, instance, row, ispostselect=None, **flags):
         """populate an instance from a result row."""
 
-        populators = selectcontext.attributes.get(('instance_populators', self, flags.get('ispostselect')), None)
+        populators = selectcontext.attributes.get(('instance_populators', self, ispostselect), None)
         if populators is None:
             populators = []
             post_processors = []
@@ -1573,11 +1573,11 @@ class Mapper(object):
             if poly_select_loader is not None:
                 post_processors.append(poly_select_loader)
                 
-            selectcontext.attributes[('instance_populators', self, flags.get('ispostselect'))] = populators
-            selectcontext.attributes[('post_processors', self, flags.get('ispostselect'))] = post_processors
+            selectcontext.attributes[('instance_populators', self, ispostselect)] = populators
+            selectcontext.attributes[('post_processors', self, ispostselect)] = post_processors
 
         for p in populators:
-            p(instance, row, flags)
+            p(instance, row, ispostselect=ispostselect, **flags)
             
         if self.non_primary:
             selectcontext.attributes[('populating_mapper', instance)] = self
@@ -1595,7 +1595,7 @@ class Mapper(object):
         
         cond, param_names = self._deferred_inheritance_condition(needs_tables)
         statement = sql.select(needs_tables, cond, use_labels=True)
-        def post_execute(instance, flags):
+        def post_execute(instance, **flags):
             self.__log_debug("Post query loading instance " + mapperutil.instance_str(instance))
 
             identitykey = self.instance_key(instance)
@@ -1604,7 +1604,7 @@ class Mapper(object):
             for c in param_names:
                 params[c.name] = self.get_attr_by_column(instance, c)
             row = selectcontext.session.connection(self).execute(statement, **params).fetchone()
-            self.populate_instance(selectcontext, instance, row, {'isnew':False, 'instancekey':identitykey, 'ispostselect':True})
+            self.populate_instance(selectcontext, instance, row, **{'isnew':False, 'instancekey':identitykey, 'ispostselect':True})
 
         return post_execute
             
@@ -1710,7 +1710,7 @@ class MapperExtension(object):
 
         return EXT_PASS
 
-    def append_result(self, mapper, selectcontext, row, instance, result, flags):
+    def append_result(self, mapper, selectcontext, row, instance, result, **flags):
         """Receive an object instance before that instance is appended
         to a result list.
 
@@ -1735,14 +1735,14 @@ class MapperExtension(object):
         result
           List to which results are being appended.
 
-        flags
+        \**flags
           extra information about the row, same as criterion in
           `create_row_processor()` method of [sqlalchemy.orm.interfaces#MapperProperty]
         """
 
         return EXT_PASS
 
-    def populate_instance(self, mapper, selectcontext, row, instance, flags):
+    def populate_instance(self, mapper, selectcontext, row, instance, **flags):
         """Receive a newly-created instance before that instance has
         its attributes populated.
 
index 2941815a1c8775c1510dad16b2e8bc843ca9391f..d15d29a228a1385616679b5fb61b137be5261a1b 100644 (file)
@@ -35,8 +35,8 @@ class ColumnLoader(LoaderStrategy):
 
     def create_row_processor(self, selectcontext, mapper, row):
         if self.columns[0] in row:
-            def execute(instance, row, flags):
-                if flags['isnew'] or flags.get('ispostselect'):
+            def execute(instance, row, isnew, ispostselect=None, **flags):
+                if isnew or ispostselect:
                     if self._should_log_debug:
                         self.logger.debug("populating %s with %s/%s" % (mapperutil.attribute_str(instance, self.key), row.__class__.__name__, self.columns[0].key))
                     instance.__dict__[self.key] = row[self.columns[0]]
@@ -48,8 +48,8 @@ class ColumnLoader(LoaderStrategy):
                 return (None, None)
             
             if hosted_mapper.polymorphic_fetch == 'deferred':
-                def execute(instance, row, flags):
-                    if flags['isnew']:
+                def execute(instance, row, isnew, **flags):
+                    if isnew:
                         sessionlib.attribute_manager.init_instance_attribute(instance, self.key, False, callable_=self._get_deferred_loader(instance, mapper, needs_tables))
                 self.logger.debug("Returning deferred column fetcher for %s %s" % (mapper, self.key))
                 return (execute, None)
@@ -96,15 +96,15 @@ class DeferredColumnLoader(LoaderStrategy):
     
     def create_row_processor(self, selectcontext, mapper, row):
         if not self.is_default or len(selectcontext.options):
-            def execute(instance, row, flags):
-                if flags['isnew']:
+            def execute(instance, row, isnew, **flags):
+                if isnew:
                     if self._should_log_debug:
                         self.logger.debug("set deferred callable on %s" % mapperutil.attribute_str(instance, self.key))
                     sessionlib.attribute_manager.init_instance_attribute(instance, self.key, False, callable_=self.setup_loader(instance))
             return (execute, None)
         else:
-            def execute(instance, row, flags):
-                if flags['isnew']:
+            def execute(instance, row, isnew, **flags):
+                if isnew:
                     if self._should_log_debug:
                         self.logger.debug("set deferred callable on %s" % mapperutil.attribute_str(instance, self.key))
                     sessionlib.attribute_manager.reset_instance_attribute(instance, self.key)
@@ -205,7 +205,7 @@ class NoLoader(AbstractRelationLoader):
 
     def create_row_processor(self, selectcontext, mapper, row):
         if not self.is_default or len(selectcontext.options):
-            def execute(instance, row, identitykey, isnew):
+            def execute(instance, row, isnew, **flags):
                 if isnew:
                     if self._should_log_debug:
                         self.logger.debug("set instance-level no loader on %s" % mapperutil.attribute_str(instance, self.key))
@@ -296,8 +296,8 @@ class LazyLoader(AbstractRelationLoader):
 
     def create_row_processor(self, selectcontext, mapper, row):
         if not self.is_default or len(selectcontext.options):
-            def execute(instance, row, flags):
-                if flags['isnew']:
+            def execute(instance, row, isnew, **flags):
+                if isnew:
                     if self._should_log_debug:
                         self.logger.debug("set instance-level lazy loader on %s" % mapperutil.attribute_str(instance, self.key))
                     # we are not the primary manager for this attribute on this class - set up a per-instance lazyloader,
@@ -305,8 +305,8 @@ class LazyLoader(AbstractRelationLoader):
                     self._init_instance_attribute(instance, callable_=self.setup_loader(instance, selectcontext.options))
             return (execute, None)
         else:
-            def execute(instance, row, flags):
-                if flags['isnew']:
+            def execute(instance, row, isnew, **flags):
+                if isnew:
                     if self._should_log_debug:
                         self.logger.debug("set class-level lazy loader on %s" % mapperutil.attribute_str(instance, self.key))
                     # we are the primary manager for this attribute on this class - reset its per-instance attribute state, 
@@ -621,7 +621,7 @@ class EagerLoader(AbstractRelationLoader):
     def create_row_processor(self, selectcontext, mapper, row):
         row_decorator = self._create_row_decorator(selectcontext, row)
         if row_decorator is not None:
-            def execute(instance, row, flags):
+            def execute(instance, row, isnew, **flags):
                 if self in selectcontext.recursion_stack:
                     return
                 decorated_row = row_decorator(row)
@@ -633,7 +633,7 @@ class EagerLoader(AbstractRelationLoader):
                     if not self.uselist:
                         if self._should_log_debug:
                             self.logger.debug("eagerload scalar instance on %s" % mapperutil.attribute_str(instance, self.key))
-                        if flags['isnew']:
+                        if isnew:
                             # set a scalar object instance directly on the parent object, 
                             # bypassing InstrumentedAttribute event handlers.
                             instance.__dict__[self.key] = self.mapper._instance(selectcontext, decorated_row, None)
@@ -642,7 +642,7 @@ class EagerLoader(AbstractRelationLoader):
                             # so that we further descend into properties
                             self.mapper._instance(selectcontext, decorated_row, None)
                     else:
-                        if flags['isnew']:
+                        if isnew:
                             if self._should_log_debug:
                                 self.logger.debug("initialize UniqueAppender on %s" % mapperutil.attribute_str(instance, self.key))
 
index ce642c1588f6f36892e70ec7be94490baa7a85ad..55007c4fa7720a4010e7c778e8b31bbb71b08f49 100644 (file)
@@ -12,23 +12,16 @@ __all__ = [ 'TypeEngine', 'TypeDecorator', 'NullTypeEngine',
             ]
 
 from sqlalchemy import util, exceptions
-import inspect, weakref
+import inspect
 try:
     import cPickle as pickle
 except:
     import pickle
 
-_impl_cache = weakref.WeakKeyDictionary()
-
 class AbstractType(object):
-    def _get_impl_dict(self):
-        try:
-            return _impl_cache[self]
-        except KeyError:
-            return _impl_cache.setdefault(self, {})
-
-    impl_dict = property(_get_impl_dict)
-
+    def __init__(self, *args, **kwargs):
+        pass
+        
     def copy_value(self, value):
         return value
 
@@ -50,14 +43,14 @@ class AbstractType(object):
         return "%s(%s)" % (self.__class__.__name__, ",".join(["%s=%s" % (k, getattr(self, k)) for k in inspect.getargspec(self.__init__)[0][1:]]))
 
 class TypeEngine(AbstractType):
-    def __init__(self, *args, **params):
-        pass
-
     def dialect_impl(self, dialect):
         try:
-            return self.impl_dict[dialect]
+            return self._impl_dict[dialect]
+        except AttributeError:
+            self._impl_dict = {}
+            return self._impl_dict.setdefault(dialect, dialect.type_descriptor(self))
         except KeyError:
-            return self.impl_dict.setdefault(dialect, dialect.type_descriptor(self))
+            return self._impl_dict.setdefault(dialect, dialect.type_descriptor(self))
 
     def get_col_spec(self):
         raise NotImplementedError()
@@ -87,15 +80,20 @@ class TypeDecorator(AbstractType):
 
     def dialect_impl(self, dialect):
         try:
-            return self.impl_dict[dialect]
-        except:
-            typedesc = dialect.type_descriptor(self.impl)
-            tt = self.copy()
-            if not isinstance(tt, self.__class__):
-                raise exceptions.AssertionError("Type object %s does not properly implement the copy() method, it must return an object of type %s" % (self, self.__class__))
-            tt.impl = typedesc
-            self.impl_dict[dialect] = tt
-            return tt
+            return self._impl_dict[dialect]
+        except AttributeError:
+            self._impl_dict = {}
+            return self._impl_dict.setdefault(dialect, self._create_dialect_impl(dialect))
+        except KeyError:
+            return self._impl_dict.setdefault(dialect, self._create_dialect_impl(dialect))
+
+    def _create_dialect_impl(self, dialect):
+        typedesc = dialect.type_descriptor(self.impl)
+        tt = self.copy()
+        if not isinstance(tt, self.__class__):
+            raise exceptions.AssertionError("Type object %s does not properly implement the copy() method, it must return an object of type %s" % (self, self.__class__))
+        tt.impl = typedesc
+        return tt
 
     def __getattr__(self, key):
         """Proxy all other undefined accessors to the underlying implementation."""
index 9f12a4d1a9b83e008531c8ee43778304551c6ed9..2d8879d13ff90fa04612386b275f4ae0b229616e 100644 (file)
@@ -574,7 +574,7 @@ class MapperTest(MapperSuperTest):
     def testextensionoptions(self):
         sess  = create_session()
         class ext1(MapperExtension):
-            def populate_instance(self, mapper, selectcontext, row, instance, flags):
+            def populate_instance(self, mapper, selectcontext, row, instance, **flags):
                 """test options at the Mapper._instance level"""
                 instance.TEST = "hello world"
                 return EXT_PASS
@@ -585,7 +585,7 @@ class MapperTest(MapperSuperTest):
             def select_by(self, *args, **kwargs):
                 """test options at the Query level"""
                 return "HI"
-            def populate_instance(self, mapper, selectcontext, row, instance, flags):
+            def populate_instance(self, mapper, selectcontext, row, instance, **flags):
                 """test options at the Mapper._instance level"""
                 instance.TEST_2 = "also hello world"
                 return EXT_PASS
index 3e865a041469badc571e44100547101eaf922129..2869fc6f7db8cf7421666072788880571c565d48 100644 (file)
@@ -30,14 +30,14 @@ class LoadTest(AssertMixin):
         l = []
         for x in range(1,NUM/DIVISOR):
             l.append({'item_id':x, 'value':'this is item #%d' % x})
-        print l
+        #print l
         items.insert().execute(*l)
         for x in range(1, NUM/DIVISOR):
             l = []
             for y in range(1, NUM/(NUM/DIVISOR)):
                 z = ((x-1) * NUM/(NUM/DIVISOR)) + y
                 l.append({'sub_id':z,'value':'this is iteim #%d' % z, 'parent_id':x})
-            print l
+            #print l
             subitems.insert().execute(*l)    
     def testload(self):
         class Item(object):pass