diff options
-rw-r--r-- | .hgignore | 3 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | coverage/collector.py | 30 | ||||
-rw-r--r-- | test/coverage_coverage.py | 34 |
4 files changed, 67 insertions, 3 deletions
@@ -10,8 +10,9 @@ syntax: glob # Stuff in the root.
build
-dist
coverage.egg-info
+dist
+htmlcov
MANIFEST
setuptools-*.egg
@@ -8,8 +8,9 @@ TEST_ZIP = test/zipmods.zip clean: python test/test_farm.py clean -rm -rf build - -rm -rf dist -rm -rf coverage.egg-info + -rm -rf dist + -rm -rf htmlcov -rm -f *.pyd */*.pyd -rm -f *.pyc */*.pyc */*/*.pyc */*/*/*.pyc */*/*/*/*.pyc */*/*/*/*/*.pyc -rm -f *.pyo */*.pyo */*/*.pyo */*/*/*.pyo */*/*/*/*.pyo */*/*/*/*/*.pyo diff --git a/coverage/collector.py b/coverage/collector.py index efc41c3..f9bb317 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -56,7 +56,6 @@ except ImportError: """Stop this Tracer.""" sys.settrace(None) - class Collector: """Collects trace data. @@ -72,6 +71,11 @@ class Collector: """ + # The stack of active Collectors. Collectors are added here when started, + # and popped when stopped. Collectors on the stack are paused when not + # the top, and resumed when they become the top again. + _collectors = [] + def __init__(self, should_trace): """Create a collector. @@ -123,6 +127,9 @@ class Collector: def start(self): """Start collecting trace information.""" + if self._collectors: + self._collectors[-1]._pause() + self._collectors.append(self) # Install the tracer on this thread. self._start_tracer() # Install our installation tracer in threading, to jump start other @@ -131,10 +138,31 @@ class Collector: def stop(self): """Stop collecting trace information.""" + assert self._collectors + assert self._collectors[-1] is self + for tracer in self.tracers: tracer.stop() self.tracers = [] threading.settrace(None) + + # Remove this Collector from the stack, and resume the one underneath + # (if any). + self._collectors.pop() + if self._collectors: + self._collectors[-1]._resume() + + def _pause(self): + """Stop tracing, but be prepared to _resume.""" + for tracer in self.tracers: + tracer.stop() + threading.settrace(None) + + def _resume(self): + """Resume tracing after a _pause.""" + for tracer in self.tracers: + tracer.start() + threading.settrace(self._installation_trace) def data_points(self): """Return the (filename, lineno) pairs collected.""" diff --git a/test/coverage_coverage.py b/test/coverage_coverage.py new file mode 100644 index 0000000..f2a47f7 --- /dev/null +++ b/test/coverage_coverage.py @@ -0,0 +1,34 @@ +# Coverage-test Coverage itself. + +import coverage +import os, sys + +cov = coverage.coverage() +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 +sys.modules.update(covmods) + +# Run nosetests, with the arguments from our command line. +import nose +nose.run(sys.argv[1:]) + +cov.stop() +cov.save() # TODO: This is needed to get group_collected_data called. + +cov.exclude("#pragma: no cover") +cov.exclude("def __repr__") +cov.exclude("if __name__ == .__main__.:") + +cov.html_report(directory='htmlcov', ignore_errors=True) |