Skip to content

Commit 039ef09

Browse files
committed
If a plugin is disabled, don't try to record its file tracers. #1011
1 parent 24eb6fd commit 039ef09

File tree

4 files changed

+53
-1
lines changed

4 files changed

+53
-1
lines changed

CHANGES.rst

+5
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ Unreleased
3131
to name a package to disambiguate this case. Thanks, Thomas Grainger. Fixes
3232
`issue 268`_.
3333

34+
- If a plugin was disabled due to an exception, we used to still try to record
35+
its information, causing an exception, as reported in `issue 1011`_. This is
36+
now fixed.
37+
3438
.. _issue 268: https://github.com/nedbat/coveragepy/issues/268
39+
.. _issue 1011: https://github.com/nedbat/coveragepy/issues/1011
3540

3641

3742
.. _changes_521:

coverage/collector.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ def reset(self):
196196
# handle them.
197197
self.file_tracers = {}
198198

199+
self.disabled_plugins = set()
200+
199201
# The .should_trace_cache attribute is a cache from file names to
200202
# coverage.FileDisposition objects, or None. When a file is first
201203
# considered for tracing, a FileDisposition is obtained from
@@ -419,6 +421,10 @@ def mapped_file_dict(self, d):
419421

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

424+
def plugin_was_disabled(self, plugin):
425+
"""Record that `plugin` was disabled during the run."""
426+
self.disabled_plugins.add(plugin._coverage_plugin_name)
427+
422428
def flush_data(self):
423429
"""Save the collected data to our associated `CoverageData`.
424430
@@ -434,7 +440,12 @@ def flush_data(self):
434440
self.covdata.add_arcs(self.mapped_file_dict(self.data))
435441
else:
436442
self.covdata.add_lines(self.mapped_file_dict(self.data))
437-
self.covdata.add_file_tracers(self.mapped_file_dict(self.file_tracers))
443+
444+
file_tracers = {
445+
k: v for k, v in self.file_tracers.items()
446+
if v not in self.disabled_plugins
447+
}
448+
self.covdata.add_file_tracers(self.mapped_file_dict(file_tracers))
438449

439450
self._clear_data()
440451
return True

coverage/control.py

+4
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,10 @@ def get_data(self):
709709
self._init_data(suffix=None)
710710
self._post_init()
711711

712+
for plugin in self._plugins:
713+
if not plugin._coverage_enabled:
714+
self._collector.plugin_was_disabled(plugin)
715+
712716
if self._collector and self._collector.flush_data():
713717
self._post_save_work()
714718

tests/test_plugins.py

+32
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ def g(x):
611611
cov = coverage.Coverage()
612612
cov.set_option("run:plugins", [module_name])
613613
self.start_import_stop(cov, "simple")
614+
cov.save() # pytest-cov does a save after stop, so we'll do it too.
614615
return cov
615616

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

719+
def test_file_tracer_fails_eventually(self):
720+
# Django coverage plugin can report on a few files and then fail.
721+
# https://github.com/nedbat/coveragepy/issues/1011
722+
self.make_file("bad_plugin.py", """\
723+
import os.path
724+
import coverage.plugin
725+
class Plugin(coverage.plugin.CoveragePlugin):
726+
def __init__(self):
727+
self.calls = 0
728+
729+
def file_tracer(self, filename):
730+
print(filename)
731+
self.calls += 1
732+
if self.calls <= 2:
733+
return FileTracer(filename)
734+
else:
735+
17/0 # Oh noes!
736+
737+
class FileTracer(coverage.FileTracer):
738+
def __init__(self, filename):
739+
self.filename = filename
740+
def source_filename(self):
741+
return os.path.basename(self.filename).replace(".py", ".foo")
742+
def line_number_range(self, frame):
743+
return -1, -1
744+
745+
def coverage_init(reg, options):
746+
reg.add_file_tracer(Plugin())
747+
""")
748+
self.run_bad_plugin("bad_plugin", "Plugin")
749+
718750
def test_file_tracer_returns_wrong(self):
719751
self.make_file("bad_plugin.py", """\
720752
import coverage.plugin

0 commit comments

Comments
 (0)