diff --git a/coverage/__init__.py b/coverage/__init__.py index 192239926..d9a139366 100644 --- a/coverage/__init__.py +++ b/coverage/__init__.py @@ -12,6 +12,7 @@ from coverage.control import Coverage, process_startup from coverage.data import CoverageData +from coverage.debug import enable_aspectlib_maybe from coverage.misc import CoverageException from coverage.plugin import CoveragePlugin, FileTracer, FileReporter from coverage.pytracer import PyTracer @@ -19,6 +20,9 @@ # Backward compatibility. coverage = Coverage +# Possibly enable aspectlib to debug our execution. +enable_aspectlib_maybe() + # On Windows, we encode and decode deep enough that something goes wrong and # the encodings.utf_8 module is loaded and then unloaded, I don't know why. # Adding a reference here prevents it from being unloaded. Yuk. diff --git a/coverage/debug.py b/coverage/debug.py index 8ed664ce2..96e579209 100644 --- a/coverage/debug.py +++ b/coverage/debug.py @@ -5,6 +5,7 @@ import inspect import os +import re import sys from coverage.misc import isolate_module @@ -112,3 +113,49 @@ def log(msg, stack=False): # pragma: debugging f.write("{pid}: {msg}\n".format(pid=os.getpid(), msg=msg)) if stack: dump_stack_frames(out=f) + + +def enable_aspectlib_maybe(): + """For debugging, we can use aspectlib to trace execution. + + Define COVERAGE_ASPECTLIB to enable and configure aspectlib to trace + execution:: + + COVERAGE_ASPECTLIB=covaspect.txt:coverage.Coverage:coverage.data.CoverageData program... + + This will trace all the public methods on Coverage and CoverageData, + writing the information to covaspect.txt. + + """ + aspects = os.environ.get("COVERAGE_ASPECTLIB", "") + if not aspects: + return + + import aspectlib # pylint: disable=import-error + import aspectlib.debug # pylint: disable=import-error + + class AspectlibOutputFile(object): + """A file-like object that includes pid and cwd information.""" + def __init__(self, outfile): + self.outfile = outfile + self.cwd = None + + def write(self, text): + """Just like file.write""" + cwd = os.getcwd() + if cwd != self.cwd: + self._write("cwd is now {0!r}\n".format(cwd)) + self.cwd = cwd + self._write(text) + + def _write(self, text): + """The raw text-writer, so that we can use it ourselves.""" + self.outfile.write("{0:5d}: {1}".format(os.getpid(), text)) + + aspects = aspects.split(':') + aspects_file = AspectlibOutputFile(open(aspects[0], "a")) + aspect_log = aspectlib.debug.log(print_to=aspects_file, use_logging=False) + aspects = aspects[1:] + public_methods = re.compile(r'^(__init__|[a-zA-Z].*)$') + for aspect in aspects: + aspectlib.weave(aspect, aspect_log, methods=public_methods) diff --git a/lab/aspectlib.diff b/lab/aspectlib.diff deleted file mode 100644 index 5e4ea6ec8..000000000 --- a/lab/aspectlib.diff +++ /dev/null @@ -1,14 +0,0 @@ -diff -r 44af4372756b coverage/__init__.py ---- a/coverage/__init__.py Sat Nov 21 14:26:51 2015 -0500 -+++ b/coverage/__init__.py Sun Nov 22 08:18:04 2015 -0500 -@@ -18,6 +18,10 @@ - # Backward compatibility. - coverage = Coverage - -+if 1: -+ import aspectlib, aspectlib.debug, sys -+ aspectlib.weave(Coverage, aspectlib.debug.log(print_to=sys.stdout), methods=aspectlib.PUBLIC_METHODS) -+ - # On Windows, we encode and decode deep enough that something goes wrong and - # the encodings.utf_8 module is loaded and then unloaded, I don't know why. - # Adding a reference here prevents it from being unloaded. Yuk.