Skip to content

Commit 92e4542

Browse files
committed
🐛 fix: hook parse_intermixed_args as well
Since Python 3.12 parse_known_intermixed_args calls _parse_known_args2 directly, so a factory ending in parse_intermixed_args() skipped the :hook: monkeypatch, parsed Sphinx's argv and exited the build. Patch parse_known_intermixed_args alongside parse_known_args, through one patch.object context manager that restores both on any exception.
1 parent 3cfee42 commit 92e4542

6 files changed

Lines changed: 50 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
99
- Add `force_refs_lower` to enable `:ref:` links with mixed-case program names and arguments.
1010
- Fix Sphinx smart quotes rewriting `--` to an en dash in `--option` names within descriptions, epilogs, and help text.
1111
- Register flags and positional arguments as Sphinx program options so the `:option:` role links to them.
12+
- Make `:hook:` intercept `parse_intermixed_args()` as well as `parse_args()`.
1213

1314
## 1.13.1
1415

roots/test-hook-intermixed/conf.py

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: main
4+
:hook:
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 main() -> None:
7+
parser = ArgumentParser(prog="foo", add_help=False)
8+
parser.add_argument("--flag", help="a flag")
9+
args = parser.parse_intermixed_args()
10+
print(args) # noqa: T201

src/sphinx_argparse_cli/_logic.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,15 @@ def parser(self) -> ArgumentParser:
9494
raise self.error(msg) # noqa: B904
9595
parser: ArgumentParser | None = None
9696
if "hook" in self.options:
97-
original_parse_known_args = ArgumentParser.parse_known_args
98-
ArgumentParser.parse_known_args = _parse_known_args_hook # type: ignore[method-assign,assignment]
99-
try:
100-
parser_creator()
101-
except HookError as hooked:
102-
parser = hooked.parser
103-
finally:
104-
ArgumentParser.parse_known_args = original_parse_known_args
97+
# parse_intermixed_args bypasses parse_known_args since Python 3.12, so both entry points need the hook
98+
with (
99+
patch.object(ArgumentParser, "parse_known_args", _parse_known_args_hook),
100+
patch.object(ArgumentParser, "parse_known_intermixed_args", _parse_known_args_hook),
101+
):
102+
try:
103+
parser_creator()
104+
except HookError as hooked:
105+
parser = hooked.parser
105106
else:
106107
parser = parser_creator()
107108

tests/test_logic.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,24 @@ def test_hook(build_outcome: str) -> None:
7070
assert build_outcome
7171

7272

73+
@pytest.mark.sphinx(buildername="text", testroot="hook-intermixed")
74+
def test_hook_intermixed(build_outcome: str) -> None:
75+
assert (
76+
build_outcome
77+
== """foo - CLI interface
78+
*******************
79+
80+
foo [--flag FLAG]
81+
82+
83+
foo options
84+
===========
85+
86+
* **"--flag"** "FLAG" - a flag
87+
"""
88+
)
89+
90+
7391
@pytest.mark.sphinx(buildername="text", testroot="hook-fail")
7492
def test_hook_fail(app: SphinxTestApp, warning: StringIO) -> None:
7593
app.build()

0 commit comments

Comments
 (0)