diff --git a/CHANGES.rst b/CHANGES.rst index eaad2cb03..015f7db8f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -29,6 +29,11 @@ Unreleased - Fix: Complex conditionals over excluded lines could have incorrectly reported a missing branch (`issue 1271`_). This is now fixed. +- Fix: More exceptions are now handled when trying to parse source files for + reporting. Problems that used to terminate coverage.py can now be handled + with ``[report] ignore_errors``. This helps with plugins failing to read + files (`django_coverage_plugin issue 78`_). + - Fix: Removed another vestige of jQuery from the source tarball (`issue 840`_). @@ -37,6 +42,7 @@ Unreleased I'd rather not "fix" unsupported interfaces, it's actually nicer with a default value. +.. _django_coverage_plugin issue 78: https://github.com/nedbat/django_coverage_plugin/issues/78 .. _issue 1147: https://github.com/nedbat/coveragepy/issues/1147 .. _issue 1271: https://github.com/nedbat/coveragepy/issues/1271 .. _issue 1273: https://github.com/nedbat/coveragepy/issues/1273 diff --git a/coverage/python.py b/coverage/python.py index 969bfa89c..78c3e716e 100644 --- a/coverage/python.py +++ b/coverage/python.py @@ -57,9 +57,7 @@ def get_python_source(filename): break else: # Couldn't find source. - exc_msg = f"No source for code: '{filename}'.\n" - exc_msg += "Aborting report output, consider using -i." - raise NoSource(exc_msg) + raise NoSource(f"No source for code: '{filename}'.") # Replace \f because of http://bugs.python.org/issue19035 source = source.replace(b'\f', b' ') diff --git a/coverage/report.py b/coverage/report.py index 112dcae12..c1aaa45b8 100644 --- a/coverage/report.py +++ b/coverage/report.py @@ -5,7 +5,7 @@ import sys -from coverage.exceptions import CoverageException, NoSource, NotPython +from coverage.exceptions import CoverageException, NotPython from coverage.files import prep_patterns, FnmatchMatcher from coverage.misc import ensure_dir_for_file, file_be_gone @@ -70,9 +70,6 @@ def get_analysis_to_report(coverage, morfs): for fr in sorted(file_reporters): try: analysis = coverage._analyze(fr) - except NoSource: - if not config.ignore_errors: - raise except NotPython: # Only report errors for .py files, and only if we didn't # explicitly suppress those errors. @@ -84,5 +81,11 @@ def get_analysis_to_report(coverage, morfs): coverage._warn(msg, slug="couldnt-parse") else: raise + except Exception as exc: + if config.ignore_errors: + msg = f"Couldn't parse '{fr.filename}': {exc}".rstrip() + coverage._warn(msg, slug="couldnt-parse") + else: + raise else: yield (fr, analysis) diff --git a/tests/test_xml.py b/tests/test_xml.py index a03257a27..336dec78e 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -135,7 +135,12 @@ def test_no_source(self): cov = coverage.Coverage() self.start_import_stop(cov, "innocuous") os.remove("innocuous.py") - cov.xml_report(ignore_errors=True) + with pytest.warns(Warning) as warns: + cov.xml_report(ignore_errors=True) + assert_coverage_warnings( + warns, + re.compile(r"Couldn't parse '.*innocuous.py'. \(couldnt-parse\)"), + ) self.assert_exists("coverage.xml") def test_filename_format_showing_everything(self):