Index: third_party/coverage-3.7.1/coverage/control.py |
diff --git a/third_party/coverage-3.6/coverage/control.py b/third_party/coverage-3.7.1/coverage/control.py |
similarity index 84% |
rename from third_party/coverage-3.6/coverage/control.py |
rename to third_party/coverage-3.7.1/coverage/control.py |
index afb61370c505d4a2e48a60bccd22231ce2815d74..f75a3dda5b1b479a45e52c50d1390b7d076a8b1f 100644 |
--- a/third_party/coverage-3.6/coverage/control.py |
+++ b/third_party/coverage-3.7.1/coverage/control.py |
@@ -3,11 +3,12 @@ |
import atexit, os, random, socket, sys |
from coverage.annotate import AnnotateReporter |
-from coverage.backward import string_class, iitems |
+from coverage.backward import string_class, iitems, sorted # pylint: disable=W0622 |
from coverage.codeunit import code_unit_factory, CodeUnit |
from coverage.collector import Collector |
from coverage.config import CoverageConfig |
from coverage.data import CoverageData |
+from coverage.debug import DebugControl |
from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher |
from coverage.files import PathAliases, find_python_files, prep_patterns |
from coverage.html import HtmlReporter |
@@ -17,6 +18,14 @@ from coverage.results import Analysis, Numbers |
from coverage.summary import SummaryReporter |
from coverage.xmlreport import XmlReporter |
+# Pypy has some unusual stuff in the "stdlib". Consider those locations |
+# when deciding where the stdlib is. |
+try: |
+ import _structseq # pylint: disable=F0401 |
+except ImportError: |
+ _structseq = None |
+ |
+ |
class coverage(object): |
"""Programmatic access to coverage.py. |
@@ -33,7 +42,8 @@ class coverage(object): |
""" |
def __init__(self, data_file=None, data_suffix=None, cover_pylib=None, |
auto_data=False, timid=None, branch=None, config_file=True, |
- source=None, omit=None, include=None): |
+ source=None, omit=None, include=None, debug=None, |
+ debug_file=None): |
""" |
`data_file` is the base name of the data file to use, defaulting to |
".coverage". `data_suffix` is appended (with a dot) to `data_file` to |
@@ -68,6 +78,10 @@ class coverage(object): |
`include` will be measured, files that match `omit` will not. Each |
will also accept a single string argument. |
+ `debug` is a list of strings indicating what debugging information is |
+ desired. `debug_file` is the file to write debug messages to, |
+ defaulting to stderr. |
+ |
""" |
from coverage import __version__ |
@@ -100,9 +114,12 @@ class coverage(object): |
self.config.from_args( |
data_file=data_file, cover_pylib=cover_pylib, timid=timid, |
branch=branch, parallel=bool_or_none(data_suffix), |
- source=source, omit=omit, include=include |
+ source=source, omit=omit, include=include, debug=debug, |
) |
+ # Create and configure the debugging controller. |
+ self.debug = DebugControl(self.config.debug, debug_file or sys.stderr) |
+ |
self.auto_data = auto_data |
# _exclude_re is a dict mapping exclusion list names to compiled |
@@ -147,7 +164,8 @@ class coverage(object): |
# started rather than wherever the process eventually chdir'd to. |
self.data = CoverageData( |
basename=self.config.data_file, |
- collector="coverage v%s" % __version__ |
+ collector="coverage v%s" % __version__, |
+ debug=self.debug, |
) |
# The dirs for files considered "installed with the interpreter". |
@@ -158,8 +176,8 @@ class coverage(object): |
# environments (virtualenv, for example), these modules may be |
# spread across a few locations. Look at all the candidate modules |
# we've imported, and take all the different ones. |
- for m in (atexit, os, random, socket): |
- if hasattr(m, "__file__"): |
+ for m in (atexit, os, random, socket, _structseq): |
+ if m is not None and hasattr(m, "__file__"): |
m_dir = self._canonical_dir(m) |
if m_dir not in self.pylib_dirs: |
self.pylib_dirs.append(m_dir) |
@@ -168,7 +186,7 @@ class coverage(object): |
# where we are. |
self.cover_dir = self._canonical_dir(__file__) |
- # The matchers for _should_trace, created when tracing starts. |
+ # The matchers for _should_trace. |
self.source_match = None |
self.pylib_match = self.cover_match = None |
self.include_match = self.omit_match = None |
@@ -201,26 +219,28 @@ class coverage(object): |
filename = filename[:-9] + ".py" |
return filename |
- def _should_trace(self, filename, frame): |
- """Decide whether to trace execution in `filename` |
+ def _should_trace_with_reason(self, filename, frame): |
+ """Decide whether to trace execution in `filename`, with a reason. |
This function is called from the trace function. As each new file name |
is encountered, this function determines whether it is traced or not. |
- Returns a canonicalized filename if it should be traced, False if it |
- should not. |
+ Returns a pair of values: the first indicates whether the file should |
+ be traced: it's a canonicalized filename if it should be traced, None |
+ if it should not. The second value is a string, the resason for the |
+ decision. |
""" |
if not filename: |
# Empty string is pretty useless |
- return False |
+ return None, "empty string isn't a filename" |
if filename.startswith('<'): |
# Lots of non-file execution is represented with artificial |
# filenames like "<string>", "<doctest readme.txt[0]>", or |
# "<exec_function>". Don't ever trace these executions, since we |
# can't do anything with the data later anyway. |
- return False |
+ return None, "not a real filename" |
self._check_for_packages() |
@@ -246,35 +266,41 @@ class coverage(object): |
# stdlib and coverage.py directories. |
if self.source_match: |
if not self.source_match.match(canonical): |
- return False |
+ return None, "falls outside the --source trees" |
elif self.include_match: |
if not self.include_match.match(canonical): |
- return False |
+ return None, "falls outside the --include trees" |
else: |
# If we aren't supposed to trace installed code, then check if this |
# is near the Python standard library and skip it if so. |
if self.pylib_match and self.pylib_match.match(canonical): |
- return False |
+ return None, "is in the stdlib" |
# We exclude the coverage code itself, since a little of it will be |
# measured otherwise. |
if self.cover_match and self.cover_match.match(canonical): |
- return False |
+ return None, "is part of coverage.py" |
# Check the file against the omit pattern. |
if self.omit_match and self.omit_match.match(canonical): |
- return False |
+ return None, "is inside an --omit pattern" |
- return canonical |
+ return canonical, "because we love you" |
+ |
+ def _should_trace(self, filename, frame): |
+ """Decide whether to trace execution in `filename`. |
- # To log what should_trace returns, change this to "if 1:" |
- if 0: |
- _real_should_trace = _should_trace |
- def _should_trace(self, filename, frame): # pylint: disable=E0102 |
- """A logging decorator around the real _should_trace function.""" |
- ret = self._real_should_trace(filename, frame) |
- print("should_trace: %r -> %r" % (filename, ret)) |
- return ret |
+ Calls `_should_trace_with_reason`, and returns just the decision. |
+ |
+ """ |
+ canonical, reason = self._should_trace_with_reason(filename, frame) |
+ if self.debug.should('trace'): |
+ if not canonical: |
+ msg = "Not tracing %r: %s" % (filename, reason) |
+ else: |
+ msg = "Tracing %r" % (filename,) |
+ self.debug.write(msg) |
+ return canonical |
def _warn(self, msg): |
"""Use `msg` as a warning.""" |
@@ -364,6 +390,16 @@ class coverage(object): |
if self.omit: |
self.omit_match = FnmatchMatcher(self.omit) |
+ # The user may want to debug things, show info if desired. |
+ if self.debug.should('config'): |
+ self.debug.write("Configuration values:") |
+ config_info = sorted(self.config.__dict__.items()) |
+ self.debug.write_formatted_info(config_info) |
+ |
+ if self.debug.should('sys'): |
+ self.debug.write("Debugging info:") |
+ self.debug.write_formatted_info(self.sysinfo()) |
+ |
self.collector.start() |
self._started = True |
self._measured = True |
@@ -479,29 +515,37 @@ class coverage(object): |
Also warn about various problems collecting data. |
""" |
- if self._measured: |
- self.data.add_line_data(self.collector.get_line_data()) |
- self.data.add_arc_data(self.collector.get_arc_data()) |
- self.collector.reset() |
- |
- # If there are still entries in the source_pkgs list, then we never |
- # encountered those packages. |
- if self._warn_unimported_source: |
- for pkg in self.source_pkgs: |
- self._warn("Module %s was never imported." % pkg) |
- |
- # Find out if we got any data. |
- summary = self.data.summary() |
- if not summary and self._warn_no_data: |
- self._warn("No data was collected.") |
- |
- # Find files that were never executed at all. |
- for src in self.source: |
- for py_file in find_python_files(src): |
- py_file = self.file_locator.canonical_filename(py_file) |
- self.data.touch_file(py_file) |
- |
- self._measured = False |
+ if not self._measured: |
+ return |
+ |
+ self.data.add_line_data(self.collector.get_line_data()) |
+ self.data.add_arc_data(self.collector.get_arc_data()) |
+ self.collector.reset() |
+ |
+ # If there are still entries in the source_pkgs list, then we never |
+ # encountered those packages. |
+ if self._warn_unimported_source: |
+ for pkg in self.source_pkgs: |
+ self._warn("Module %s was never imported." % pkg) |
+ |
+ # Find out if we got any data. |
+ summary = self.data.summary() |
+ if not summary and self._warn_no_data: |
+ self._warn("No data was collected.") |
+ |
+ # Find files that were never executed at all. |
+ for src in self.source: |
+ for py_file in find_python_files(src): |
+ py_file = self.file_locator.canonical_filename(py_file) |
+ |
+ if self.omit_match and self.omit_match.match(py_file): |
+ # Turns out this file was omitted, so don't pull it back |
+ # in as unexecuted. |
+ continue |
+ |
+ self.data.touch_file(py_file) |
+ |
+ self._measured = False |
# Backward compatibility with version 1. |
def analysis(self, morf): |
@@ -528,8 +572,11 @@ class coverage(object): |
""" |
analysis = self._analyze(morf) |
return ( |
- analysis.filename, analysis.statements, analysis.excluded, |
- analysis.missing, analysis.missing_formatted() |
+ analysis.filename, |
+ sorted(analysis.statements), |
+ sorted(analysis.excluded), |
+ sorted(analysis.missing), |
+ analysis.missing_formatted(), |
) |
def _analyze(self, it): |
@@ -680,11 +727,23 @@ class coverage(object): |
('executable', sys.executable), |
('cwd', os.getcwd()), |
('path', sys.path), |
- ('environment', [ |
+ ('environment', sorted([ |
("%s = %s" % (k, v)) for k, v in iitems(os.environ) |
if re.search(r"^COV|^PY", k) |
- ]), |
+ ])), |
+ ('command_line', " ".join(getattr(sys, 'argv', ['???']))), |
] |
+ if self.source_match: |
+ info.append(('source_match', self.source_match.info())) |
+ if self.include_match: |
+ info.append(('include_match', self.include_match.info())) |
+ if self.omit_match: |
+ info.append(('omit_match', self.omit_match.info())) |
+ if self.cover_match: |
+ info.append(('cover_match', self.cover_match.info())) |
+ if self.pylib_match: |
+ info.append(('pylib_match', self.pylib_match.info())) |
+ |
return info |