[Zope3-checkins] SVN: zope.testing/trunk/src/zope/testing/testrunner - added option to use the cProfiler of Python 2.5

Christian Zagrodnick cz at gocept.com
Wed May 30 03:17:47 EDT 2007


Log message for revision 75992:
  - added option to use the cProfiler of Python 2.5
  
  note, that this features is not quite as useful right now since the test runner
  fails horribly with Python 2.5. The only way to use it right now would be to
  compile the cProfiler manually for Python 2.4 (which is what I did).
  
  
  

Changed:
  A   zope.testing/trunk/src/zope/testing/testrunner-profiling-cprofiler.txt
  U   zope.testing/trunk/src/zope/testing/testrunner-profiling.txt
  U   zope.testing/trunk/src/zope/testing/testrunner.py

-=-
Added: zope.testing/trunk/src/zope/testing/testrunner-profiling-cprofiler.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-profiling-cprofiler.txt	                        (rev 0)
+++ zope.testing/trunk/src/zope/testing/testrunner-profiling-cprofiler.txt	2007-05-30 07:17:46 UTC (rev 75992)
@@ -0,0 +1,54 @@
+Profiling
+=========
+
+The testrunner includes the ability to profile the test execution with cProfile
+via the `--profile=cProfile` option::
+
+    >>> import os.path, sys
+    >>> directory_with_tests = os.path.join(this_directory, 'testrunner-ex')
+    >>> sys.path.append(directory_with_tests)
+
+    >>> defaults = [
+    ...     '--path', directory_with_tests,
+    ...     '--tests-pattern', '^sampletestsf?$',
+    ...     ]
+
+    >>> sys.argv = [testrunner_script, '--profile=cProfile']
+
+When the tests are run, we get profiling output::
+
+    >>> from zope.testing import testrunner
+    >>> testrunner.run(defaults)
+    Running unit tests:
+    ...
+    Running samplelayers.Layer1 tests:
+    ...
+    Running samplelayers.Layer11 tests:
+    ...
+    Total: ... tests, 0 failures, 0 errors
+    ...
+       ncalls  tottime  percall  cumtime  percall filename:lineno(function)...
+
+Profiling also works across layers::
+
+    >>> sys.argv = [testrunner_script, '-ssample2', '--profile=cProfile', 
+    ...             '--tests-pattern', 'sampletests_ntd']
+    >>> testrunner.run(defaults)
+    Running...
+      Tear down ... not supported...
+       ncalls  tottime  percall  cumtime  percall filename:lineno(function)...
+
+The testrunner creates temnporary files containing cProfiler profiler
+data::
+
+    >>> import glob
+    >>> files = list(glob.glob('tests_profile.*.prof'))
+    >>> files.sort()
+    >>> files
+    ['tests_profile.cZj2jt.prof', 'tests_profile.yHD-so.prof']
+
+It deletes these when rerun.  We'll delete these ourselves::
+
+    >>> import os
+    >>> for f in files:
+    ...     os.unlink(f)


Property changes on: zope.testing/trunk/src/zope/testing/testrunner-profiling-cprofiler.txt
___________________________________________________________________
Name: svn:keywords
   + Id Rev Date
Name: svn:eol-style
   + native

Modified: zope.testing/trunk/src/zope/testing/testrunner-profiling.txt
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner-profiling.txt	2007-05-29 17:35:29 UTC (rev 75991)
+++ zope.testing/trunk/src/zope/testing/testrunner-profiling.txt	2007-05-30 07:17:46 UTC (rev 75992)
@@ -13,7 +13,7 @@
     ...     '--tests-pattern', '^sampletestsf?$',
     ...     ]
 
-    >>> sys.argv = [testrunner_script, '--profile']
+    >>> sys.argv = [testrunner_script, '--profile=hotshot']
 
 When the tests are run, we get profiling output.
 
@@ -31,7 +31,7 @@
 
 Profiling also works across layers.
 
-    >>> sys.argv = [testrunner_script, '-ssample2', '--profile', 
+    >>> sys.argv = [testrunner_script, '-ssample2', '--profile=hotshot', 
     ...             '--tests-pattern', 'sampletests_ntd']
     >>> testrunner.run(defaults)
     Running...

Modified: zope.testing/trunk/src/zope/testing/testrunner.py
===================================================================
--- zope.testing/trunk/src/zope/testing/testrunner.py	2007-05-29 17:35:29 UTC (rev 75991)
+++ zope.testing/trunk/src/zope/testing/testrunner.py	2007-05-30 07:17:46 UTC (rev 75992)
@@ -35,14 +35,68 @@
 import types
 import unittest
 
+
+available_profilers = {}
+
+try:
+    import cProfile
+    import pstats
+except ImportError:
+    pass
+else:
+    class CProfiler(object):
+        """cProfiler"""
+        def __init__(self, filepath):
+            self.filepath = filepath
+            self.profiler = cProfile.Profile()
+            self.enable = self.profiler.enable
+            self.disable = self.profiler.disable
+
+        def finish(self):
+            self.profiler.dump_stats(self.filepath)
+
+        def loadStats(self, prof_glob):
+            stats = None
+            for file_name in glob.glob(prof_glob):
+                if stats is None:
+                    stats = pstats.Stats(file_name)
+                else:
+                    stats.add(file_name)
+            return stats
+
+    available_profilers['cProfile'] = CProfiler
+
 # some Linux distributions don't include the profiler, which hotshot uses
 try:
     import hotshot
     import hotshot.stats
 except ImportError:
-    hotshot = None
+    pass
+else:
+    class HotshotProfiler(object):
+        """hotshot interface"""
 
+        def __init__(self, filepath):
+            self.profiler = hotshot.Profile(filepath)
+            self.enable = self.profiler.start
+            self.disable = self.profiler.stop
 
+        def finish(self):
+            self.profiler.close()
+
+        def loadStats(self, prof_glob):
+            stats = None
+            for file_name in glob.glob(prof_glob):
+                loaded = hotshot.stats.load(file_name)
+                if stats is None:
+                    stats = loaded
+                else:
+                    stats.add(loaded)
+            return stats
+
+    available_profilers['hotshot'] = HotshotProfiler
+
+
 real_pdb_set_trace = pdb.set_trace
 
 # For some reason, the doctest module resets the trace callable randomly, thus
@@ -231,11 +285,6 @@
     # to make tests of the test runner work properly. :)
     pdb.set_trace = real_pdb_set_trace
 
-    if hotshot is None and options.profile:
-        print ('The Python you\'re using doesn\'t seem to have the profiler '
-               'so you can\'t use the --profile switch.')
-        sys.exit()
-
     if (options.profile
         and sys.version_info[:3] <= (2,4,1)
         and __debug__):
@@ -263,8 +312,8 @@
 
         # set up the output file
         oshandle, file_path = tempfile.mkstemp(prof_suffix, prof_prefix, '.')
-        prof = hotshot.Profile(file_path)
-        prof.start()
+        profiler = available_profilers[options.profile](file_path)
+        profiler.enable()
 
     try:
         try:
@@ -275,22 +324,15 @@
         if tracer:
             tracer.stop()
         if options.profile:
-            prof.stop()
-            prof.close()
+            profiler.disable()
+            profiler.finish()
             # We must explicitly close the handle mkstemp returned, else on
             # Windows this dies the next time around just above due to an
             # attempt to unlink a still-open file.
             os.close(oshandle)
 
     if options.profile and not options.resume_layer:
-        stats = None
-        for file_name in glob.glob(prof_glob):
-            loaded = hotshot.stats.load(file_name)
-            if stats is None:
-                stats = loaded
-            else:
-                stats.add(loaded)
-
+        stats = profiler.loadStats(prof_glob)
         stats.sort_stats('cumulative', 'calls')
         stats.print_stats(50)
 
@@ -638,8 +680,8 @@
         args.extend(options.original_testrunner_args[1:])
 
         # this is because of a bug in Python (http://www.python.org/sf/900092)
-        if (hotshot is not None and options.profile
-        and sys.version_info[:3] <= (2,4,1)):
+        if (options.profile == 'hotshot'
+            and sys.version_info[:3] <= (2,4,1)):
             args.insert(1, '-O')
 
         if sys.platform.startswith('win'):
@@ -1626,10 +1668,11 @@
 """)
 
 analysis.add_option(
-    '--profile', action="store_true", dest='profile',
+    '--profile', action="store", dest='profile', type="choice",
+    choices=available_profilers.keys(),
     help="""\
-Run the tests under hotshot and display the top 50 stats, sorted by
-cumulative time and number of calls.
+Run the tests under cProfiler or hotshot and display the top 50 stats, sorted
+by cumulative time and number of calls.
 """)
 
 def do_pychecker(*args):
@@ -2065,7 +2108,24 @@
                         ]),
                     )
                 )
+        try:
+            import cProfile
+        except ImportError:
+            pass
+        else:
+            suites.append(
+                doctest.DocFileSuite(
+                    'testrunner-profiling-cprofiler.txt',
+                    setUp=setUp, tearDown=tearDown,
+                    optionflags=doctest.ELLIPSIS+doctest.NORMALIZE_WHITESPACE,
+                    checker = renormalizing.RENormalizing([
+                        (re.compile(r'tests_profile[.]\S*[.]prof'),
+                         'tests_profile.*.prof'),
+                        ]),
+                    )
+                )
 
+
     if hasattr(sys, 'gettotalrefcount'):
         suites.append(
             doctest.DocFileSuite(



More information about the Zope3-Checkins mailing list