From c3340b6d999d7b3a79e6ecb35c8c13a90216dc15 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Fri, 9 Jul 2021 17:01:12 +0100 Subject: [PATCH 1/4] Support TOML v1.0.0 syntax in `pyproject.toml` fixes #1180 Co-authored-by: Taneli Hukkinen <3275109+hukkin@users.noreply.github.com> --- coverage/tomlconfig.py | 12 ++++++------ setup.py | 2 +- tests/helpers.py | 2 +- tests/test_config.py | 8 ++++---- tests/test_testing.py | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/coverage/tomlconfig.py b/coverage/tomlconfig.py index 1e0b1241b..aa11a8a96 100644 --- a/coverage/tomlconfig.py +++ b/coverage/tomlconfig.py @@ -12,9 +12,9 @@ # TOML support is an install-time extra option. try: - import toml + import tomli except ImportError: # pragma: not covered - toml = None + tomli = None class TomlDecodeError(Exception): @@ -44,12 +44,12 @@ def read(self, filenames): toml_text = fp.read() except OSError: return [] - if toml: + if tomli is not None: toml_text = substitute_variables(toml_text, os.environ) try: - self.data = toml.loads(toml_text) - except toml.TomlDecodeError as err: - raise TomlDecodeError(*err.args) + self.data = tomli.loads(toml_text) + except tomli.TOMLDecodeError as err: + raise TomlDecodeError(str(err)) return [filename] else: has_toml = re.search(r"^\[tool\.coverage\.", toml_text, flags=re.MULTILINE) diff --git a/setup.py b/setup.py index da2df88fd..f6fb7b4eb 100644 --- a/setup.py +++ b/setup.py @@ -107,7 +107,7 @@ def better_set_verbosity(v): extras_require={ # Enable pyproject.toml support. - 'toml': ['toml'], + 'toml': ['tomli'], }, # We need to get HTML assets from our htmlfiles directory. diff --git a/tests/helpers.py b/tests/helpers.py index 3b0e12834..28adf78c7 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -242,7 +242,7 @@ def without_module(using_module, missing_module_name): Use this in a test function to make an optional module unavailable during the test:: - with without_module(product.something, 'toml'): + with without_module(product.something, 'tomli'): use_toml_somehow() Arguments: diff --git a/tests/test_config.py b/tests/test_config.py index a8b0ecef5..be0c3a402 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -715,7 +715,7 @@ def test_note_is_obsolete(self): def test_no_toml_installed_no_toml(self): # Can't read a toml file that doesn't exist. - with without_module(coverage.tomlconfig, 'toml'): + with without_module(coverage.tomlconfig, 'tomli'): msg = "Couldn't read 'cov.toml' as a config file" with pytest.raises(CoverageException, match=msg): coverage.Coverage(config_file="cov.toml") @@ -723,7 +723,7 @@ def test_no_toml_installed_no_toml(self): def test_no_toml_installed_explicit_toml(self): # Can't specify a toml config file if toml isn't installed. self.make_file("cov.toml", "# A toml file!") - with without_module(coverage.tomlconfig, 'toml'): + with without_module(coverage.tomlconfig, 'tomli'): msg = "Can't read 'cov.toml' without TOML support" with pytest.raises(CoverageException, match=msg): coverage.Coverage(config_file="cov.toml") @@ -735,7 +735,7 @@ def test_no_toml_installed_pyproject_toml(self): [tool.coverage.run] xyzzy = 17 """) - with without_module(coverage.tomlconfig, 'toml'): + with without_module(coverage.tomlconfig, 'tomli'): msg = "Can't read 'pyproject.toml' without TOML support" with pytest.raises(CoverageException, match=msg): coverage.Coverage() @@ -747,7 +747,7 @@ def test_no_toml_installed_pyproject_no_coverage(self): [tool.something] xyzzy = 17 """) - with without_module(coverage.tomlconfig, 'toml'): + with without_module(coverage.tomlconfig, 'tomli'): cov = coverage.Coverage() # We get default settings: assert not cov.config.timid diff --git a/tests/test_testing.py b/tests/test_testing.py index 7219ff0bc..f0b544b17 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -348,7 +348,7 @@ def _same_python_executable(e1, e2): def test_without_module(): toml1 = tomlconfig.toml - with without_module(tomlconfig, 'toml'): + with without_module(tomlconfig, 'tomli'): toml2 = tomlconfig.toml toml3 = tomlconfig.toml From 400eb4f7e82f341fc4e68029bed0af04815029d3 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Fri, 9 Jul 2021 18:34:51 +0100 Subject: [PATCH 2/4] fix toml meta test --- tests/test_testing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_testing.py b/tests/test_testing.py index f0b544b17..4699799ec 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -347,10 +347,10 @@ def _same_python_executable(e1, e2): def test_without_module(): - toml1 = tomlconfig.toml + toml1 = tomlconfig.tomli with without_module(tomlconfig, 'tomli'): - toml2 = tomlconfig.toml - toml3 = tomlconfig.toml + toml2 = tomlconfig.tomli + toml3 = tomlconfig.tomli assert toml1 is toml3 is not None assert toml2 is None From 771f0a808e1c01dbfc0a90cf45fa0e4ccad8abe6 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Fri, 9 Jul 2021 19:55:35 +0100 Subject: [PATCH 3/4] use pytest.mark.parametrize to narrow test failure --- tests/test_config.py | 45 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index be0c3a402..b01b5bb93 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -186,31 +186,28 @@ def test_parse_errors(self): with pytest.raises(CoverageException, match=msg): coverage.Coverage() - def test_toml_parse_errors(self): + @pytest.mark.parametrize("bad_config,msg", [ + ("[tool.coverage.run]\ntimid = \"maybe?\"\n", r"maybe[?]"), + ("[tool.coverage.run\n", r"Key group"), + ('[tool.coverage.report]\nexclude_lines = ["foo("]\n', + r"Invalid \[tool.coverage.report\].exclude_lines value u?'foo\(': " + r"(unbalanced parenthesis|missing \))"), + ('[tool.coverage.report]\npartial_branches = ["foo["]\n', + r"Invalid \[tool.coverage.report\].partial_branches value u?'foo\[': " + r"(unexpected end of regular expression|unterminated character set)"), + ('[tool.coverage.report]\npartial_branches_always = ["foo***"]\n', + r"Invalid \[tool.coverage.report\].partial_branches_always value " + r"u?'foo\*\*\*': " + r"multiple repeat"), + ('[tool.coverage.run]\nconcurrency="foo"', "not a list"), + ("[tool.coverage.report]\nprecision=1.23", "not an integer"), + ('[tool.coverage.report]\nfail_under="s"', "not a float"), + ]) + def test_toml_parse_errors(self, bad_config, msg): # Im-parsable values raise CoverageException, with details. - bad_configs_and_msgs = [ - ("[tool.coverage.run]\ntimid = \"maybe?\"\n", r"maybe[?]"), - ("[tool.coverage.run\n", r"Key group"), - ('[tool.coverage.report]\nexclude_lines = ["foo("]\n', - r"Invalid \[tool.coverage.report\].exclude_lines value u?'foo\(': " - r"(unbalanced parenthesis|missing \))"), - ('[tool.coverage.report]\npartial_branches = ["foo["]\n', - r"Invalid \[tool.coverage.report\].partial_branches value u?'foo\[': " - r"(unexpected end of regular expression|unterminated character set)"), - ('[tool.coverage.report]\npartial_branches_always = ["foo***"]\n', - r"Invalid \[tool.coverage.report\].partial_branches_always value " - r"u?'foo\*\*\*': " - r"multiple repeat"), - ('[tool.coverage.run]\nconcurrency="foo"', "not a list"), - ("[tool.coverage.report]\nprecision=1.23", "not an integer"), - ('[tool.coverage.report]\nfail_under="s"', "not a float"), - ] - - for bad_config, msg in bad_configs_and_msgs: - print("Trying %r" % bad_config) - self.make_file("pyproject.toml", bad_config) - with pytest.raises(CoverageException, match=msg): - coverage.Coverage() + self.make_file("pyproject.toml", bad_config) + with pytest.raises(CoverageException, match=msg): + coverage.Coverage() def test_environment_vars_in_config(self): # Config files can have $envvars in them. From 3a3b9c4708a55ca3c655c7df32f6fe99112979da Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Fri, 9 Jul 2021 20:44:13 +0100 Subject: [PATCH 4/4] Update tests/test_config.py Co-authored-by: Taneli Hukkinen <3275109+hukkin@users.noreply.github.com> --- tests/test_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_config.py b/tests/test_config.py index b01b5bb93..2bef500e6 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -188,7 +188,7 @@ def test_parse_errors(self): @pytest.mark.parametrize("bad_config,msg", [ ("[tool.coverage.run]\ntimid = \"maybe?\"\n", r"maybe[?]"), - ("[tool.coverage.run\n", r"Key group"), + ("[tool.coverage.run\n", None), ('[tool.coverage.report]\nexclude_lines = ["foo("]\n', r"Invalid \[tool.coverage.report\].exclude_lines value u?'foo\(': " r"(unbalanced parenthesis|missing \))"),