diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-11-30 07:00:18 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-11-30 07:00:18 -0500 |
commit | e25db2ddcb8584a3422f7f33a6e1dc27b7824e27 (patch) | |
tree | 9e4c78d3bc9b7e8841df19c474b51e324f99cd09 | |
parent | 61eb3e5f2d1bc9c6997073dca8db888b3d6eb410 (diff) | |
parent | 7abb46ad6a6e511bc10646dd3f30cb93eb44c8d8 (diff) | |
download | python-coveragepy-git-e25db2ddcb8584a3422f7f33a6e1dc27b7824e27.tar.gz |
Merge stuff I almost lost!
-rw-r--r-- | TODO.txt | 6 | ||||
-rw-r--r-- | allcoverage.cmd | 44 | ||||
-rw-r--r-- | coverage/codeunit.py | 1 | ||||
-rw-r--r-- | coverage/collector.py | 5 | ||||
-rw-r--r-- | coverage/control.py | 10 | ||||
-rw-r--r-- | test/coverage_coverage.py | 107 | ||||
-rw-r--r-- | test/coveragetest.py | 13 | ||||
-rw-r--r-- | test/test_api.py | 3 |
8 files changed, 141 insertions, 48 deletions
@@ -64,7 +64,9 @@ x Tricky swapping of collector like figleaf, pycov, et al. (Don't need to do - 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
@@ -97,6 +99,7 @@ x Why can't you specify execute (-x) and report (-r) in the same invocation? - 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.
@@ -123,6 +126,7 @@ x Why can't you specify execute (-x) and report (-r) in the same invocation? - 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.
diff --git a/allcoverage.cmd b/allcoverage.cmd new file mode 100644 index 00000000..5da7e15f --- /dev/null +++ b/allcoverage.cmd @@ -0,0 +1,44 @@ +@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
diff --git a/coverage/codeunit.py b/coverage/codeunit.py index e3107052..6d156da7 100644 --- a/coverage/codeunit.py +++ b/coverage/codeunit.py @@ -34,6 +34,7 @@ def code_unit_factory(morfs, file_locator, omit_prefixes=None): 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: diff --git a/coverage/collector.py b/coverage/collector.py index 5bbd02e0..6ea419ee 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -148,6 +148,9 @@ class Collector(object): # 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__ @@ -196,6 +199,7 @@ class Collector(object): 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 @@ -204,6 +208,7 @@ class Collector(object): def stop(self): """Stop collecting trace information.""" + #print >>sys.stderr, "Stopping: %r" % self._collectors assert self._collectors assert self._collectors[-1] is self diff --git a/coverage/control.py b/coverage/control.py index 674bb15e..7efc3492 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -1,6 +1,6 @@ """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 @@ -56,7 +56,8 @@ class coverage(object): self.cover_pylib = cover_pylib self.auto_data = auto_data - + self.atexit_registered = False + self.exclude_re = "" self.exclude_list = [] @@ -168,8 +169,9 @@ class coverage(object): 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): diff --git a/test/coverage_coverage.py b/test/coverage_coverage.py index e1e7674f..a1cb13fc 100644 --- a/test/coverage_coverage.py +++ b/test/coverage_coverage.py @@ -1,45 +1,78 @@ -"""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) - -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() - -# 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. -import nose -nose.run(sys.argv[1:]) +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, 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) + + # 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() + +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'") diff --git a/test/coveragetest.py b/test/coveragetest.py index 1fb04721..073dc39f 100644 --- a/test/coveragetest.py +++ b/test/coveragetest.py @@ -168,12 +168,13 @@ class CoverageTest(TestCase): 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] diff --git a/test/test_api.py b/test/test_api.py index 932606fd..7308cdc6 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -8,6 +8,9 @@ from coverage.backward import StringIO 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.""" |