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 @@ -14,6 +14,8 @@ All notable changes to this project will be documented in this file.
- Make `:hook:` intercept `parse_intermixed_args()` as well as `parse_args()`.
- Keep ANSI color codes out of usage blocks when `PYTHON_COLORS=1` is set on Python 3.14 or newer.
- Skip sub-commands added with `help=argparse.SUPPRESS` instead of rendering them with a `==SUPPRESS==` description.
- Use the description, or `arguments`, as the heading of an argument group without a title instead of rendering `None`
and emitting duplicate label warnings.

## 1.13.1

Expand Down
8 changes: 8 additions & 0 deletions roots/test-group-untitled/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-group-untitled/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.. sphinx_argparse_cli::
:module: parser
:func: make
11 changes: 11 additions & 0 deletions roots/test-group-untitled/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from __future__ import annotations

from argparse import ArgumentParser


def make() -> ArgumentParser:
parser = ArgumentParser(prog="tool")
parser.add_argument_group(description="only a description").add_argument("--x", help="x help")
parser.add_argument_group(description="another").add_argument("--y", help="y help")
parser.add_argument_group().add_argument("--z", help="z help")
return parser
14 changes: 7 additions & 7 deletions src/sphinx_argparse_cli/_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,15 @@ def _pre_format(self, block: str | None) -> paragraph | literal_block | None:
def _mk_option_group(self, group: _ArgumentGroup, prefix: str, prog: str) -> section:
sub_title_prefix: str = self.options.get("group_sub_title_prefix")
title_prefix = self.options.get("group_title_prefix")
title_text = self._build_opt_grp_title(group, prefix, prog, sub_title_prefix, title_prefix)
title_ref: str = f"{prefix}{' ' if prefix else ''}{group.title}"
# an untitled group borrows its description as heading so its anchor stays unique
group_title = group.title or group.description or "arguments"
title_text = self._build_opt_grp_title(group_title, prefix, prog, sub_title_prefix, title_prefix)
title_ref: str = f"{prefix}{' ' if prefix else ''}{group_title}"
ref_id = self._make_id(title_ref)
# the text sadly needs to be prefixed, because otherwise the autosectionlabel will conflict
header = title("", Text(title_text))
group_section = section("", header, ids=[ref_id], names=[ref_id])
if description := self._pre_format(group.description):
if group.title and (description := self._pre_format(group.description)):
group_section += description
self._register_ref(ref_id, title_text, group_section)
opt_group = bullet_list()
Expand All @@ -230,12 +232,10 @@ def _mk_option_group(self, group: _ArgumentGroup, prefix: str, prog: str) -> sec
return group_section

def _build_opt_grp_title(
self, group: _ArgumentGroup, prefix: str, prog: str, sub_title_prefix: str, title_prefix: str
self, group_title: str, prefix: str, prog: str, sub_title_prefix: str, title_prefix: str
) -> str:
sub_cmd = prefix[len(prog) :].strip() or None if prefix != prog else None
title_text = self._resolve_prefix(prog, sub_cmd, prefix, title_prefix, sub_title_prefix)
title_text += group.title or ""
return title_text
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:
line = paragraph()
Expand Down
13 changes: 13 additions & 0 deletions tests/test_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,19 @@ def test_usage_ignores_python_colors(build_outcome: str) -> None:
)


@pytest.mark.sphinx(buildername="html", testroot="group-untitled")
def test_group_untitled(build_outcome: str, warning: StringIO) -> None:
headings = re.findall(r'<h2>(.*?)<a class="headerlink" href="(#[^"]+)"', build_outcome)
assert headings == [
("tool options", "#tool-options"),
("tool only a description", "#tool-only-a-description"),
("tool another", "#tool-another"),
("tool arguments", "#tool-arguments"),
]
assert "<p>only a description</p>" not in build_outcome
assert not warning.getvalue()


@pytest.mark.sphinx(buildername="text", testroot="ref-duplicate-label")
def test_ref_duplicate_label(build_outcome: tuple[str, str], warning: StringIO) -> None:
assert build_outcome
Expand Down