Skip to content

Commit f2deec1

Browse files
Ignore ill-formed INI files instead of crashing (#3213)
1 parent d216355 commit f2deec1

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

codespell_lib/_codespell.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
EX_OK = 0
119119
EX_USAGE = 64
120120
EX_DATAERR = 65
121+
EX_CONFIG = 78
121122

122123
# OPTIONS:
123124
#
@@ -586,7 +587,7 @@ def parse_options(
586587
used_cfg_files.append(cfg_file)
587588

588589
# Use config files
589-
config.read(cfg_files)
590+
config.read(used_cfg_files)
590591
if config.has_section("codespell"):
591592
# Build a "fake" argv list using option name and value.
592593
cfg_args = []
@@ -1021,7 +1022,14 @@ def _script_main() -> int:
10211022

10221023
def main(*args: str) -> int:
10231024
"""Contains flow control"""
1024-
options, parser, used_cfg_files = parse_options(args)
1025+
try:
1026+
options, parser, used_cfg_files = parse_options(args)
1027+
except configparser.Error as e:
1028+
print(
1029+
f"ERROR: ill-formed config file: {e.message}",
1030+
file=sys.stderr,
1031+
)
1032+
return EX_CONFIG
10251033

10261034
# Report used config files
10271035
if not options.quiet_level & QuietLevels.CONFIG_FILES:

codespell_lib/tests/test_basic.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,21 @@
1313
import pytest
1414

1515
import codespell_lib as cs_
16-
from codespell_lib._codespell import EX_DATAERR, EX_OK, EX_USAGE, uri_regex_def
16+
from codespell_lib._codespell import (
17+
EX_CONFIG,
18+
EX_DATAERR,
19+
EX_OK,
20+
EX_USAGE,
21+
uri_regex_def,
22+
)
1723

1824

1925
def test_constants() -> None:
2026
"""Test our EX constants."""
2127
assert EX_OK == 0
2228
assert EX_USAGE == 64
2329
assert EX_DATAERR == 65
30+
assert EX_CONFIG == 78
2431

2532

2633
class MainWrapper:
@@ -42,7 +49,7 @@ def main(
4249
assert frame is not None
4350
capsys = frame.f_locals["capsys"]
4451
stdout, stderr = capsys.readouterr()
45-
assert code in (EX_OK, EX_USAGE, EX_DATAERR)
52+
assert code in (EX_OK, EX_USAGE, EX_DATAERR, EX_CONFIG)
4653
if code == EX_DATAERR: # have some misspellings
4754
code = int(stderr.split("\n")[-2])
4855
elif code == EX_OK and count:
@@ -1028,7 +1035,7 @@ def test_uri_regex_def() -> None:
10281035
assert not uri_regex.findall(boilerplate % uri), uri
10291036

10301037

1031-
def test_quiet_option_32(
1038+
def test_quiet_level_32(
10321039
tmp_path: Path,
10331040
tmpdir: pytest.TempPathFactory,
10341041
capsys: pytest.CaptureFixture[str],
@@ -1057,6 +1064,27 @@ def test_quiet_option_32(
10571064
assert "setup.cfg" in stdout
10581065

10591066

1067+
def test_ill_formed_ini_config_file(
1068+
tmp_path: Path,
1069+
tmpdir: pytest.TempPathFactory,
1070+
capsys: pytest.CaptureFixture[str],
1071+
) -> None:
1072+
d = tmp_path / "files"
1073+
d.mkdir()
1074+
conf = str(tmp_path / "setup.cfg")
1075+
with open(conf, "w") as f:
1076+
# It should contain but lacks a section.
1077+
f.write("foobar =\n")
1078+
args = ("--config", conf)
1079+
1080+
# Should not raise a configparser.Error exception.
1081+
result = cs.main(str(d), *args, std=True)
1082+
assert isinstance(result, tuple)
1083+
code, _, stderr = result
1084+
assert code == 78
1085+
assert "ill-formed config file" in stderr
1086+
1087+
10601088
@pytest.mark.parametrize("kind", ("toml", "cfg"))
10611089
def test_config_toml(
10621090
tmp_path: Path,

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,6 @@ max-complexity = 45
143143
[tool.ruff.pylint]
144144
allow-magic-value-types = ["bytes", "int", "str",]
145145
max-args = 12
146-
max-branches = 48
147-
max-returns = 10
146+
max-branches = 49
147+
max-returns = 11
148148
max-statements = 111

0 commit comments

Comments
 (0)