Skip to content

Commit fd03b89

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

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: 24 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,29 @@ 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+
393+
# Split lines read from `@PATH` using shlex.split(), otherwise default
394+
# behaviour is to have one arg per line. See:
395+
# https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.convert_arg_line_to_args
396+
class ArgumentParser(argparse.ArgumentParser):
397+
def convert_arg_line_to_args(self, arg_line: str
398+
) -> list[str]:
399+
if sys.platform == "win32":
400+
# On Windows, shlex.split() seems to be messed up by back
401+
# slashes. Temporarily changing them to forward slashes seems
402+
# to make things work better.
403+
arg_line = arg_line.replace("\\", "/")
404+
ret = shlex.split(arg_line)
405+
ret = [p.replace("/", "\\") for p in ret]
406+
else:
407+
ret = shlex.split(arg_line)
408+
return ret
409+
410+
parser = ArgumentParser(
411+
formatter_class=NewlineHelpFormatter,
412+
fromfile_prefix_chars="@",
413+
epilog="Use @PATH to read additional arguments from file PATH.",
414+
)
392415

393416
parser.set_defaults(colors=_supports_ansi_colors())
394417
parser.add_argument("--version", action="version", version=VERSION)

codespell_lib/tests/test_basic.py

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

0 commit comments

Comments
 (0)