From e1dd1184aecf4a9aee5425b487e67dcfd734d608 Mon Sep 17 00:00:00 2001 From: Bart Feenstra Date: Mon, 13 May 2024 17:15:53 +0100 Subject: [PATCH 1/3] Report data file errors in more detail: include file and directory paths, and make helpful suggestions --- coverage/cmdline.py | 11 +++++--- coverage/data.py | 23 ++++++++++------ coverage/exceptions.py | 60 +++++++++++++++++++++++++++++++++++++++++ coverage/html.py | 6 +++-- coverage/report.py | 7 +++-- coverage/report_core.py | 7 +++-- tests/test_api.py | 26 +++++++++++++++--- tests/test_coverage.py | 24 ++++++++++++++--- tests/test_data.py | 2 +- tests/test_html.py | 8 +++++- tests/test_process.py | 8 +++++- tests/test_report.py | 24 ++++++++++++++--- tests/test_xml.py | 8 +++++- 13 files changed, 182 insertions(+), 32 deletions(-) diff --git a/coverage/cmdline.py b/coverage/cmdline.py index 9f9c06559..1f254e004 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -13,6 +13,7 @@ import sys import textwrap import traceback +from contextlib import suppress from typing import cast, Any, NoReturn @@ -24,7 +25,8 @@ from coverage.control import DEFAULT_DATAFILE from coverage.data import combinable_files, debug_data_file from coverage.debug import info_header, short_stack, write_formatted_info -from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource +from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource, \ + NoDataFilesFoundError from coverage.execfile import PyRunner from coverage.results import display_covered, should_fail_under from coverage.version import __url__ @@ -882,9 +884,10 @@ def do_debug(self, args: list[str]) -> int: print(info_header("data")) data_file = self.coverage.config.data_file debug_data_file(data_file) - for filename in combinable_files(data_file): - print("-----") - debug_data_file(filename) + with suppress(NoDataFilesFoundError): + for filename in combinable_files(data_file): + print("-----") + debug_data_file(filename) elif args[0] == "config": write_formatted_info(print, "config", self.coverage.config.debug_info()) elif args[0] == "premain": diff --git a/coverage/data.py b/coverage/data.py index 9513adfca..10c5b81ad 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -15,10 +15,10 @@ import glob import hashlib import os.path - from typing import Callable, Iterable -from coverage.exceptions import CoverageException, NoDataError +from coverage.exceptions import CoverageException, DataFileOrDirectoryNotFoundError, \ + NoDataFilesFoundError, UnusableDataFilesError from coverage.files import PathAliases from coverage.misc import Hasher, file_be_gone, human_sorted, plural from coverage.sqldata import CoverageData @@ -82,12 +82,17 @@ def combinable_files(data_file: str, data_paths: Iterable[str] | None = None) -> pattern = glob.escape(os.path.join(os.path.abspath(p), local)) +".*" files_to_combine.extend(glob.glob(pattern)) else: - raise NoDataError(f"Couldn't combine from non-existent path '{p}'") + raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + p, is_combining=True + ) # SQLite might have made journal files alongside our database files. # We never want to combine those. files_to_combine = [fnm for fnm in files_to_combine if not fnm.endswith("-journal")] + if not files_to_combine: + raise NoDataFilesFoundError.new_for_data_directory(data_dir) + # Sorting isn't usually needed, since it shouldn't matter what order files # are combined, but sorting makes tests more predictable, and makes # debugging more understandable when things go wrong. @@ -129,10 +134,12 @@ def combine_parallel_data( `message` is a function to use for printing messages to the user. """ - files_to_combine = combinable_files(data.base_filename(), data_paths) - - if strict and not files_to_combine: - raise NoDataError("No data to combine") + try: + files_to_combine = combinable_files(data.base_filename(), data_paths) + except NoDataFilesFoundError: + if strict: + raise + return file_hashes = set() combined_any = False @@ -190,7 +197,7 @@ def combine_parallel_data( file_be_gone(f) if strict and not combined_any: - raise NoDataError("No usable data files") + raise UnusableDataFilesError.new_for_data_files(*files_to_combine) def debug_data_file(filename: str) -> None: diff --git a/coverage/exceptions.py b/coverage/exceptions.py index ecd1b5e64..651afb856 100644 --- a/coverage/exceptions.py +++ b/coverage/exceptions.py @@ -5,6 +5,16 @@ from __future__ import annotations +import os.path + + +def _message_append_combine_hint(message: str, is_combining: bool) -> str: + """Append information about the combine command to error messages.""" + if not is_combining: + message += " Perhaps `coverage combine` must be run first." + return message + + class _BaseCoverageException(Exception): """The base-base of all Coverage exceptions.""" pass @@ -24,11 +34,61 @@ class DataError(CoverageException): """An error in using a data file.""" pass + class NoDataError(CoverageException): """We didn't have data to work with.""" pass +class DataFileOrDirectoryNotFoundError(NoDataError): + """A data file or data directory could be found.""" + @classmethod + def new_for_data_file_or_directory( + cls, data_file_or_directory_path: str, *, is_combining: bool = False + ) -> 'DataFileOrDirectoryNotFoundError': + """ + Create a new instance. + """ + message = ( + f"The data file or directory `{os.path.abspath(data_file_or_directory_path)}` could not" + " be found." + ) + return cls(_message_append_combine_hint(message, is_combining)) + + +class NoDataFilesFoundError(NoDataError): + """No data files could be found in a data directory.""" + @classmethod + def new_for_data_directory( + cls, data_directory_path: str, *, is_combining: bool = False + ) -> 'NoDataFilesFoundError': + """ + Create a new instance. + """ + message = ( + f"The data directory `{os.path.abspath(data_directory_path)}` does not contain any data" + " files." + ) + return cls(_message_append_combine_hint(message, is_combining)) + + +class UnusableDataFilesError(NoDataError): + """The given data files are unusable.""" + @classmethod + def new_for_data_files(cls, *data_file_paths: str) -> 'UnusableDataFilesError': + """ + Create a new instance. + """ + message = ( + "The following data files are unusable, perhaps because they do not contain valid" + " coverage information:" + ) + for data_file_path in data_file_paths: + message += f"\n- `{os.path.abspath(data_file_path)}`" + + return cls(message) + + class NoSource(CoverageException): """We couldn't find the source for a module.""" pass diff --git a/coverage/html.py b/coverage/html.py index 51a7f9419..2619381f3 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -19,7 +19,7 @@ import coverage from coverage.data import CoverageData, add_data_to_hash -from coverage.exceptions import NoDataError +from coverage.exceptions import DataFileOrDirectoryNotFoundError from coverage.files import flat_rootname from coverage.misc import ( ensure_dir, file_be_gone, Hasher, isolate_module, format_local_datetime, @@ -317,7 +317,9 @@ def report(self, morfs: Iterable[TMorf] | None) -> float: file_be_gone(os.path.join(self.directory, ftr.html_filename)) if not have_data: - raise NoDataError("No data to report.") + raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + os.path.dirname(self.coverage.get_data().base_filename()) + ) self.make_directory() self.make_local_static_report_files() diff --git a/coverage/report.py b/coverage/report.py index 42f7b5aec..6b120b5fb 100644 --- a/coverage/report.py +++ b/coverage/report.py @@ -5,11 +5,12 @@ from __future__ import annotations +import os import sys from typing import Any, IO, Iterable, TYPE_CHECKING -from coverage.exceptions import ConfigError, NoDataError +from coverage.exceptions import ConfigError, DataFileOrDirectoryNotFoundError from coverage.misc import human_sorted_items from coverage.plugin import FileReporter from coverage.report_core import get_analysis_to_report @@ -182,7 +183,9 @@ def report(self, morfs: Iterable[TMorf] | None, outfile: IO[str] | None = None) self.report_one_file(fr, analysis) if not self.total.n_files and not self.skipped_count: - raise NoDataError("No data to report.") + raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + os.path.dirname(self.coverage.get_data().base_filename()) + ) if self.output_format == "total": self.write(self.total.pc_covered_str) diff --git a/coverage/report_core.py b/coverage/report_core.py index db0e7b280..ab413ed4b 100644 --- a/coverage/report_core.py +++ b/coverage/report_core.py @@ -5,13 +5,14 @@ from __future__ import annotations +import os import sys from typing import ( Callable, Iterable, Iterator, IO, Protocol, TYPE_CHECKING, ) -from coverage.exceptions import NoDataError, NotPython +from coverage.exceptions import NotPython, DataFileOrDirectoryNotFoundError from coverage.files import prep_patterns, GlobMatcher from coverage.misc import ensure_dir_for_file, file_be_gone from coverage.plugin import FileReporter @@ -93,7 +94,9 @@ def get_analysis_to_report( fr_morfs = [(fr, morf) for (fr, morf) in fr_morfs if not matcher.match(fr.filename)] if not fr_morfs: - raise NoDataError("No data to report.") + raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + os.path.dirname(coverage.get_data().base_filename()) + ) for fr, morf in sorted(fr_morfs): try: diff --git a/tests/test_api.py b/tests/test_api.py index 9f65166b9..0c1a5b78d 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -300,7 +300,13 @@ def test_empty_reporting(self) -> None: # empty summary reports raise exception, just like the xml report cov = coverage.Coverage() cov.erase() - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): cov.report() def test_completely_zero_reporting(self) -> None: @@ -446,7 +452,13 @@ def test_combining_twice(self) -> None: self.assert_exists(".coverage") cov2 = coverage.Coverage() - with pytest.raises(NoDataError, match=r"No data to combine"): + with pytest.raises( + NoDataError, + match=( + r"^The data directory `(.+?)` does not contain any data files. Perhaps `coverage " + r"combine` must be run first.$" + ) + ): cov2.combine(strict=True, keep=False) cov3 = coverage.Coverage() @@ -1326,7 +1338,7 @@ def test_combine_parallel_data(self) -> None: # Running combine again should fail, because there are no parallel data # files to combine. cov = coverage.Coverage() - with pytest.raises(NoDataError, match=r"No data to combine"): + with pytest.raises(NoDataError): cov.combine(strict=True) # And the originally combined data is still there. @@ -1376,7 +1388,13 @@ def test_combine_no_usable_files(self) -> None: # Combine the parallel coverage data files into .coverage, but nothing is readable. cov = coverage.Coverage() with pytest.warns(Warning) as warns: - with pytest.raises(NoDataError, match=r"No usable data files"): + with pytest.raises( + NoDataError, + match=( + r"^The following data files are unusable, perhaps because they do not contain " + r"valid coverage information:\n- `(.+?)`\n- `(.+?)`$" + ) + ): cov.combine(strict=True) warn_rx = re.compile( diff --git a/tests/test_coverage.py b/tests/test_coverage.py index d50971120..8386baf16 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -1635,19 +1635,37 @@ class ReportingTest(CoverageTest): def test_no_data_to_report_on_annotate(self) -> None: # Reporting with no data produces a nice message and no output # directory. - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): self.command_line("annotate -d ann") self.assert_doesnt_exist("ann") def test_no_data_to_report_on_html(self) -> None: # Reporting with no data produces a nice message and no output # directory. - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): self.command_line("html -d htmlcov") self.assert_doesnt_exist("htmlcov") def test_no_data_to_report_on_xml(self) -> None: # Reporting with no data produces a nice message. - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): self.command_line("xml") self.assert_doesnt_exist("coverage.xml") diff --git a/tests/test_data.py b/tests/test_data.py index 1f0bb20dc..67e1045d8 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -915,7 +915,7 @@ def test_combining_from_files(self) -> None: def test_combining_from_nonexistent_directories(self) -> None: covdata = DebugCoverageData() - msg = "Couldn't combine from non-existent path 'xyzzy'" + msg = r"^The data file or directory `(.+?)` could not be found.$" with pytest.raises(NoDataError, match=msg): combine_parallel_data(covdata, data_paths=['xyzzy']) diff --git a/tests/test_html.py b/tests/test_html.py index 1a8c71f95..8c28678e3 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -426,7 +426,13 @@ def test_dothtml_not_python(self) -> None: self.make_file("innocuous.html", "

This isn't python at all!

") cov = coverage.Coverage() cov.load() - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): cov.html_report() def test_execed_liar_ignored(self) -> None: diff --git a/tests/test_process.py b/tests/test_process.py index 27d01c0f0..4e7a5dcd9 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -1143,7 +1143,13 @@ class FailUnderNoFilesTest(CoverageTest): def test_report(self) -> None: self.make_file(".coveragerc", "[report]\nfail_under = 99\n") st, out = self.run_command_status("coverage report") - assert 'No data to report.' in out + assert re.match( + ( + r"The data file or directory `([^`]+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\." + ), + out + ) assert st == 1 diff --git a/tests/test_report.py b/tests/test_report.py index fca027f9b..b10bc769b 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -551,7 +551,13 @@ def foo(): def test_report_skip_covered_no_data(self) -> None: cov = coverage.Coverage() cov.load() - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): self.get_report(cov, skip_covered=True) self.assert_doesnt_exist(".coverage") @@ -744,7 +750,13 @@ def test_dotpy_not_python_ignored(self) -> None: self.make_data_file(lines={"mycode.py": [1]}) cov = coverage.Coverage() cov.load() - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): with pytest.warns(Warning) as warns: self.get_report(cov, morfs=["mycode.py"], ignore_errors=True) assert_coverage_warnings( @@ -761,7 +773,13 @@ def test_dothtml_not_python(self) -> None: self.make_data_file(lines={"mycode.html": [1]}) cov = coverage.Coverage() cov.load() - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): self.get_report(cov, morfs=["mycode.html"]) def test_report_no_extension(self) -> None: diff --git a/tests/test_xml.py b/tests/test_xml.py index ad915380a..7b76d5c34 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -145,7 +145,13 @@ def test_config_affects_xml_placement(self) -> None: def test_no_data(self) -> None: # https://github.com/nedbat/coveragepy/issues/210 - with pytest.raises(NoDataError, match="No data to report."): + with pytest.raises( + NoDataError, + match=( + r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " + r"combine` must be run first\.$" + ) + ): self.run_xml_report() self.assert_doesnt_exist("coverage.xml") self.assert_doesnt_exist(".coverage") From 8bf5006624623f38155c8a75d3a0e42a9c53fbc7 Mon Sep 17 00:00:00 2001 From: Bart Feenstra Date: Thu, 16 May 2024 19:23:01 +0100 Subject: [PATCH 2/3] Implement most of @nedbat's feedback --- coverage/cmdline.py | 5 +++-- coverage/data.py | 6 +++--- coverage/exceptions.py | 22 +++++++++++----------- coverage/html.py | 2 +- coverage/report.py | 2 +- coverage/report_core.py | 2 +- tests/test_api.py | 10 +++++----- tests/test_coverage.py | 12 ++++++------ tests/test_data.py | 2 +- tests/test_html.py | 4 ++-- tests/test_process.py | 4 ++-- tests/test_report.py | 12 ++++++------ tests/test_xml.py | 4 ++-- 13 files changed, 44 insertions(+), 43 deletions(-) diff --git a/coverage/cmdline.py b/coverage/cmdline.py index 1f254e004..efbd57aad 100644 --- a/coverage/cmdline.py +++ b/coverage/cmdline.py @@ -25,8 +25,9 @@ from coverage.control import DEFAULT_DATAFILE from coverage.data import combinable_files, debug_data_file from coverage.debug import info_header, short_stack, write_formatted_info -from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource, \ - NoDataFilesFoundError +from coverage.exceptions import ( + _BaseCoverageException, _ExceptionDuringRun, NoSource, NoDataFilesFoundError, +) from coverage.execfile import PyRunner from coverage.results import display_covered, should_fail_under from coverage.version import __url__ diff --git a/coverage/data.py b/coverage/data.py index 10c5b81ad..299c66e76 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -82,7 +82,7 @@ def combinable_files(data_file: str, data_paths: Iterable[str] | None = None) -> pattern = glob.escape(os.path.join(os.path.abspath(p), local)) +".*" files_to_combine.extend(glob.glob(pattern)) else: - raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + raise DataFileOrDirectoryNotFoundError.new( p, is_combining=True ) @@ -91,7 +91,7 @@ def combinable_files(data_file: str, data_paths: Iterable[str] | None = None) -> files_to_combine = [fnm for fnm in files_to_combine if not fnm.endswith("-journal")] if not files_to_combine: - raise NoDataFilesFoundError.new_for_data_directory(data_dir) + raise NoDataFilesFoundError.new(data_dir) # Sorting isn't usually needed, since it shouldn't matter what order files # are combined, but sorting makes tests more predictable, and makes @@ -197,7 +197,7 @@ def combine_parallel_data( file_be_gone(f) if strict and not combined_any: - raise UnusableDataFilesError.new_for_data_files(*files_to_combine) + raise UnusableDataFilesError.new(*files_to_combine) def debug_data_file(filename: str) -> None: diff --git a/coverage/exceptions.py b/coverage/exceptions.py index 651afb856..450e3e040 100644 --- a/coverage/exceptions.py +++ b/coverage/exceptions.py @@ -11,7 +11,7 @@ def _message_append_combine_hint(message: str, is_combining: bool) -> str: """Append information about the combine command to error messages.""" if not is_combining: - message += " Perhaps `coverage combine` must be run first." + message += " Perhaps 'coverage combine' must be run first." return message @@ -43,15 +43,15 @@ class NoDataError(CoverageException): class DataFileOrDirectoryNotFoundError(NoDataError): """A data file or data directory could be found.""" @classmethod - def new_for_data_file_or_directory( + def new( cls, data_file_or_directory_path: str, *, is_combining: bool = False - ) -> 'DataFileOrDirectoryNotFoundError': + ) -> DataFileOrDirectoryNotFoundError: """ Create a new instance. """ message = ( - f"The data file or directory `{os.path.abspath(data_file_or_directory_path)}` could not" - " be found." + f"The data file or directory '{os.path.abspath(data_file_or_directory_path)}' could not" + + " be found." ) return cls(_message_append_combine_hint(message, is_combining)) @@ -59,15 +59,15 @@ def new_for_data_file_or_directory( class NoDataFilesFoundError(NoDataError): """No data files could be found in a data directory.""" @classmethod - def new_for_data_directory( + def new( cls, data_directory_path: str, *, is_combining: bool = False ) -> 'NoDataFilesFoundError': """ Create a new instance. """ message = ( - f"The data directory `{os.path.abspath(data_directory_path)}` does not contain any data" - " files." + f"The data directory '{os.path.abspath(data_directory_path)}' does not contain any data" + + " files." ) return cls(_message_append_combine_hint(message, is_combining)) @@ -75,16 +75,16 @@ def new_for_data_directory( class UnusableDataFilesError(NoDataError): """The given data files are unusable.""" @classmethod - def new_for_data_files(cls, *data_file_paths: str) -> 'UnusableDataFilesError': + def new(cls, *data_file_paths: str) -> 'UnusableDataFilesError': """ Create a new instance. """ message = ( "The following data files are unusable, perhaps because they do not contain valid" - " coverage information:" + + " coverage information:" ) for data_file_path in data_file_paths: - message += f"\n- `{os.path.abspath(data_file_path)}`" + message += f"\n- '{os.path.abspath(data_file_path)}'" return cls(message) diff --git a/coverage/html.py b/coverage/html.py index 2619381f3..c1f3bf8be 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -317,7 +317,7 @@ def report(self, morfs: Iterable[TMorf] | None) -> float: file_be_gone(os.path.join(self.directory, ftr.html_filename)) if not have_data: - raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + raise DataFileOrDirectoryNotFoundError.new( os.path.dirname(self.coverage.get_data().base_filename()) ) diff --git a/coverage/report.py b/coverage/report.py index 6b120b5fb..97881af8f 100644 --- a/coverage/report.py +++ b/coverage/report.py @@ -183,7 +183,7 @@ def report(self, morfs: Iterable[TMorf] | None, outfile: IO[str] | None = None) self.report_one_file(fr, analysis) if not self.total.n_files and not self.skipped_count: - raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + raise DataFileOrDirectoryNotFoundError.new( os.path.dirname(self.coverage.get_data().base_filename()) ) diff --git a/coverage/report_core.py b/coverage/report_core.py index ab413ed4b..3c9182339 100644 --- a/coverage/report_core.py +++ b/coverage/report_core.py @@ -94,7 +94,7 @@ def get_analysis_to_report( fr_morfs = [(fr, morf) for (fr, morf) in fr_morfs if not matcher.match(fr.filename)] if not fr_morfs: - raise DataFileOrDirectoryNotFoundError.new_for_data_file_or_directory( + raise DataFileOrDirectoryNotFoundError.new( os.path.dirname(coverage.get_data().base_filename()) ) diff --git a/tests/test_api.py b/tests/test_api.py index 0c1a5b78d..63879e2b5 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -303,8 +303,8 @@ def test_empty_reporting(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): cov.report() @@ -455,8 +455,8 @@ def test_combining_twice(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data directory `(.+?)` does not contain any data files. Perhaps `coverage " - r"combine` must be run first.$" + r"^The data directory '(.+?)' does not contain any data files. Perhaps 'coverage " + r"combine' must be run first.$" ) ): cov2.combine(strict=True, keep=False) @@ -1392,7 +1392,7 @@ def test_combine_no_usable_files(self) -> None: NoDataError, match=( r"^The following data files are unusable, perhaps because they do not contain " - r"valid coverage information:\n- `(.+?)`\n- `(.+?)`$" + r"valid coverage information:\n- '(.+?)'\n- '(.+?)'$" ) ): cov.combine(strict=True) diff --git a/tests/test_coverage.py b/tests/test_coverage.py index 8386baf16..a5264277b 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -1638,8 +1638,8 @@ def test_no_data_to_report_on_annotate(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): self.command_line("annotate -d ann") @@ -1651,8 +1651,8 @@ def test_no_data_to_report_on_html(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): self.command_line("html -d htmlcov") @@ -1663,8 +1663,8 @@ def test_no_data_to_report_on_xml(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): self.command_line("xml") diff --git a/tests/test_data.py b/tests/test_data.py index 67e1045d8..bd6d2194b 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -915,7 +915,7 @@ def test_combining_from_files(self) -> None: def test_combining_from_nonexistent_directories(self) -> None: covdata = DebugCoverageData() - msg = r"^The data file or directory `(.+?)` could not be found.$" + msg = r"^The data file or directory '(.+?)' could not be found.$" with pytest.raises(NoDataError, match=msg): combine_parallel_data(covdata, data_paths=['xyzzy']) diff --git a/tests/test_html.py b/tests/test_html.py index 8c28678e3..3a0865922 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -429,8 +429,8 @@ def test_dothtml_not_python(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): cov.html_report() diff --git a/tests/test_process.py b/tests/test_process.py index 4e7a5dcd9..c96539978 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -1145,8 +1145,8 @@ def test_report(self) -> None: st, out = self.run_command_status("coverage report") assert re.match( ( - r"The data file or directory `([^`]+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\." + r"The data file or directory '([^']+?)' could not be found\. Perhaps 'coverage " + + r"combine' must be run first\." ), out ) diff --git a/tests/test_report.py b/tests/test_report.py index b10bc769b..393be02ea 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -554,8 +554,8 @@ def test_report_skip_covered_no_data(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): self.get_report(cov, skip_covered=True) @@ -753,8 +753,8 @@ def test_dotpy_not_python_ignored(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): with pytest.warns(Warning) as warns: @@ -776,8 +776,8 @@ def test_dothtml_not_python(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): self.get_report(cov, morfs=["mycode.html"]) diff --git a/tests/test_xml.py b/tests/test_xml.py index 7b76d5c34..ef8ba9dff 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -148,8 +148,8 @@ def test_no_data(self) -> None: with pytest.raises( NoDataError, match=( - r"^The data file or directory `(.+?)` could not be found\. Perhaps `coverage " - r"combine` must be run first\.$" + r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " + r"combine' must be run first\.$" ) ): self.run_xml_report() From 42b02a1f3057bcf29bae421de84d89281d688a7b Mon Sep 17 00:00:00 2001 From: Bart Feenstra Date: Thu, 16 May 2024 19:27:37 +0100 Subject: [PATCH 3/3] Non-magic string concatenation --- tests/test_api.py | 6 +++--- tests/test_coverage.py | 6 +++--- tests/test_html.py | 2 +- tests/test_report.py | 6 +++--- tests/test_xml.py | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 63879e2b5..c07a48eb1 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -304,7 +304,7 @@ def test_empty_reporting(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): cov.report() @@ -456,7 +456,7 @@ def test_combining_twice(self) -> None: NoDataError, match=( r"^The data directory '(.+?)' does not contain any data files. Perhaps 'coverage " - r"combine' must be run first.$" + + r"combine' must be run first.$" ) ): cov2.combine(strict=True, keep=False) @@ -1392,7 +1392,7 @@ def test_combine_no_usable_files(self) -> None: NoDataError, match=( r"^The following data files are unusable, perhaps because they do not contain " - r"valid coverage information:\n- '(.+?)'\n- '(.+?)'$" + + r"valid coverage information:\n- '(.+?)'\n- '(.+?)'$" ) ): cov.combine(strict=True) diff --git a/tests/test_coverage.py b/tests/test_coverage.py index a5264277b..051a6c217 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -1639,7 +1639,7 @@ def test_no_data_to_report_on_annotate(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): self.command_line("annotate -d ann") @@ -1652,7 +1652,7 @@ def test_no_data_to_report_on_html(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): self.command_line("html -d htmlcov") @@ -1664,7 +1664,7 @@ def test_no_data_to_report_on_xml(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): self.command_line("xml") diff --git a/tests/test_html.py b/tests/test_html.py index 3a0865922..2767c0532 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -430,7 +430,7 @@ def test_dothtml_not_python(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): cov.html_report() diff --git a/tests/test_report.py b/tests/test_report.py index 393be02ea..c81fdfec3 100644 --- a/tests/test_report.py +++ b/tests/test_report.py @@ -555,7 +555,7 @@ def test_report_skip_covered_no_data(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): self.get_report(cov, skip_covered=True) @@ -754,7 +754,7 @@ def test_dotpy_not_python_ignored(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): with pytest.warns(Warning) as warns: @@ -777,7 +777,7 @@ def test_dothtml_not_python(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): self.get_report(cov, morfs=["mycode.html"]) diff --git a/tests/test_xml.py b/tests/test_xml.py index ef8ba9dff..15760bab7 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -149,7 +149,7 @@ def test_no_data(self) -> None: NoDataError, match=( r"^The data file or directory '(.+?)' could not be found\. Perhaps 'coverage " - r"combine' must be run first\.$" + + r"combine' must be run first\.$" ) ): self.run_xml_report()