Skip to content

Commit bedd7e6

Browse files
committed
🐛 fix(prog): propagate :prog: override to subcommands
When using the :prog: directive option to rename the program, only the top-level parser prog was updated. Subcommand parsers still retained the original prog, producing inconsistent titles and references. Recursively updates all subparser prog values when :prog: is set. Fixes #71
1 parent 0790dd2 commit bedd7e6

5 files changed

Lines changed: 41 additions & 1 deletion

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from __future__ import annotations
2+
3+
import sys
4+
from pathlib import Path
5+
6+
sys.path.insert(0, str(Path(__file__).parent))
7+
extensions = ["sphinx_argparse_cli"]
8+
nitpicky = True
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.. sphinx_argparse_cli::
2+
:module: parser
3+
:func: make
4+
:prog: my-tool
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from __future__ import annotations
2+
3+
from argparse import ArgumentParser
4+
5+
6+
def make() -> ArgumentParser:
7+
parser = ArgumentParser(prog="original-name")
8+
sub = parser.add_subparsers()
9+
sub.add_parser("foo", help="foo help")
10+
return parser

src/sphinx_argparse_cli/_logic.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ def parser(self) -> ArgumentParser:
140140
raise self.error(msg)
141141

142142
if "prog" in self.options:
143-
self._parser.prog = self.options["prog"]
143+
old_prog, new_prog = self._parser.prog, self.options["prog"]
144+
self._parser.prog = new_prog
145+
_update_sub_parser_prog(self._parser, old_prog, new_prog)
144146

145147
self._raw_format = self._parser.formatter_class == RawDescriptionHelpFormatter
146148
return self._parser
@@ -447,6 +449,15 @@ def _strip_ansi_colors(text: str) -> str: # pragma: >=3.14 cover
447449
return _ANSI_COLOR_RE.sub("", text)
448450

449451

452+
def _update_sub_parser_prog(parser: ArgumentParser, old_prog: str, new_prog: str) -> None:
453+
if not (sub_parsers := parser._subparsers): # noqa: SLF001
454+
return
455+
sub_action: _SubParsersAction[ArgumentParser] = sub_parsers._group_actions[0] # type: ignore[assignment] # noqa: SLF001
456+
for sub_parser in sub_action.choices.values():
457+
sub_parser.prog = sub_parser.prog.replace(old_prog, new_prog, 1)
458+
_update_sub_parser_prog(sub_parser, old_prog, new_prog)
459+
460+
450461
__all__ = [
451462
"SphinxArgparseCli",
452463
]

tests/test_logic.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,10 @@ def test_actions(build_outcome: str) -> None:
381381
assert "increase verbosity" in build_outcome
382382
assert "paths to include" in build_outcome
383383
assert "a required optional argument" in build_outcome
384+
385+
386+
@pytest.mark.sphinx(buildername="text", testroot="prog-subcommands")
387+
def test_prog_subcommands(build_outcome: str) -> None:
388+
assert "my-tool" in build_outcome
389+
assert "original-name" not in build_outcome
390+
assert "my-tool foo" in build_outcome

0 commit comments

Comments
 (0)