summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2017-03-28 06:21:34 -0400
committerNed Batchelder <ned@nedbatchelder.com>2017-03-28 06:21:34 -0400
commitb536b6c77c943eb95a0fe27705d842070027b407 (patch)
treedcd9fc433cac970057eac5e6f5a0ff39443e706a
parent778da6cf5ef2a5ed2b2748b2bed215f3ab68995d (diff)
downloadpython-coveragepy-b536b6c77c943eb95a0fe27705d842070027b407.tar.gz
Allow plugins to report files they haven't executed.
By Emil Madsen, from: https://github.com/nedbat/coveragepy/pull/28
-rw-r--r--coverage/control.py18
-rw-r--r--coverage/data.py11
-rw-r--r--coverage/plugin.py9
3 files changed, 31 insertions, 7 deletions
diff --git a/coverage/control.py b/coverage/control.py
index 30923b9..1f79e2f 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -3,8 +3,10 @@
"""Core control stuff for coverage.py."""
+
import atexit
import inspect
+import itertools
import os
import platform
import re
@@ -854,6 +856,11 @@ class Coverage(object):
if self.config.note:
self.data.add_run_info(note=self.config.note)
+ def _find_plugin_files(self, src_dir):
+ for plugin in self.plugins:
+ for x_file in plugin.find_executable_files(src_dir):
+ yield x_file, plugin._coverage_plugin_name
+
def _find_unexecuted_files(self, src_dir):
"""Find unexecuted files in `src_dir`.
@@ -861,15 +868,16 @@ class Coverage(object):
and add them as unexecuted files in `self.data`.
"""
- for py_file in find_python_files(src_dir):
- py_file = files.canonical_filename(py_file)
+ py_files = ((py_file, None) for py_file in files.find_python_files(src_dir))
+ plugin_files = self._find_plugin_files(src_dir)
- if self.omit_match and self.omit_match.match(py_file):
+ for file_path, plugin_name in itertools.chain(py_files, plugin_files):
+ file_path = files.canonical_filename(file_path)
+ if self.omit_match and self.omit_match.match(file_path):
# Turns out this file was omitted, so don't pull it back
# in as unexecuted.
continue
-
- self.data.touch_file(py_file)
+ self.data.touch_file(file_path, plugin_name)
# Backward compatibility with version 1.
def analysis(self, morf):
diff --git a/coverage/data.py b/coverage/data.py
index 67b74d0..ecfb86b 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -416,8 +416,12 @@ class CoverageData(object):
self._runs[0].update(kwargs)
self._validate()
- def touch_file(self, filename):
- """Ensure that `filename` appears in the data, empty if needed."""
+ def touch_file(self, filename, plugin_name=""):
+ """Ensure that `filename` appears in the data, empty if needed.
+
+ `plugin_name` is the name of the plugin resposible for this file. It is used
+ to associate the right filereporter, etc.
+ """
if self._debug and self._debug.should('dataop'):
self._debug.write("Touching %r" % (filename,))
if not self._has_arcs() and not self._has_lines():
@@ -428,6 +432,9 @@ class CoverageData(object):
else:
where = self._lines
where.setdefault(filename, [])
+ if plugin_name:
+ # Set the tracer for this file
+ self._file_tracers[filename] = plugin_name
self._validate()
diff --git a/coverage/plugin.py b/coverage/plugin.py
index fc95eee..43f291b 100644
--- a/coverage/plugin.py
+++ b/coverage/plugin.py
@@ -89,6 +89,15 @@ class CoveragePlugin(object):
"""
_needs_to_implement(self, "file_reporter")
+ def find_executable_files(self, src_dir):
+ """Yield all of the executable files in `dirname`, recursively.
+
+ Executability is a plugin-specific property, but generally means files
+ which would have been considered for coverage analysis, had they been
+ included automatically.
+ """
+ return []
+
def sys_info(self):
"""Get a list of information useful for debugging.