Skip to content

Commit

Permalink
Improve pyproject.toml validation messages
Browse files Browse the repository at this point in the history
Based on the following discussions:

- pypa/packaging.python.org#1031 (comment)
- pypa/packaging-problems#604

it seems that people are having a hard time finding information about
validation error due to the long traceback and debug info.

The idea behind this change is to make the most relevant information
to fix the error easier to spot.
  • Loading branch information
abravalheri committed Aug 4, 2022
1 parent 3181239 commit 9f57e70
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 22 deletions.
12 changes: 8 additions & 4 deletions setuptools/config/pyprojecttoml.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,14 @@ def validate(config: dict, filepath: _Path) -> bool:
try:
return validator.validate(config)
except validator.ValidationError as ex:
_logger.error(f"configuration error: {ex.summary}") # type: ignore
_logger.debug(ex.details) # type: ignore
error = ValueError(f"invalid pyproject.toml config: {ex.name}") # type: ignore
raise error from None
summary = f"configuration error: {ex.summary}"
if ex.name.strip("`") != "project":
# Probably it is just a field missing/misnamed, not worthy the verbosity...
_logger.debug(summary)
_logger.debug(ex.details)

error = f"invalid pyproject.toml config: {ex.name}."
raise ValueError(f"{error}\n{summary}") from None


def apply_configuration(
Expand Down
23 changes: 5 additions & 18 deletions setuptools/tests/config/test_pyprojecttoml.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import logging
import re
from configparser import ConfigParser
from inspect import cleandoc
Expand Down Expand Up @@ -307,7 +306,7 @@ def test_ignore_unrelated_config(tmp_path, example):


@pytest.mark.parametrize(
"example, error_msg, value_shown_in_debug",
"example, error_msg",
[
(
"""
Expand All @@ -316,30 +315,18 @@ def test_ignore_unrelated_config(tmp_path, example):
version = "1.2"
requires = ['pywin32; platform_system=="Windows"' ]
""",
"configuration error: `project` must not contain {'requires'} properties",
'"requires": ["pywin32; platform_system==\\"Windows\\""]',
"configuration error: .project. must not contain ..requires.. properties",
),
],
)
def test_invalid_example(tmp_path, caplog, example, error_msg, value_shown_in_debug):
caplog.set_level(logging.DEBUG)
def test_invalid_example(tmp_path, example, error_msg):
pyproject = tmp_path / "pyproject.toml"
pyproject.write_text(cleandoc(example))

caplog.clear()
with pytest.raises(ValueError, match="invalid pyproject.toml"):
pattern = re.compile(f"invalid pyproject.toml.*{error_msg}.*", re.M | re.S)
with pytest.raises(ValueError, match=pattern):
read_configuration(pyproject)

# Make sure the logs give guidance to the user
error_log = caplog.record_tuples[0]
assert error_log[1] == logging.ERROR
assert error_msg in error_log[2]

debug_log = caplog.record_tuples[1]
assert debug_log[1] == logging.DEBUG
debug_msg = "".join(line.strip() for line in debug_log[2].splitlines())
assert value_shown_in_debug in debug_msg


@pytest.mark.parametrize("config", ("", "[tool.something]\nvalue = 42"))
def test_empty(tmp_path, config):
Expand Down

0 comments on commit 9f57e70

Please sign in to comment.