encodings.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  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. """Imposter encodings module that installs a coverage-style tracer.
  4. This is NOT the encodings module; it is an imposter that sets up tracing
  5. instrumentation and then replaces itself with the real encodings module.
  6. If the directory that holds this file is placed first in the PYTHONPATH when
  7. using "coverage" to run Python's tests, then this file will become the very
  8. first module imported by the internals of Python 3. It installs a
  9. coverage.py-compatible trace function that can watch Standard Library modules
  10. execute from the very earliest stages of Python's own boot process. This fixes
  11. a problem with coverage.py - that it starts too late to trace the coverage of
  12. many of the most fundamental modules in the Standard Library.
  13. """
  14. import sys
  15. class FullCoverageTracer(object):
  16. def __init__(self):
  17. # `traces` is a list of trace events. Frames are tricky: the same
  18. # frame object is used for a whole scope, with new line numbers
  19. # written into it. So in one scope, all the frame objects are the
  20. # same object, and will eventually all will point to the last line
  21. # executed. So we keep the line numbers alongside the frames.
  22. # The list looks like:
  23. #
  24. # traces = [
  25. # ((frame, event, arg), lineno), ...
  26. # ]
  27. #
  28. self.traces = []
  29. def fullcoverage_trace(self, *args):
  30. frame, event, arg = args
  31. self.traces.append((args, frame.f_lineno))
  32. return self.fullcoverage_trace
  33. sys.settrace(FullCoverageTracer().fullcoverage_trace)
  34. # In coverage/files.py is actual_filename(), which uses glob.glob. I don't
  35. # understand why, but that use of glob borks everything if fullcoverage is in
  36. # effect. So here we make an ugly hail-mary pass to switch off glob.glob over
  37. # there. This means when using fullcoverage, Windows path names will not be
  38. # their actual case.
  39. #sys.fullcoverage = True
  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. parentdir = max(filter(__file__.startswith, sys.path), key=len)
  46. sys.path.remove(parentdir)
  47. del sys.modules['encodings']
  48. import encodings