diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2017-03-28 06:21:34 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2017-03-28 06:21:34 -0400 |
commit | b536b6c77c943eb95a0fe27705d842070027b407 (patch) | |
tree | dcd9fc433cac970057eac5e6f5a0ff39443e706a | |
parent | 778da6cf5ef2a5ed2b2748b2bed215f3ab68995d (diff) | |
download | python-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.py | 18 | ||||
-rw-r--r-- | coverage/data.py | 11 | ||||
-rw-r--r-- | coverage/plugin.py | 9 |
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. |