Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise exception on invalid toml configuration #4165

Merged
merged 11 commits into from Jan 26, 2024
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -29,6 +29,7 @@

<!-- Changes to how Black can be configured -->

- Raise an error when toml config contains an invalid key (#4165)
- Fix symlink handling, properly catch and ignore symlinks that point outside of root
(#4161)
- Fix cache mtime logic that resulted in false positive cache hits (#4128)
Expand Down
14 changes: 14 additions & 0 deletions src/black/__init__.py
Expand Up @@ -117,6 +117,10 @@ def from_configuration(
FileMode = Mode


class InvalidConfigKey(Exception):
"""Invalid configuration key found in pyproject toml."""


def read_pyproject_toml(
ctx: click.Context, param: click.Parameter, value: Optional[str]
) -> Optional[str]:
Expand All @@ -142,6 +146,7 @@ def read_pyproject_toml(
if not config:
return None
else:
spellcheck_pyproject_toml_keys(ctx, list(config), value)
# Sanitize the values to be Click friendly. For more information please see:
# https://github.com/psf/black/issues/1458
# https://github.com/pallets/click/issues/1567
Expand Down Expand Up @@ -181,6 +186,15 @@ def read_pyproject_toml(
return value


def spellcheck_pyproject_toml_keys(
ctx: click.Context, config_keys: List[str], config_file_path: str
) -> None:
available_config_options = {param.name for param in ctx.command.params}
for key in config_keys:
if key not in available_config_options:
raise InvalidConfigKey(f"Invalid key {key} in {config_file_path}")
dankrzeminski32 marked this conversation as resolved.
Show resolved Hide resolved


def target_version_option_callback(
c: click.Context, p: Union[click.Option, click.Parameter], v: Tuple[str, ...]
) -> List[TargetVersion]:
Expand Down
2 changes: 2 additions & 0 deletions tests/data/incorrect_spelling.toml
@@ -0,0 +1,2 @@
[tool.black]
ine_length = 50
12 changes: 12 additions & 0 deletions tests/test_black.py
Expand Up @@ -106,6 +106,7 @@ class FakeContext(click.Context):
def __init__(self) -> None:
self.default_map: Dict[str, Any] = {}
self.params: Dict[str, Any] = {}
self.command: click.Command = black.main
# Dummy root, since most of the tests don't care about it
self.obj: Dict[str, Any] = {"root": PROJECT_ROOT}

Expand Down Expand Up @@ -1538,6 +1539,17 @@ def test_parse_pyproject_toml(self) -> None:
self.assertEqual(config["exclude"], r"\.pyi?$")
self.assertEqual(config["include"], r"\.py?$")

def test_spellcheck_pyproject_toml(self) -> None:
test_toml_file = THIS_DIR / "data" / "incorrect_spelling.toml"
with pytest.raises(black.InvalidConfigKey) as exc_info:
self.invokeBlack(
["print('hello world')", "--verbose", "--config", str(test_toml_file)],
exit_code=123,
ignore_config=False,
)

exc_info.match(f"Invalid key ine_length in {re.escape(str(test_toml_file))}")

def test_parse_pyproject_toml_project_metadata(self) -> None:
for test_toml, expected in [
("only_black_pyproject.toml", ["py310"]),
Expand Down