summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2023-02-08 21:50:20 -0700
committerNed Batchelder <ned@nedbatchelder.com>2023-02-08 22:01:35 -0700
commit8f3e7b45b3aabf4d7d01dc470010d3d36f30a0ba (patch)
tree72c9ee920e66586385e4c63c54301a122fe7e0c7
parent423fa596325acb8f6bcb37a3502cf7853e5d395a (diff)
downloadpython-coveragepy-git-8f3e7b45b3aabf4d7d01dc470010d3d36f30a0ba.tar.gz
fix: only write "Wrote report" message if report succeeded.
For example, see [issue 1554](https://github.com/nedbat/coveragepy/issues/1554) for the previous misleading behavior when the exception being raised wasn't a CoverageException.
-rw-r--r--CHANGES.rst4
-rw-r--r--coverage/report.py23
-rw-r--r--tests/test_report.py13
3 files changed, 22 insertions, 18 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index b4883728..f336cff5 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -23,6 +23,10 @@ Unreleased
- Added a :meth:`.CoverageData.purge_files` method to remove recorded data for
a particular file. Contributed by `Stephan Deibel <pull 1547_>`_.
+- Fix: when reporting commands fail, they will no longer congratulate
+ themselves with messages like "Wrote XML report to file.xml" before spewing a
+ traceback about their failure.
+
- Fix: In some embedded environments, an IndexError could occur on stop() when
the originating thread exits before completion. This is now fixed, thanks to
`Russell Keith-Magee <pull 1543_>`_, closing `issue 1542`_.
diff --git a/coverage/report.py b/coverage/report.py
index 74ae1817..09eed0a8 100644
--- a/coverage/report.py
+++ b/coverage/report.py
@@ -9,7 +9,7 @@ import sys
from typing import Callable, Iterable, Iterator, IO, Optional, Tuple, TYPE_CHECKING
-from coverage.exceptions import CoverageException, NoDataError, NotPython
+from coverage.exceptions import NoDataError, NotPython
from coverage.files import prep_patterns, GlobMatcher
from coverage.misc import ensure_dir_for_file, file_be_gone
from coverage.plugin import FileReporter
@@ -47,26 +47,25 @@ def render_report(
if output_path == "-":
outfile = sys.stdout
else:
- # Ensure that the output directory is created; done here
- # because this report pre-opens the output file.
- # HTMLReport does this using the Report plumbing because
- # its task is more complex, being multiple files.
+ # Ensure that the output directory is created; done here because this
+ # report pre-opens the output file. HtmlReporter does this on its own
+ # because its task is more complex, being multiple files.
ensure_dir_for_file(output_path)
outfile = open(output_path, "w", encoding="utf-8")
file_to_close = outfile
+ delete_file = True
try:
- return reporter.report(morfs, outfile=outfile)
- except CoverageException:
- delete_file = True
- raise
+ ret = reporter.report(morfs, outfile=outfile)
+ if file_to_close is not None:
+ msgfn(f"Wrote {reporter.report_type} to {output_path}")
+ delete_file = False
+ return ret
finally:
- if file_to_close:
+ if file_to_close is not None:
file_to_close.close()
if delete_file:
file_be_gone(output_path) # pragma: part covered (doesn't return)
- else:
- msgfn(f"Wrote {reporter.report_type} to {output_path}")
def get_analysis_to_report(
diff --git a/tests/test_report.py b/tests/test_report.py
index 3d87b514..c85c6b47 100644
--- a/tests/test_report.py
+++ b/tests/test_report.py
@@ -5,7 +5,7 @@
from __future__ import annotations
-from typing import IO, Iterable, List, Optional
+from typing import IO, Iterable, List, Optional, Type
import pytest
@@ -21,7 +21,7 @@ class FakeReporter:
report_type = "fake report file"
- def __init__(self, output: str = "", error: bool = False) -> None:
+ def __init__(self, output: str = "", error: Optional[Type[Exception]] = None) -> None:
self.output = output
self.error = error
self.morfs: Optional[Iterable[TMorf]] = None
@@ -31,7 +31,7 @@ class FakeReporter:
self.morfs = morfs
outfile.write(self.output)
if self.error:
- raise CoverageException("You asked for it!")
+ raise self.error("You asked for it!")
return 17.25
@@ -57,10 +57,11 @@ class RenderReportTest(CoverageTest):
assert f.read().rstrip() == b"Gr\xc3\xa9\xc3\xa8tings!"
assert msgs == ["Wrote fake report file to output.txt"]
- def test_exception(self) -> None:
- fake = FakeReporter(error=True)
+ @pytest.mark.parametrize("error", [CoverageException, ZeroDivisionError])
+ def test_exception(self, error: Type[Exception]) -> None:
+ fake = FakeReporter(error=error)
msgs: List[str] = []
- with pytest.raises(CoverageException, match="You asked for it!"):
+ with pytest.raises(error, match="You asked for it!"):
render_report("output.txt", fake, [], msgs.append)
assert self.stdout() == ""
self.assert_doesnt_exist("output.txt")