sphinx-argparse-cli 1.21.3__tar.gz → 1.22.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sphinx-argparse-cli
3
- Version: 1.21.3
3
+ Version: 1.22.0
4
4
  Summary: render CLI arguments (sub-commands friendly) defined by argparse module
5
5
  Project-URL: Documentation, https://github.com/tox-dev/sphinx-argparse-cli#sphinx-argparse-cli
6
6
  Project-URL: Homepage, https://github.com/tox-dev/sphinx-argparse-cli
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
24
  Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Programming Language :: Python :: 3.15
25
26
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
27
  Classifier: Topic :: Documentation
27
28
  Classifier: Topic :: Documentation :: Sphinx
@@ -63,7 +64,7 @@ Use the directive in any reStructuredText file:
63
64
  ```
64
65
 
65
66
  `:module:` points to the Python module containing the parser, and `:func:` names a zero-argument function that returns
66
- an `ArgumentParser`. Build your docs and the full CLI reference appears automatically.
67
+ an `ArgumentParser`. Build your docs and the full CLI reference appears.
67
68
 
68
69
  ## How-to guides
69
70
 
@@ -129,7 +130,7 @@ Set the character width for usage lines and optionally show usage before the des
129
130
 
130
131
  ### Override title, description, or epilog
131
132
 
132
- Replace auto-detected values, or pass an empty string to suppress them entirely:
133
+ Replace auto-detected values, or pass an empty string to suppress them:
133
134
 
134
135
  ```rst
135
136
  .. sphinx_argparse_cli::
@@ -166,7 +167,7 @@ The anchor text is visible after the `#` in the URL when you click a heading.
166
167
  ### Handle mixed-case references
167
168
 
168
169
  Sphinx `:ref:` only supports lower-case targets. When your program name or flags contain capital letters, set
169
- `:force_refs_lower:` to convert them — each upper-case letter becomes its lower-case form prefixed with `_` (e.g. `A`
170
+ `:force_refs_lower:` to convert them. Each upper-case letter becomes its lower-case form prefixed with `_` (e.g. `A`
170
171
  becomes `_a`):
171
172
 
172
173
  ```rst
@@ -32,7 +32,7 @@ Use the directive in any reStructuredText file:
32
32
  ```
33
33
 
34
34
  `:module:` points to the Python module containing the parser, and `:func:` names a zero-argument function that returns
35
- an `ArgumentParser`. Build your docs and the full CLI reference appears automatically.
35
+ an `ArgumentParser`. Build your docs and the full CLI reference appears.
36
36
 
37
37
  ## How-to guides
38
38
 
@@ -98,7 +98,7 @@ Set the character width for usage lines and optionally show usage before the des
98
98
 
99
99
  ### Override title, description, or epilog
100
100
 
101
- Replace auto-detected values, or pass an empty string to suppress them entirely:
101
+ Replace auto-detected values, or pass an empty string to suppress them:
102
102
 
103
103
  ```rst
104
104
  .. sphinx_argparse_cli::
@@ -135,7 +135,7 @@ The anchor text is visible after the `#` in the URL when you click a heading.
135
135
  ### Handle mixed-case references
136
136
 
137
137
  Sphinx `:ref:` only supports lower-case targets. When your program name or flags contain capital letters, set
138
- `:force_refs_lower:` to convert them — each upper-case letter becomes its lower-case form prefixed with `_` (e.g. `A`
138
+ `:force_refs_lower:` to convert them. Each upper-case letter becomes its lower-case form prefixed with `_` (e.g. `A`
139
139
  becomes `_a`):
140
140
 
141
141
  ```rst
@@ -2,7 +2,7 @@
2
2
  build-backend = "hatchling.build"
3
3
  requires = [
4
4
  "hatch-vcs>=0.5",
5
- "hatchling>=1.28",
5
+ "hatchling>=1.30.1",
6
6
  ]
7
7
 
8
8
  [project]
@@ -31,6 +31,7 @@ classifiers = [
31
31
  "Programming Language :: Python :: 3.12",
32
32
  "Programming Language :: Python :: 3.13",
33
33
  "Programming Language :: Python :: 3.14",
34
+ "Programming Language :: Python :: 3.15",
34
35
  "Programming Language :: Python :: Implementation :: CPython",
35
36
  "Topic :: Documentation",
36
37
  "Topic :: Documentation :: Sphinx",
@@ -56,29 +57,29 @@ dev = [
56
57
  test = [
57
58
  "covdefaults>=2.3",
58
59
  "defusedxml>=0.7.1",
59
- "pytest>=9.0.2",
60
- "pytest-cov>=7",
60
+ "pytest>=9.1.1",
61
+ "pytest-cov>=7.1",
61
62
  ]
62
63
  type = [
63
- "ty>=0.0.17",
64
+ "ty<0.0.25,>=0.0.24",
64
65
  { include-group = "test" },
65
66
  ]
66
67
  lint = [
67
- "pre-commit-uv>=4.2",
68
+ "pre-commit-uv>=4.2.2",
68
69
  ]
69
70
  pkg-meta = [
70
71
  "check-wheel-contents>=0.6.3",
71
72
  "twine>=6.2",
72
- "uv>=0.10.2",
73
+ "uv>=0.11.26",
73
74
  ]
74
75
 
75
76
  [tool.hatch]
77
+ version.source = "vcs"
76
78
  build.hooks.vcs.version-file = "src/sphinx_argparse_cli/version.py"
77
79
  build.targets.sdist.include = [
78
80
  "/src",
79
81
  "/tests",
80
82
  ]
81
- version.source = "vcs"
82
83
 
83
84
  [tool.black]
84
85
  line-length = 120
@@ -128,7 +129,10 @@ builtin = "clear,usage,en-GB_to_en-US"
128
129
  count = true
129
130
 
130
131
  [tool.pyproject-fmt]
131
- max_supported_python = "3.14"
132
+ max_supported_python = "3.15"
133
+
134
+ [tool.ty]
135
+ environment.python-version = "3.14"
132
136
 
133
137
  [tool.coverage]
134
138
  run.parallel = true
@@ -143,6 +147,3 @@ paths.source = [
143
147
  report.fail_under = 100
144
148
  html.show_contexts = true
145
149
  html.skip_covered = false
146
-
147
- [tool.ty]
148
- environment.python-version = "3.14"
@@ -17,16 +17,18 @@ from argparse import (
17
17
  from collections import defaultdict
18
18
  from contextlib import contextmanager
19
19
  from pathlib import Path
20
- from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, cast
20
+ from typing import TYPE_CHECKING, Any, ClassVar, Final, cast
21
21
  from unittest.mock import patch
22
22
 
23
23
  from docutils.nodes import (
24
24
  Element,
25
+ FixedTextElement,
25
26
  Node,
26
27
  Text,
27
28
  bullet_list,
28
29
  container,
29
30
  fully_normalize_name,
31
+ inline,
30
32
  list_item,
31
33
  literal,
32
34
  literal_block,
@@ -48,22 +50,10 @@ if TYPE_CHECKING:
48
50
 
49
51
  from docutils.parsers.rst.states import RSTState, RSTStateMachine
50
52
  from sphinx.domains.std import StandardDomain
53
+ from sphinx.util.logging import SphinxLoggerAdapter
51
54
 
52
55
 
53
- class TextAsDefault(NamedTuple):
54
- text: str
55
-
56
-
57
- def make_id(key: str) -> str:
58
- return "-".join(key.split()).rstrip("-")
59
-
60
-
61
- def make_id_lower(key: str) -> str:
62
- # replace all capital letters "X" with "_lower(X)"
63
- return re.sub("[A-Z]", lambda m: "_" + m.group(0).lower(), make_id(key))
64
-
65
-
66
- logger = getLogger(__name__)
56
+ _LOGGER: Final[SphinxLoggerAdapter] = getLogger(__name__)
67
57
 
68
58
 
69
59
  class SphinxArgparseCli(SphinxDirective):
@@ -82,9 +72,8 @@ class SphinxArgparseCli(SphinxDirective):
82
72
  "group_title_prefix": unchanged,
83
73
  "group_sub_title_prefix": unchanged,
84
74
  "no_default_values": unchanged,
85
- # :ref: only supports lower-case. If this is set, any
86
- # would-be-upper-case chars will be prefixed with _. Since
87
- # this is backwards incompatible for URL's, this is opt-in.
75
+ # :ref: only supports lower-case, so this prefixes would-be-upper-case chars with _;
76
+ # opt-in because it breaks existing URLs.
88
77
  "force_refs_lower": flag,
89
78
  }
90
79
 
@@ -106,7 +95,7 @@ class SphinxArgparseCli(SphinxDirective):
106
95
  self._parser: ArgumentParser | None = None
107
96
  self._std_domain: StandardDomain = cast("StandardDomain", self.env.get_domain("std"))
108
97
  self._raw_format: bool = False
109
- self.make_id = make_id_lower if "force_refs_lower" in self.options else make_id
98
+ self._make_id = make_id_lower if "force_refs_lower" in self.options else make_id
110
99
 
111
100
  @property
112
101
  def parser(self) -> ArgumentParser:
@@ -153,10 +142,8 @@ class SphinxArgparseCli(SphinxDirective):
153
142
  self, sub_parser: _SubParsersAction[ArgumentParser]
154
143
  ) -> Iterator[tuple[list[str], str, ArgumentParser]]:
155
144
  parser_to_args: dict[int, list[str]] = defaultdict(list)
156
- str_to_parser: dict[str, ArgumentParser] = {}
157
145
  for key, parser in sub_parser._name_parser_map.items(): # noqa: SLF001
158
146
  parser_to_args[id(parser)].append(key)
159
- str_to_parser[key] = parser
160
147
  done_parser: set[int] = set()
161
148
 
162
149
  for name, parser in sub_parser.choices.items():
@@ -170,28 +157,24 @@ class SphinxArgparseCli(SphinxDirective):
170
157
  help_msg = next((a.help for a in sub_parser._choices_actions if a.dest == name), None) or "" # noqa: SLF001
171
158
  yield aliases, help_msg, parser
172
159
 
173
- # If this parser has a subparser, recurse into it
174
160
  if parser._subparsers: # noqa: SLF001
175
161
  sub_sub_parser: _SubParsersAction[ArgumentParser] = parser._subparsers._group_actions[0] # type: ignore[assignment] # noqa: SLF001
176
162
  yield from self._load_sub_parsers(sub_sub_parser)
177
163
 
178
- def load_sub_parsers(self) -> Iterator[tuple[list[str], str, ArgumentParser]]:
164
+ def _iter_sub_commands(self) -> Iterator[tuple[list[str], str, ArgumentParser]]:
179
165
  top_sub_parser = self.parser._subparsers # noqa: SLF001
180
166
  if not top_sub_parser:
181
167
  return
182
- sub_parser: _SubParsersAction[ArgumentParser]
183
- sub_parser = top_sub_parser._group_actions[0] # type: ignore[assignment] # noqa: SLF001
184
-
168
+ sub_parser: _SubParsersAction[ArgumentParser] = top_sub_parser._group_actions[0] # type: ignore[assignment] # noqa: SLF001
185
169
  yield from self._load_sub_parsers(sub_parser)
186
170
 
187
171
  def run(self) -> list[Node]:
188
- # construct headers
189
- self.env.note_reread() # this document needs to be always updated
172
+ self.env.note_reread() # this document needs to always be rebuilt
190
173
  title_text = self.options.get("title", f"{self.parser.prog} - CLI interface").strip()
191
174
  if not title_text:
192
175
  home_section: Element = container("")
193
176
  else:
194
- home_section = section("", title("", Text(title_text)), ids=[self.make_id(title_text)], names=[title_text])
177
+ home_section = section("", title("", Text(title_text)), ids=[self._make_id(title_text)], names=[title_text])
195
178
 
196
179
  if "usage_first" in self.options:
197
180
  home_section += self._mk_usage(self.parser)
@@ -202,15 +185,13 @@ class SphinxArgparseCli(SphinxDirective):
202
185
  if "usage_first" not in self.options:
203
186
  home_section += self._mk_usage(self.parser)
204
187
 
205
- # construct groups excluding sub-parsers
206
188
  for group in self.parser._action_groups: # noqa: SLF001
207
189
  if not group._group_actions or group is self.parser._subparsers: # noqa: SLF001
208
190
  continue
209
191
  home_section += self._mk_option_group(
210
192
  group, prefix=self.parser.prog.split("/")[-1], prog=self.parser.prog.split("/")[-1]
211
193
  )
212
- # construct sub-parser
213
- for aliases, help_msg, parser in self.load_sub_parsers():
194
+ for aliases, help_msg, parser in self._iter_sub_commands():
214
195
  home_section += self._mk_sub_command(aliases, help_msg, parser)
215
196
 
216
197
  if epilog := self._pre_format(self.options.get("epilog", self.parser.epilog)):
@@ -228,14 +209,16 @@ class SphinxArgparseCli(SphinxDirective):
228
209
  lit = literal_block("", Text(block), classes=["sphinx-argparse-cli-wrap"])
229
210
  lit["language"] = "none"
230
211
  return lit
231
- return paragraph("", Text(block))
212
+ para = paragraph("", Text(block))
213
+ _protect_option_dashes(para)
214
+ return para
232
215
 
233
216
  def _mk_option_group(self, group: _ArgumentGroup, prefix: str, prog: str) -> section:
234
217
  sub_title_prefix: str = self.options["group_sub_title_prefix"]
235
218
  title_prefix = self.options["group_title_prefix"]
236
219
  title_text = self._build_opt_grp_title(group, prefix, prog, sub_title_prefix, title_prefix)
237
220
  title_ref: str = f"{prefix}{' ' if prefix else ''}{group.title}"
238
- ref_id = self.make_id(title_ref)
221
+ ref_id = self._make_id(title_ref)
239
222
  # the text sadly needs to be prefixed, because otherwise the autosectionlabel will conflict
240
223
  header = title("", Text(title_text))
241
224
  group_section = section("", header, ids=[ref_id], names=[ref_id])
@@ -265,15 +248,11 @@ class SphinxArgparseCli(SphinxDirective):
265
248
  if action.metavar:
266
249
  as_key = action.metavar if isinstance(action.metavar, str) else action.metavar[0]
267
250
  if action.option_strings:
268
- first = True
269
- is_flag = action.nargs == 0
270
- for opt in action.option_strings:
271
- if first:
272
- first = False
273
- else:
251
+ for at, opt in enumerate(action.option_strings):
252
+ if at:
274
253
  line += Text(", ")
275
254
  self._mk_option_name(line, prefix, opt)
276
- if not is_flag:
255
+ if action.nargs != 0:
277
256
  line += Text(" ")
278
257
  metavar_text = (
279
258
  " ".join(meta.upper() for meta in action.metavar)
@@ -284,7 +263,6 @@ class SphinxArgparseCli(SphinxDirective):
284
263
  else:
285
264
  self._mk_option_name(line, prefix, as_key)
286
265
 
287
- point = list_item("", line, ids=[])
288
266
  if action.help:
289
267
  help_text = load_help_text(action.help)
290
268
  temp = paragraph()
@@ -302,16 +280,15 @@ class SphinxArgparseCli(SphinxDirective):
302
280
  line += Text(" (default: ")
303
281
  line += literal(text=str(action.default).replace(str(Path.cwd()), "{cwd}"))
304
282
  line += Text(")")
305
- return point
283
+ _protect_option_dashes(line)
284
+ return list_item("", line, ids=[])
306
285
 
307
286
  def _mk_option_name(self, line: paragraph, prefix: str, opt: str) -> None:
308
- ref_id = self.make_id(f"{prefix}-{opt}")
287
+ ref_id = self._make_id(f"{prefix}-{opt}")
309
288
  ref_title = f"{prefix} {opt}"
310
289
  ref = reference("", refid=ref_id, reftitle=ref_title)
311
290
  line.attributes["ids"].append(ref_id)
312
- st = strong()
313
- st += literal(text=opt)
314
- ref += st
291
+ ref += strong("", "", literal(text=opt))
315
292
  self._register_ref(ref_id, ref_title, ref, is_cli_option=True)
316
293
  line += ref
317
294
 
@@ -329,7 +306,7 @@ class SphinxArgparseCli(SphinxDirective):
329
306
  else:
330
307
  name = normalize_name(ref_name)
331
308
  if name in self._std_domain.labels:
332
- logger.warning(
309
+ _LOGGER.warning(
333
310
  __("duplicate label %s, other instance in %s"),
334
311
  name,
335
312
  self.env.doc2path(self._std_domain.labels[name][0]),
@@ -355,7 +332,7 @@ class SphinxArgparseCli(SphinxDirective):
355
332
  title_text += aliases_text
356
333
  title_ref += aliases_text
357
334
  title_text = title_text.strip()
358
- ref_id = self.make_id(title_ref)
335
+ ref_id = self._make_id(title_ref)
359
336
  group_section = section("", title("", Text(title_text)), ids=[ref_id], names=[title_ref])
360
337
  self._register_ref(ref_id, title_ref, group_section)
361
338
 
@@ -365,16 +342,16 @@ class SphinxArgparseCli(SphinxDirective):
365
342
  command_desc = (parser.description or help_msg or "").strip()
366
343
  if command_desc:
367
344
  desc_paragraph = paragraph("", Text(command_desc))
345
+ _protect_option_dashes(desc_paragraph)
368
346
  group_section += desc_paragraph
369
347
 
370
348
  if "usage_first" not in self.options:
371
349
  group_section += self._mk_usage(parser)
372
350
 
373
351
  for group in parser._action_groups: # noqa: SLF001
374
- if not group._group_actions: # do not show empty groups # noqa: SLF001
352
+ if not group._group_actions: # noqa: SLF001
375
353
  continue
376
354
  if isinstance(group._group_actions[0], _SubParsersAction): # noqa: SLF001
377
- # If this is a subparser, ignore it
378
355
  continue
379
356
  group_section += self._mk_option_group(group, prefix=parser.prog, prog=self.parser.prog.split("/")[-1])
380
357
  return group_section
@@ -415,33 +392,64 @@ class SphinxArgparseCli(SphinxDirective):
415
392
  @staticmethod
416
393
  def _apply_sub_title(title_text: str, sub_title_prefix: str, prog: str, sub_cmd: str) -> str:
417
394
  if sub_title_prefix:
418
- sub_title_prefix = sub_title_prefix.replace("{prog}", prog)
419
- sub_title_prefix = sub_title_prefix.replace("{subcommand}", sub_cmd)
395
+ sub_title_prefix = sub_title_prefix.replace("{prog}", prog).replace("{subcommand}", sub_cmd)
420
396
  title_text += f"{sub_title_prefix} "
421
397
  return title_text
422
398
 
423
399
  def _mk_usage(self, parser: ArgumentParser) -> literal_block:
424
400
  parser.formatter_class = lambda prog: HelpFormatter(prog, width=self.options.get("usage_width", 100))
425
- with self.no_color():
401
+ with self._no_color():
426
402
  texts = parser.format_usage()[len("usage: ") :].splitlines()
427
403
  texts = [line if at == 0 else f"{' ' * (len(parser.prog) + 1)}{line.lstrip()}" for at, line in enumerate(texts)]
428
404
  return literal_block("", Text("\n".join(texts)), classes=["sphinx-argparse-cli-wrap"])
429
405
 
430
406
  @contextmanager
431
- def no_color(self) -> Iterator[None]:
407
+ def _no_color(self) -> Iterator[None]:
432
408
  with patch.dict(os.environ, {"NO_COLOR": "1"}, clear=False):
433
- yield None
409
+ yield
434
410
 
435
411
 
436
- SINGLE_QUOTE = re.compile(r"[']+(.+?)[']+")
437
- DOUBLE_QUOTE = re.compile(r'["]+(.+?)["]+')
438
- CURLY_BRACES = re.compile(r"[{](.+?)[}]")
412
+ def make_id_lower(key: str) -> str:
413
+ return re.sub("[A-Z]", lambda m: f"_{m.group(0).lower()}", make_id(key))
414
+
415
+
416
+ def make_id(key: str) -> str:
417
+ return "-".join(key.split()).rstrip("-")
418
+
419
+
420
+ _HELP_SUBSTITUTIONS: Final[list[tuple[re.Pattern[str], str]]] = [
421
+ (re.compile(r"[']+(.+?)[']+"), "``'\\1'``"),
422
+ (re.compile(r'["]+(.+?)["]+'), '``"\\1"``'),
423
+ (re.compile(r"[{](.+?)[}]"), "``{\\1}``"),
424
+ ]
439
425
 
440
426
 
441
427
  def load_help_text(help_text: str) -> str:
442
- single_quote = SINGLE_QUOTE.sub("``'\\1'``", help_text)
443
- double_quote = DOUBLE_QUOTE.sub('``"\\1"``', single_quote)
444
- return CURLY_BRACES.sub("``{\\1}``", double_quote)
428
+ for pattern, replacement in _HELP_SUBSTITUTIONS:
429
+ help_text = pattern.sub(replacement, help_text)
430
+ return help_text
431
+
432
+
433
+ _OPTION_TOKEN: Final[re.Pattern[str]] = re.compile(r"((?<!\w)--[a-zA-Z0-9][\w-]*)")
434
+
435
+
436
+ def _protect_option_dashes(node: Element) -> None:
437
+ """Wrap each ``--option`` in a smartquotes-exempt inline so its ``--`` survives Sphinx's en-dash transform."""
438
+ for text in list(node.findall(Text)):
439
+ if isinstance(text.parent, (literal, FixedTextElement)):
440
+ continue
441
+ # A capturing group makes split() interleave the option tokens (odd indices) with the surrounding text.
442
+ parts = _OPTION_TOKEN.split(text)
443
+ if len(parts) == 1:
444
+ continue
445
+ text.parent.replace(
446
+ text,
447
+ [
448
+ inline("", part, support_smartquotes=False) if index % 2 else Text(part)
449
+ for index, part in enumerate(parts)
450
+ if part
451
+ ],
452
+ )
445
453
 
446
454
 
447
455
  class HookError(Exception):
@@ -453,7 +461,7 @@ def _parse_known_args_hook(self: ArgumentParser, *args: Any, **kwargs: Any) -> N
453
461
  raise HookError(self)
454
462
 
455
463
 
456
- _ANSI_COLOR_RE = re.compile(r"\x1b\[[0-9;]*m")
464
+ _ANSI_COLOR_RE: Final[re.Pattern[str]] = re.compile(r"\x1b\[[0-9;]*m")
457
465
 
458
466
 
459
467
  def _strip_ansi_colors(text: str) -> str: # pragma: >=3.14 cover
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '1.22.0'
22
+ __version_tuple__ = version_tuple = (1, 22, 0)
23
+
24
+ __commit_id__ = commit_id = None
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
7
7
 
8
8
  import pytest
9
9
 
10
- from sphinx_argparse_cli._logic import make_id, make_id_lower
10
+ from sphinx_argparse_cli._logic import load_help_text, make_id, make_id_lower
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from io import StringIO
@@ -142,6 +142,19 @@ def test_multiline_epilog_subclass_formatter_as_html(build_outcome: str) -> None
142
142
  assert ref in build_outcome
143
143
 
144
144
 
145
+ @pytest.mark.sphinx(buildername="html", testroot="smartquotes")
146
+ def test_option_dashes_survive_smartquotes(build_outcome: str) -> None:
147
+ # option names mentioned in parser-supplied text keep their double hyphen
148
+ assert "Pass input via <span>--text</span> or stdin." in build_outcome
149
+ assert "see also <span>--2fa</span> and <span>--dry_run</span>." in build_outcome
150
+ assert "combine with <span>--output</span> for files" in build_outcome
151
+ assert "build things with <span>--flair</span>" in build_outcome
152
+ for mangled in ("\u2013text", "\u2013output", "\u20132fa", "\u2013dry_run", "\u2013flair"):
153
+ assert mangled not in build_outcome
154
+ # the surrounding text keeps normal typography
155
+ assert "north\u2013south and 10\u201320" in build_outcome
156
+
157
+
145
158
  @pytest.mark.sphinx(buildername="text", testroot="complex")
146
159
  @pytest.mark.prepare(directive_args=[":usage_width: 100"])
147
160
  def test_usage_width_default(build_outcome: str) -> None:
@@ -179,10 +192,7 @@ def test_suppressed_action(build_outcome: str) -> None:
179
192
  ],
180
193
  )
181
194
  def test_help_loader(example: str, output: str) -> None:
182
- from sphinx_argparse_cli._logic import load_help_text # noqa: PLC0415
183
-
184
- result = load_help_text(example)
185
- assert result == output
195
+ assert load_help_text(example) == output
186
196
 
187
197
 
188
198
  @pytest.mark.sphinx(buildername="html", testroot="ref")
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import sphinx_argparse_cli
3
4
 
4
- def test_version() -> None:
5
- import sphinx_argparse_cli # noqa: PLC0415
6
5
 
6
+ def test_version() -> None:
7
7
  assert sphinx_argparse_cli.__version__
@@ -1,34 +0,0 @@
1
- # file generated by setuptools-scm
2
- # don't change, don't track in version control
3
-
4
- __all__ = [
5
- "__version__",
6
- "__version_tuple__",
7
- "version",
8
- "version_tuple",
9
- "__commit_id__",
10
- "commit_id",
11
- ]
12
-
13
- TYPE_CHECKING = False
14
- if TYPE_CHECKING:
15
- from typing import Tuple
16
- from typing import Union
17
-
18
- VERSION_TUPLE = Tuple[Union[int, str], ...]
19
- COMMIT_ID = Union[str, None]
20
- else:
21
- VERSION_TUPLE = object
22
- COMMIT_ID = object
23
-
24
- version: str
25
- __version__: str
26
- __version_tuple__: VERSION_TUPLE
27
- version_tuple: VERSION_TUPLE
28
- commit_id: COMMIT_ID
29
- __commit_id__: COMMIT_ID
30
-
31
- __version__ = version = '1.21.3'
32
- __version_tuple__ = version_tuple = (1, 21, 3)
33
-
34
- __commit_id__ = commit_id = None