• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
3
4"""Imposter encodings module that installs a coverage-style tracer.
5
6This is NOT the encodings module; it is an imposter that sets up tracing
7instrumentation and then replaces itself with the real encodings module.
8
9If the directory that holds this file is placed first in the PYTHONPATH when
10using "coverage" to run Python's tests, then this file will become the very
11first module imported by the internals of Python 3.  It installs a
12coverage.py-compatible trace function that can watch Standard Library modules
13execute from the very earliest stages of Python's own boot process.  This fixes
14a problem with coverage.py - that it starts too late to trace the coverage of
15many of the most fundamental modules in the Standard Library.
16
17"""
18
19import sys
20
21class FullCoverageTracer(object):
22    def __init__(self):
23        # `traces` is a list of trace events.  Frames are tricky: the same
24        # frame object is used for a whole scope, with new line numbers
25        # written into it.  So in one scope, all the frame objects are the
26        # same object, and will eventually all will point to the last line
27        # executed.  So we keep the line numbers alongside the frames.
28        # The list looks like:
29        #
30        #   traces = [
31        #       ((frame, event, arg), lineno), ...
32        #       ]
33        #
34        self.traces = []
35
36    def fullcoverage_trace(self, *args):
37        frame, event, arg = args
38        self.traces.append((args, frame.f_lineno))
39        return self.fullcoverage_trace
40
41sys.settrace(FullCoverageTracer().fullcoverage_trace)
42
43# In coverage/files.py is actual_filename(), which uses glob.glob.  I don't
44# understand why, but that use of glob borks everything if fullcoverage is in
45# effect.  So here we make an ugly hail-mary pass to switch off glob.glob over
46# there.  This means when using fullcoverage, Windows path names will not be
47# their actual case.
48
49#sys.fullcoverage = True
50
51# Finally, remove our own directory from sys.path; remove ourselves from
52# sys.modules; and re-import "encodings", which will be the real package
53# this time.  Note that the delete from sys.modules dictionary has to
54# happen last, since all of the symbols in this module will become None
55# at that exact moment, including "sys".
56
57parentdir = max(filter(__file__.startswith, sys.path), key=len)
58sys.path.remove(parentdir)
59del sys.modules['encodings']
60import encodings
61