Skip to content

Commit 12b4220

Browse files
Read additional args from file with with @<path>.
1 parent 0eff305 commit 12b4220

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,13 @@ instead of these invalid entries:
229229
230230
.. _tomli: https://pypi.org/project/tomli/
231231

232+
Reading arguments from file
233+
---------------------------
234+
235+
Additional arguments can be read from a file with ``@PATH``. Arguments are
236+
extracted using ``shlex.split()``.
237+
238+
232239
pre-commit hook
233240
---------------
234241

codespell_lib/_codespell.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import itertools
2424
import os
2525
import re
26+
import shlex
2627
import sys
2728
import textwrap
2829
from collections.abc import Iterable, Sequence
@@ -388,7 +389,27 @@ def _supports_ansi_colors() -> bool:
388389
def parse_options(
389390
args: Sequence[str],
390391
) -> tuple[argparse.Namespace, argparse.ArgumentParser, list[str]]:
391-
parser = argparse.ArgumentParser(formatter_class=NewlineHelpFormatter)
392+
# Split lines read from `@PATH` using shlex.split(), otherwise default
393+
# behaviour is to have one arg per line. See:
394+
# https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.convert_arg_line_to_args
395+
class ArgumentParser2(argparse.ArgumentParser):
396+
def convert_arg_line_to_args(self, arg_line: str) -> list[str]:
397+
if sys.platform == "win32":
398+
# On Windows, shlex.split() seems to be messed up by back
399+
# slashes. Temporarily changing them to forward slashes seems
400+
# to make things work better.
401+
arg_line = arg_line.replace("\\", "/")
402+
ret = shlex.split(arg_line)
403+
ret = [p.replace("/", "\\") for p in ret]
404+
else:
405+
ret = shlex.split(arg_line)
406+
return ret
407+
408+
parser = ArgumentParser2(
409+
formatter_class=NewlineHelpFormatter,
410+
fromfile_prefix_chars="@",
411+
epilog="Use @PATH to read additional arguments from file PATH.",
412+
)
392413

393414
parser.set_defaults(colors=_supports_ansi_colors())
394415
parser.add_argument("--version", action="version", version=VERSION)

codespell_lib/tests/test_basic.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,3 +1458,39 @@ def test_stdin(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
14581458
code, stdout, _ = result
14591459
assert stdout == "1: Thsi ==> This\n"
14601460
assert code == 1
1461+
1462+
1463+
def test_args_from_file(
1464+
tmp_path: Path,
1465+
capsys: pytest.CaptureFixture[str],
1466+
) -> None:
1467+
import textwrap
1468+
1469+
print()
1470+
fname1 = tmp_path / "tmp1"
1471+
fname2 = tmp_path / "tmp2"
1472+
fname3 = tmp_path / "tmp3"
1473+
fname_list = tmp_path / "tmp_list"
1474+
fname_list.write_text(f"{fname1} {fname2}\n{fname3}")
1475+
fname1.write_text("abandonned\ncode")
1476+
fname2.write_text("exmaple\n")
1477+
fname3.write_text("abilty\n")
1478+
print(f"{fname_list=}")
1479+
args = ["codespell", f"@{fname_list}"]
1480+
print(f"Running: {args=}")
1481+
cp = subprocess.run( # noqa: S603
1482+
args,
1483+
check=False,
1484+
text=True,
1485+
capture_output=True,
1486+
)
1487+
code = cp.returncode
1488+
stdout = cp.stdout
1489+
stderr = cp.stderr
1490+
print(f"{code=}")
1491+
print(f"stdout:\n{textwrap.indent(stdout, ' ')}")
1492+
print(f"stderr:\n{textwrap.indent(stderr, ' ')}")
1493+
assert "tmp1:1: abandonned ==> abandoned\n" in stdout, f"{stdout=}"
1494+
assert "tmp2:1: exmaple ==> example\n" in stdout, f"{stdout=}"
1495+
assert "tmp3:1: abilty ==> ability\n" in stdout, f"{stdout=}"
1496+
assert code, f"{code=}"

0 commit comments

Comments
 (0)