Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,9 @@ If several config files are present, they are read in the following order:

If a codespell configuration is supplied in several of these files,
the configuration from the most recently read file overwrites previously
specified configurations. Any options specified in the command line will
specified configurations. A warning is printed when both ``pyproject.toml``
and ``.codespellrc`` contain codespell settings, since only the latter is
used. Any options specified in the command line will
*override* options from the config files.

Values in a config file entry cannot start with a ``-`` character, so if
Expand Down
19 changes: 15 additions & 4 deletions codespell_lib/_codespell.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ def convert_arg_line_to_args(self, arg_line: str) -> list[str]:

# Read toml before other config files.
toml_files = []
used_toml_files = []
tomllib_raise_error = False
if os.path.isfile("pyproject.toml"):
toml_files.append("pyproject.toml")
Expand Down Expand Up @@ -721,17 +722,20 @@ def convert_arg_line_to_args(self, arg_line: str) -> list[str]:
msg = f"{toml_file}: [tool.codespell] must be a table"
raise configparser.Error(msg)
config.read_dict({"codespell": _toml_to_parseconfig(data)})
if toml_file not in used_toml_files:
used_toml_files.append(toml_file)

# Collect which config files are going to be used
used_cfg_files = []
used_ini_files = []
for cfg_file in cfg_files:
_cfg = configparser.ConfigParser()
_cfg.read(cfg_file)
if _cfg.has_section("codespell"):
used_cfg_files.append(cfg_file)
used_ini_files.append(cfg_file)

# Use config files
config.read(used_cfg_files)
# Use INI config files (TOML was already applied above)
config.read(used_ini_files)
used_cfg_files = used_toml_files + used_ini_files
if config.has_section("codespell"):
# Build a "fake" argv list using option name and value.
cfg_args = []
Expand Down Expand Up @@ -1411,6 +1415,13 @@ def main(*args: str) -> int:

# Report used config files
if not options.quiet_level & QuietLevels.CONFIG_FILES:
used_basenames = {os.path.basename(cfg_file) for cfg_file in used_cfg_files}
if "pyproject.toml" in used_basenames and ".codespellrc" in used_basenames:
print(
"WARNING: both pyproject.toml and .codespellrc contain "
"codespell settings; .codespellrc takes precedence",
file=sys.stderr,
)
if len(used_cfg_files) > 0:
print("Used config files:")
for ifile, cfg_file in enumerate(used_cfg_files, start=1):
Expand Down
40 changes: 40 additions & 0 deletions codespell_lib/tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,46 @@ def test_config_toml_codespell_array(
assert "[tool.codespell] must be a table" in stderr


def test_warn_both_pyproject_and_codespellrc(
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
) -> None:
if sys.version_info < (3, 11):
pytest.importorskip("tomli")
(tmp_path / "pyproject.toml").write_text("[tool.codespell]\nquiet-level = 2\n")
(tmp_path / ".codespellrc").write_text("[codespell]\nquiet-level = 2\n")
(tmp_path / "ok.txt").write_text("ok\n")

warning = (
"WARNING: both pyproject.toml and .codespellrc contain "
"codespell settings; .codespellrc takes precedence"
)
cwd = Path.cwd()
try:
os.chdir(tmp_path)
result = cs.main(std=True)
finally:
os.chdir(cwd)
assert isinstance(result, tuple)
code, stdout, stderr = result
assert code == 0
assert warning in stderr
assert "Used config files:" in stdout
assert "pyproject.toml" in stdout
assert ".codespellrc" in stdout

try:
os.chdir(tmp_path)
result = cs.main("--quiet-level=32", std=True)
finally:
os.chdir(cwd)
assert isinstance(result, tuple)
code, stdout, stderr = result
assert code == 0
assert warning not in stderr
assert "Used config files:" not in stdout


@contextlib.contextmanager
def FakeStdin(text: str) -> Generator[None, None, None]:
oldin = sys.stdin
Expand Down
Loading