[py-svn] commit/pytest: hpk42: half the overhead for calling a test function by introducing some caching

Bitbucket commits-noreply at bitbucket.org
Mon Mar 7 18:29:02 CET 2011


1 new changeset in pytest:

http://bitbucket.org/hpk42/pytest/changeset/2385ebbf4532/
changeset:   r2179:2385ebbf4532
user:        hpk42
date:        2011-03-07 18:28:45
summary:     half the overhead for calling a test function by introducing some caching
affected #:  7 files (996 bytes)

--- a/CHANGELOG	Mon Mar 07 13:17:07 2011 +0100
+++ b/CHANGELOG	Mon Mar 07 18:28:45 2011 +0100
@@ -1,6 +1,8 @@
 Changes between 2.0.1 and 2.0.2
 ----------------------------------------------
 
+- tackle issue32 - half the overhead for running test functions 
+
 - fix issue30 - extended xfail/skipif handling and improved reporting.
   If you have a syntax error in your skip/xfail
   expressions you now get nice error reports.


--- a/_pytest/core.py	Mon Mar 07 13:17:07 2011 +0100
+++ b/_pytest/core.py	Mon Mar 07 18:28:45 2011 +0100
@@ -60,6 +60,7 @@
 class PluginManager(object):
     def __init__(self, load=False):
         self._name2plugin = {}
+        self._listattrcache = {}
         self._plugins = []
         self._hints = []
         self.trace = TagTracer().get("pluginmanage")
@@ -272,6 +273,11 @@
     def listattr(self, attrname, plugins=None):
         if plugins is None:
             plugins = self._plugins
+        key = (attrname,) + tuple(plugins)
+        try:
+            return list(self._listattrcache[key])
+        except KeyError:
+            pass
         l = []
         last = []
         for plugin in plugins:
@@ -286,6 +292,7 @@
             except AttributeError:
                 continue
         l.extend(last)
+        self._listattrcache[key] = list(l)
         return l
 
     def call_plugin(self, plugin, methname, kwargs):
@@ -340,14 +347,20 @@
         return kwargs
 
 def varnames(func):
+    try:
+        return func._varnames
+    except AttributeError:
+        pass
     if not inspect.isfunction(func) and not inspect.ismethod(func):
         func = getattr(func, '__call__', func)
     ismethod = inspect.ismethod(func)
     rawcode = py.code.getrawcode(func)
     try:
-        return rawcode.co_varnames[ismethod:rawcode.co_argcount]
+        x = rawcode.co_varnames[ismethod:rawcode.co_argcount]
     except AttributeError:
-        return ()
+        x = ()
+    py.builtin._getfuncdict(func)['_varnames'] = x
+    return x
 
 class HookRelay:
     def __init__(self, hookspecs, pm, prefix="pytest_"):


--- a/_pytest/helpconfig.py	Mon Mar 07 13:17:07 2011 +0100
+++ b/_pytest/helpconfig.py	Mon Mar 07 18:28:45 2011 +0100
@@ -2,6 +2,7 @@
 import py
 import pytest
 import inspect, sys
+from _pytest.core import varnames
 
 def pytest_addoption(parser):
     group = parser.getgroup('debugconfig')
@@ -135,12 +136,11 @@
                 fail = True
         else:
             #print "checking", method
-            method_args = getargs(method)
-            #print "method_args", method_args
+            method_args = list(varnames(method))
             if '__multicall__' in method_args:
                 method_args.remove('__multicall__')
             hook = hooks[name]
-            hookargs = getargs(hook)
+            hookargs = varnames(hook)
             for arg in method_args:
                 if arg not in hookargs:
                     Print("argument %r not available"  %(arg, ))
@@ -162,11 +162,6 @@
     return name == "pytest_plugins" or \
            name.startswith("pytest_funcarg__")
 
-def getargs(func):
-    args = inspect.getargs(py.code.getrawcode(func))[0]
-    startindex = inspect.ismethod(func) and 1 or 0
-    return args[startindex:]
-
 def collectattr(obj):
     methods = {}
     for apiname in dir(obj):


--- a/_pytest/main.py	Mon Mar 07 13:17:07 2011 +0100
+++ b/_pytest/main.py	Mon Mar 07 18:28:45 2011 +0100
@@ -326,7 +326,13 @@
             return self._location
         except AttributeError:
             location = self.reportinfo()
-            fspath = self.session.fspath.bestrelpath(location[0])
+            # bestrelpath is a quite slow function
+            cache = self.config.__dict__.setdefault("_bestrelpathcache", {})
+            try:
+                fspath = cache[location[0]]
+            except KeyError:
+                fspath = self.session.fspath.bestrelpath(location[0])
+                cache[location[0]] = fspath
             location = (fspath, location[1], str(location[2]))
             self._location = location
             return location


--- a/pytest.py	Mon Mar 07 13:17:07 2011 +0100
+++ b/pytest.py	Mon Mar 07 18:28:45 2011 +0100
@@ -1,7 +1,7 @@
 """
 unit and functional testing with Python.
 """
-__version__ = '2.0.2.dev6'
+__version__ = '2.0.2.dev7'
 __all__ = ['main']
 
 from _pytest.core import main, UsageError, _preloadplugins


--- a/setup.py	Mon Mar 07 13:17:07 2011 +0100
+++ b/setup.py	Mon Mar 07 18:28:45 2011 +0100
@@ -22,7 +22,7 @@
         name='pytest',
         description='py.test: simple powerful testing with Python',
         long_description = long_description,
-        version='2.0.2.dev6',
+        version='2.0.2.dev7',
         url='http://pytest.org',
         license='MIT license',
         platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],


--- a/testing/test_core.py	Mon Mar 07 13:17:07 2011 +0100
+++ b/testing/test_core.py	Mon Mar 07 18:28:45 2011 +0100
@@ -433,6 +433,9 @@
         pluginmanager.register(p3)
         methods = pluginmanager.listattr('m')
         assert methods == [p2.m, p3.m, p1.m]
+        # listattr keeps a cache and deleting
+        # a function attribute requires clearing it
+        pluginmanager._listattrcache.clear()
         del P1.m.__dict__['tryfirst']
 
         pytest.mark.trylast(getattr(P2.m, 'im_func', P2.m))

Repository URL: https://bitbucket.org/hpk42/pytest/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.



More information about the pytest-commit mailing list