Skip to content

Commit

Permalink
If a plugin is disabled, don't try to record its file tracers. #1011
Browse files Browse the repository at this point in the history
  • Loading branch information
nedbat committed Sep 13, 2020
1 parent 24eb6fd commit 039ef09
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CHANGES.rst
Expand Up @@ -31,7 +31,12 @@ Unreleased
to name a package to disambiguate this case. Thanks, Thomas Grainger. Fixes
`issue 268`_.

- If a plugin was disabled due to an exception, we used to still try to record
its information, causing an exception, as reported in `issue 1011`_. This is
now fixed.

.. _issue 268: https://github.com/nedbat/coveragepy/issues/268
.. _issue 1011: https://github.com/nedbat/coveragepy/issues/1011


.. _changes_521:
Expand Down
13 changes: 12 additions & 1 deletion coverage/collector.py
Expand Up @@ -196,6 +196,8 @@ def reset(self):
# handle them.
self.file_tracers = {}

self.disabled_plugins = set()

# The .should_trace_cache attribute is a cache from file names to
# coverage.FileDisposition objects, or None. When a file is first
# considered for tracing, a FileDisposition is obtained from
Expand Down Expand Up @@ -419,6 +421,10 @@ def mapped_file_dict(self, d):

return dict((self.cached_mapped_file(k), v) for k, v in items if v)

def plugin_was_disabled(self, plugin):
"""Record that `plugin` was disabled during the run."""
self.disabled_plugins.add(plugin._coverage_plugin_name)

def flush_data(self):
"""Save the collected data to our associated `CoverageData`.
Expand All @@ -434,7 +440,12 @@ def flush_data(self):
self.covdata.add_arcs(self.mapped_file_dict(self.data))
else:
self.covdata.add_lines(self.mapped_file_dict(self.data))
self.covdata.add_file_tracers(self.mapped_file_dict(self.file_tracers))

file_tracers = {
k: v for k, v in self.file_tracers.items()
if v not in self.disabled_plugins
}
self.covdata.add_file_tracers(self.mapped_file_dict(file_tracers))

self._clear_data()
return True
4 changes: 4 additions & 0 deletions coverage/control.py
Expand Up @@ -709,6 +709,10 @@ def get_data(self):
self._init_data(suffix=None)
self._post_init()

for plugin in self._plugins:
if not plugin._coverage_enabled:
self._collector.plugin_was_disabled(plugin)

if self._collector and self._collector.flush_data():
self._post_save_work()

Expand Down
32 changes: 32 additions & 0 deletions tests/test_plugins.py
Expand Up @@ -611,6 +611,7 @@ def g(x):
cov = coverage.Coverage()
cov.set_option("run:plugins", [module_name])
self.start_import_stop(cov, "simple")
cov.save() # pytest-cov does a save after stop, so we'll do it too.
return cov

def run_bad_plugin(self, module_name, plugin_name, our_error=True, excmsg=None, excmsgs=None):
Expand Down Expand Up @@ -715,6 +716,37 @@ def coverage_init(reg, options):
""")
self.run_bad_plugin("bad_plugin", "Plugin")

def test_file_tracer_fails_eventually(self):
# Django coverage plugin can report on a few files and then fail.
# https://github.com/nedbat/coveragepy/issues/1011
self.make_file("bad_plugin.py", """\
import os.path
import coverage.plugin
class Plugin(coverage.plugin.CoveragePlugin):
def __init__(self):
self.calls = 0
def file_tracer(self, filename):
print(filename)
self.calls += 1
if self.calls <= 2:
return FileTracer(filename)
else:
17/0 # Oh noes!
class FileTracer(coverage.FileTracer):
def __init__(self, filename):
self.filename = filename
def source_filename(self):
return os.path.basename(self.filename).replace(".py", ".foo")
def line_number_range(self, frame):
return -1, -1
def coverage_init(reg, options):
reg.add_file_tracer(Plugin())
""")
self.run_bad_plugin("bad_plugin", "Plugin")

def test_file_tracer_returns_wrong(self):
self.make_file("bad_plugin.py", """\
import coverage.plugin
Expand Down

0 comments on commit 039ef09

Please sign in to comment.