Skip to content

Commit

Permalink
Built-in support for using aspectlib to debug execution.
Browse files Browse the repository at this point in the history
  • Loading branch information
nedbat committed Aug 6, 2016
1 parent 90ecf09 commit a23ab8e
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 14 deletions.
4 changes: 4 additions & 0 deletions coverage/__init__.py
Expand Up @@ -12,13 +12,17 @@

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

# 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.
Expand Down
47 changes: 47 additions & 0 deletions coverage/debug.py
Expand Up @@ -5,6 +5,7 @@

import inspect
import os
import re
import sys

from coverage.misc import isolate_module
Expand Down Expand Up @@ -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)
14 changes: 0 additions & 14 deletions lab/aspectlib.diff

This file was deleted.

0 comments on commit a23ab8e

Please sign in to comment.