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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ All notable changes to this project will be documented in this file.
whose arguments are all suppressed.
- Keep `RawDescriptionHelpFormatter` line breaks in epilogs and in descriptions rendered after the usage block, and
render sub-command epilogs.
- Render the argument spec after an option with argparse's formatter, so `nargs`, `choices` and tuple metavars show as
in the usage line; user-supplied metavars keep their case instead of being upper-cased.

## 1.13.1

Expand Down
8 changes: 8 additions & 0 deletions roots/test-nargs-metavar/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from __future__ import annotations

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))
extensions = ["sphinx_argparse_cli"]
nitpicky = True
3 changes: 3 additions & 0 deletions roots/test-nargs-metavar/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.. sphinx_argparse_cli::
:module: parser
:func: make
16 changes: 16 additions & 0 deletions roots/test-nargs-metavar/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import annotations

from argparse import REMAINDER, ArgumentParser


def make() -> ArgumentParser:
parser = ArgumentParser(prog="tool", add_help=False)
parser.add_argument("--opt", nargs="?", help="optional value")
parser.add_argument("--many", nargs="*", help="zero or more")
parser.add_argument("--two", nargs=2, help="exactly two")
parser.add_argument("--rest", nargs=REMAINDER, help="the rest")
parser.add_argument("--out", metavar="<file>", help="output")
parser.add_argument("--dir", metavar="path/to/dir", help="dir")
parser.add_argument("--format", choices=["json", "xml"], help="output format")
parser.add_argument("pair", nargs=2, metavar=("SRC", "DST"), help="copy pair")
return parser
28 changes: 15 additions & 13 deletions src/sphinx_argparse_cli/_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def _mk_option_group(
self._register_ref(ref_id, title_text, group_section)
opt_group = bullet_list()
for action in actions:
opt_group += self._mk_option_line(action, prefix)
opt_group += self._mk_option_line(parser, action, prefix)
group_section += opt_group
return group_section

Expand All @@ -230,26 +230,22 @@ def _build_opt_grp_title(
sub_cmd = prefix[len(prog) :].strip() or None if prefix != prog else None
return self._resolve_prefix(prog, sub_cmd, prefix, title_prefix, sub_title_prefix) + group_title

def _mk_option_line(self, action: Action, prefix: str) -> list_item:
def _mk_option_line(self, parser: ArgumentParser, action: Action, prefix: str) -> list_item:
line = paragraph()
as_key = action.dest
if action.metavar:
as_key = action.metavar if isinstance(action.metavar, str) else action.metavar[0]
if action.option_strings:
args_text = _format_args(parser, action) if action.nargs != 0 else None
for at, opt in enumerate(action.option_strings):
if at:
line += Text(", ")
self._mk_option_name(line, prefix, opt)
if action.nargs != 0:
if args_text is not None:
line += Text(" ")
metavar_text = (
" ".join(meta.upper() for meta in action.metavar)
if isinstance(action.metavar, tuple)
else as_key.upper()
)
line += literal(text=metavar_text)
line += literal(text=args_text)
else:
self._mk_option_name(line, prefix, as_key)
metavar = action.metavar
self._mk_option_name(
line, prefix, " ".join(metavar) if isinstance(metavar, tuple) else metavar or action.dest
)

extra: Sequence[Node] = ()
if action.help:
Expand Down Expand Up @@ -402,6 +398,12 @@ def _no_color(self) -> Iterator[None]:
yield


def _format_args(parser: ArgumentParser, action: Action) -> str:
# argparse's formatter keeps the text in step with the usage line: nargs, choices and user metavars included
formatter = parser._get_formatter() # noqa: SLF001
return formatter._format_args(action, formatter._get_default_metavar_for_optional(action)) # noqa: SLF001


def make_id_lower(key: str) -> str:
return re.sub("[A-Z]", lambda m: f"_{m.group(0).lower()}", make_id(key))

Expand Down
2 changes: 1 addition & 1 deletion tests/complex.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ complex options

* **"--no-help"**

* **"--outdir"** "OUT_DIR", **"-o"** "OUT_DIR" - output directory
* **"--outdir"** "out_dir", **"-o"** "out_dir" - output directory

* **"--in-dir"** "IN_DIR", **"-i"** "IN_DIR" - input directory

Expand Down
2 changes: 1 addition & 1 deletion tests/complex_pre_310.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ complex optional arguments

* **"--no-help"**

* **"--outdir"** "OUT_DIR", **"-o"** "OUT_DIR" - output directory
* **"--outdir"** "out_dir", **"-o"** "out_dir" - output directory

* **"--in-dir"** "IN_DIR", **"-i"** "IN_DIR" - input directory

Expand Down
38 changes: 38 additions & 0 deletions tests/test_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,44 @@ def test_nargs(build_outcome: str) -> None:
assert 'default: "None"' not in build_outcome


@pytest.mark.sphinx(buildername="text", testroot="nargs-metavar")
def test_nargs_metavar(build_outcome: str) -> None:
assert (
build_outcome
== """tool - CLI interface
********************

tool [--opt [OPT]] [--many [MANY ...]] [--two TWO TWO] [--rest ...] [--out <file>]
[--dir path/to/dir] [--format {json,xml}]
SRC DST


tool positional arguments
=========================

* **"SRC DST"** - copy pair


tool options
============

* **"--opt"** "[OPT]" - optional value

* **"--many"** "[MANY ...]" - zero or more

* **"--two"** "TWO TWO" - exactly two

* **"--rest"** "..." - the rest

* **"--out"** "<file>" - output

* **"--dir"** "path/to/dir" - dir

* **"--format"** "{json,xml}" - output format
"""
)


@pytest.mark.sphinx(buildername="text", testroot="choices")
def test_choices(build_outcome: str) -> None:
assert "output format" in build_outcome
Expand Down