Commits

Ned Batchelder committed 1d3c40b Merge

Merge stuff I almost lost!

  • Participants
  • Parent commits e778c30, 72638a9

Comments (0)

Files changed (8)

 - Track callers of functions (ala std module trace)
 - Method/Class/Module coverage reporting.
 - .coverage files that can be kept separate, rather than accumulated.
-    
+- test/coverage map: http://rbtcollins.wordpress.com/2009/09/16/back-from-hiatus/
+    - Similar to figleaf's sections.
+
 
 * Convenience
 
     - Some way to focus in on red and yellow
         - Show only lines near highlights?
         - Jump to next highlight?
+    - Cookie for changes to pyfile.html state.
     + Clickable column headers on the index page.
     + Syntax coloring in HTML report.
     + Dynamic effects in HTML report.
         - Double function decorators: all decorator lines count as executable code.
     - Document the .coverage file format.
     + HTML reporting.
+        - Much more detail about what's in the report.
     - References between pages are off:
         - They have <em> tags around them.
         - They use #anchors that don't survive the px->html conversion.

File allcoverage.cmd

+@echo off
+make --quiet testdata
+
+call \ned\bin\switchpy 23
+python setup.py -q develop
+set COVERAGE_TEST_TRACER=c
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+del coverage\tracer.pyd
+set COVERAGE_TEST_TRACER=py
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+call \ned\bin\switchpy 24
+python setup.py -q develop
+set COVERAGE_TEST_TRACER=c
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+del coverage\tracer.pyd
+set COVERAGE_TEST_TRACER=py
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+call \ned\bin\switchpy 25
+python setup.py -q develop
+set COVERAGE_TEST_TRACER=c
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+del coverage\tracer.pyd
+set COVERAGE_TEST_TRACER=py
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+call \ned\bin\switchpy 26
+python setup.py -q develop
+set COVERAGE_TEST_TRACER=c
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+del coverage\tracer.pyd
+set COVERAGE_TEST_TRACER=py
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+call \ned\bin\switchpy 31
+python setup.py -q install
+set COVERAGE_TEST_TRACER=c
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+del \python31\lib\site-packages\coverage\tracer.pyd
+set COVERAGE_TEST_TRACER=py
+python test\coverage_coverage.py run %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+python test\coverage_coverage.py report

File coverage/codeunit.py

     code_units = [CodeUnit(morf, file_locator) for morf in morfs]
     
     if omit_prefixes:
+        assert not isinstance(omit_prefixes, string_class) # common mistake
         prefixes = [file_locator.abs_file(p) for p in omit_prefixes]
         filtered = []
         for cu in code_units:

File coverage/collector.py

             # trace function.
             self._trace_class = Tracer or PyTracer
 
+    def __repr__(self):
+        return "<Collector at 0x%x>" % id(self)
+
     def tracer_name(self):
         """Return the class name of the tracer we're using."""
         return self._trace_class.__name__
         if self._collectors:
             self._collectors[-1].pause()
         self._collectors.append(self)
+        #print >>sys.stderr, "Started: %r" % self._collectors
         # Install the tracer on this thread.
         self._start_tracer()
         # Install our installation tracer in threading, to jump start other
 
     def stop(self):
         """Stop collecting trace information."""
+        #print >>sys.stderr, "Stopping: %r" % self._collectors
         assert self._collectors
         assert self._collectors[-1] is self
 

File coverage/control.py

 """Core control stuff for Coverage."""
 
-import os, socket
+import atexit, os, socket
 
 from coverage.annotate import AnnotateReporter
 from coverage.backward import string_class          # pylint: disable-msg=W0622
         
         self.cover_pylib = cover_pylib
         self.auto_data = auto_data
-        
+        self.atexit_registered = False
+
         self.exclude_re = ""
         self.exclude_list = []
         
         if self.auto_data:
             self.load()
             # Save coverage data when Python exits.
-            import atexit
-            atexit.register(self.save)
+            if not self.atexit_registered:
+                atexit.register(self.save)
+                self.atexit_registered = True
         self.collector.start()
         
     def stop(self):

File test/coverage_coverage.py

-"""Coverage-test Coverage itself."""
+"""Coverage-test Coverage.py itself."""
 
-import coverage
 import os, shutil, sys
+import nose
 
 HTML_DIR = "htmlcov"
 
-if os.path.exists(HTML_DIR):
-    shutil.rmtree(HTML_DIR)
+def run_tests_with_coverage():
+    import coverage
+    
+    tracer = os.environ.get('COVERAGE_TEST_TRACER', 'c')
+    version = "%s%s" % sys.version_info[:2]
+    suffix = ".%s_%s" % (version, tracer)
 
-cov = coverage.coverage(branch=True)
-# Cheap trick: the coverage code itself is excluded from measurement, but if
-# we clobber the cover_prefix in the coverage object, we can defeat the
-# self-detection.
-cov.cover_prefix = "Please measure coverage.py!"
-cov.erase()
-cov.start()
+    cov = coverage.coverage(branch=True, data_suffix=suffix)
+    # Cheap trick: the coverage code itself is excluded from measurement, but
+    # if we clobber the cover_prefix in the coverage object, we can defeat the
+    # self-detection.
+    cov.cover_prefix = "Please measure coverage.py!"
+    cov.erase()
+    cov.start()
+    
+    # Re-import coverage to get it coverage tested!  I don't understand all the
+    # mechanics here, but if I don't carry over the imported modules (in
+    # covmods), then things go haywire (os == None, eventually).
+    covmods = {}
+    covdir = os.path.split(coverage.__file__)[0]
+    # We have to make a list since we'll be deleting in the loop.
+    modules = list(sys.modules.items())
+    for name, mod in modules:
+        if name.startswith('coverage'):
+            if hasattr(mod, '__file__') and mod.__file__.startswith(covdir):
+                    covmods[name] = mod
+                    del sys.modules[name]
+    import coverage     # don't warn about re-import: pylint: disable-msg=W0404
+    sys.modules.update(covmods)
 
-# Re-import coverage to get it coverage tested!  I don't understand all the
-# mechanics here, but if I don't carry over the imported modules (in covmods),
-# then things go haywire (os == None eventually).
-covmods = {}
-covdir = os.path.split(coverage.__file__)
-for name, mod in sys.modules.items():
-    if name.startswith('coverage'):
-        if hasattr(mod, '__file__') and mod.__file__.startswith(covdir):
-            covmods[name] = mod
-            del sys.modules[name]
-import coverage     # don't warn about re-import: pylint: disable-msg=W0404
-sys.modules.update(covmods)
+    # Run nosetests, with the arguments from our command line.
+    print(":: Running nosetests %s" % " ".join(sys.argv[1:]))
+    nose.run()
+    
+    cov.stop()
+    print(":: Saving .coverage%s" % suffix)
+    cov.save()
 
-# Run nosetests, with the arguments from our command line.
-import nose
-nose.run(sys.argv[1:])
+def report_on_combined_files():
+    
+    if os.path.exists(HTML_DIR):
+        shutil.rmtree(HTML_DIR)
 
-cov.stop()
-cov.save()
+    print(":: Writing HTML report to %s/index.html" % HTML_DIR)
+    import coverage
+    cov = coverage.coverage()
+    cov.combine()
+    cov.save()
+    cov.clear_exclude()
+    cov.exclude("#pragma: no cover")
+    cov.exclude("def __repr__")
+    cov.exclude("if __name__ == .__main__.:")
+    cov.exclude("raise AssertionError")
+    
+    cov.html_report(directory=HTML_DIR, ignore_errors=True, omit_prefixes=["mock"])
 
-cov.clear_exclude()
-cov.exclude("#pragma: no cover")
-cov.exclude("def __repr__")
-cov.exclude("if __name__ == .__main__.:")
-cov.exclude("raise AssertionError")
 
-cov.html_report(directory=HTML_DIR, ignore_errors=True)
+try:
+    cmd = sys.argv[1]
+except IndexError:
+    cmd = ''
+    
+if cmd == 'run':
+    # Ugly hack: nose.run reads sys.argv directly, so here I delete my command
+    # argument so that sys.argv is left as just nose arguments.
+    del sys.argv[1]
+    run_tests_with_coverage()
+elif cmd == 'report':
+    report_on_combined_files()
+else:
+    print("Need 'run' or 'report'")

File test/coveragetest.py

             cov.exclude(exc)
         cov.start()
 
-        # Import the python file, executing it.
-        mod = self.import_module(modname)
-        
-        # Stop Coverage.
-        cov.stop()
-
+        try:
+            # Import the python file, executing it.
+            mod = self.import_module(modname)
+        finally:
+            # Stop Coverage.
+            cov.stop()
+    
         # Clean up our side effects
         del sys.modules[modname]
 

File test/test_api.py

 sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
 from coveragetest import CoverageTest
 
+# This file uses the singleton module interface.  Prevent it from writing
+# .coverage files at exit.
+coverage.use_cache(0)
 
 class ApiTest(CoverageTest):
     """Api-oriented tests for Coverage."""