1"""Imposter encodings module that installs a coverage-style tracer. 2 3This is NOT the encodings module; it is an imposter that sets up tracing 4instrumentation and then replaces itself with the real encodings module. 5 6If the directory that holds this file is placed first in the PYTHONPATH when 7using "coverage" to run Python's tests, then this file will become the very 8first module imported by the internals of Python 3. It installs a 9coverage-compatible trace function that can watch Standard Library modules 10execute from the very earliest stages of Python's own boot process. This fixes 11a problem with coverage - that it starts too late to trace the coverage of many 12of the most fundamental modules in the Standard Library. 13 14""" 15 16import sys 17 18class FullCoverageTracer(object): 19 def __init__(self): 20 # `traces` is a list of trace events. Frames are tricky: the same 21 # frame object is used for a whole scope, with new line numbers 22 # written into it. So in one scope, all the frame objects are the 23 # same object, and will eventually all will point to the last line 24 # executed. So we keep the line numbers alongside the frames. 25 # The list looks like: 26 # 27 # traces = [ 28 # ((frame, event, arg), lineno), ... 29 # ] 30 # 31 self.traces = [] 32 33 def fullcoverage_trace(self, *args): 34 frame, event, arg = args 35 self.traces.append((args, frame.f_lineno)) 36 return self.fullcoverage_trace 37 38sys.settrace(FullCoverageTracer().fullcoverage_trace) 39 40# Finally, remove our own directory from sys.path; remove ourselves from 41# sys.modules; and re-import "encodings", which will be the real package 42# this time. Note that the delete from sys.modules dictionary has to 43# happen last, since all of the symbols in this module will become None 44# at that exact moment, including "sys". 45 46parentdirs = [ d for d in sys.path if __file__.startswith(d) ] 47parentdirs.sort(key=len) 48sys.path.remove(parentdirs[-1]) 49del sys.modules['encodings'] 50import encodings 51