Skip to content

Commit 96640ba

Browse files
committed
apidoc: allow configuring template directories
1 parent 465b758 commit 96640ba

File tree

15 files changed

+164
-5
lines changed

15 files changed

+164
-5
lines changed

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ Features added
6868
Patch by Jean-François B.
6969
* #13508: Initial support for :pep:`695` type aliases.
7070
Patch by Martin Matouš, Jeremy Maitin-Shepard, and Adam Turner.
71+
* apidoc: Allow configuring template directories via
72+
:confval:`apidoc_template_dir` and the per-module ``template_dir`` option.
73+
Patch by Chidera Okara.
7174

7275
Bugs fixed
7376
----------

doc/usage/extensions/apidoc.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ The apidoc extension uses the following configuration values:
110110
:code-py:`'automodule_options'`
111111
See :confval:`apidoc_automodule_options`.
112112

113+
:code-py:`'template_dir'`
114+
A directory containing templates used when generating documentation files.
115+
Paths are interpreted relative to the configuration directory when not
116+
absolute. See :confval:`apidoc_template_dir`.
117+
113118
.. confval:: apidoc_exclude_patterns
114119
:type: :code-py:`Sequence[str]`
115120
:default: :code-py:`()`
@@ -170,3 +175,10 @@ The apidoc extension uses the following configuration values:
170175
:default: :code-py:`{'members', 'show-inheritance', 'undoc-members'}`
171176

172177
Options to pass to generated :rst:dir:`automodule` directives.
178+
179+
.. confval:: apidoc_template_dir
180+
:type: :code-py:`str`
181+
:default: :code-py:`None`
182+
183+
A directory containing templates that override the built-in apidoc templates.
184+
Paths are interpreted relative to the configuration directory.

sphinx/ext/apidoc/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
from __future__ import annotations
1313

14+
from pathlib import Path
15+
from types import NoneType
1416
from typing import TYPE_CHECKING
1517

1618
import sphinx
@@ -54,6 +56,9 @@ def setup(app: Sphinx) -> ExtensionMetadata:
5456
'env',
5557
types=frozenset({frozenset, list, set, tuple}),
5658
)
59+
app.add_config_value(
60+
'apidoc_template_dir', None, 'env', types=frozenset({NoneType, str, Path})
61+
)
5762
app.add_config_value('apidoc_modules', (), 'env', types=frozenset({list, tuple}))
5863

5964
# Entry point to run apidoc

sphinx/ext/apidoc/_cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,4 +353,5 @@ def _full_quickstart(opts: ApidocOptions, /, *, modules: list[str]) -> None:
353353
d['extensions'].extend(ext.split(','))
354354

355355
if not opts.dry_run:
356-
qs.generate(d, silent=True, overwrite=opts.force, templatedir=opts.template_dir)
356+
templatedir = str(opts.template_dir) if opts.template_dir is not None else None
357+
qs.generate(d, silent=True, overwrite=opts.force, templatedir=templatedir)

sphinx/ext/apidoc/_extension.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
'exclude_patterns',
3838
'automodule_options',
3939
'max_depth',
40+
'template_dir',
4041
})
4142

4243

@@ -169,7 +170,24 @@ def _parse_module_options(
169170
)
170171
]
171172

172-
# TODO template_dir
173+
template_dir = _normalize_template_dir(defaults.template_dir, confdir=confdir)
174+
if 'template_dir' in options:
175+
if options['template_dir'] is None:
176+
template_dir = None
177+
elif isinstance(options['template_dir'], str):
178+
template_dir = _normalize_template_dir(
179+
options['template_dir'], confdir=confdir
180+
)
181+
else:
182+
LOGGER.warning(
183+
__("apidoc_modules item %i '%s' must be a string"),
184+
i,
185+
'template_dir',
186+
type='apidoc',
187+
)
188+
template_dir = _normalize_template_dir(
189+
defaults.template_dir, confdir=confdir
190+
)
173191

174192
max_depth = defaults.max_depth
175193
if 'max_depth' in options:
@@ -227,6 +245,7 @@ def _parse_module_options(
227245
implicit_namespaces=bool_options['implicit_namespaces'],
228246
automodule_options=automodule_options,
229247
header=module_path.name,
248+
template_dir=template_dir,
230249
)
231250

232251

@@ -261,3 +280,18 @@ def _check_collection_of_strings(
261280
)
262281
return default
263282
return options[key]
283+
284+
285+
def _normalize_template_dir(
286+
value: str | Path | None,
287+
*,
288+
confdir: Path,
289+
) -> Path | None:
290+
"""Return a template directory path resolved relative to *confdir*."""
291+
if value is None:
292+
return None
293+
294+
path = Path(value)
295+
if not path.is_absolute():
296+
path = confdir / path
297+
return path

sphinx/ext/apidoc/_shared.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class ApidocOptions:
6666
version: str | None = None
6767
release: str | None = None
6868
extensions: Sequence[str] | None = None
69-
template_dir: str | None = None
69+
template_dir: str | Path | None = None
7070

7171

7272
@dataclasses.dataclass(frozen=True, kw_only=True, slots=True)
@@ -82,6 +82,7 @@ class ApidocDefaults:
8282
no_headings: bool
8383
module_first: bool
8484
implicit_namespaces: bool
85+
template_dir: str | Path | None
8586

8687
@classmethod
8788
def from_config(cls, config: Config, /) -> Self:
@@ -96,4 +97,5 @@ def from_config(cls, config: Config, /) -> Self:
9697
no_headings=config.apidoc_no_headings,
9798
module_first=config.apidoc_module_first,
9899
implicit_namespaces=config.apidoc_implicit_namespaces,
100+
template_dir=config.apidoc_template_dir,
99101
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.. custom-template-marker
2+
3+
{{ qualname }} documented with the custom template.
4+
5+
.. automodule:: {{ qualname }}
6+
:members:
7+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.. default-template-marker
2+
3+
{{ qualname }} documented with the default template.
4+
5+
.. automodule:: {{ qualname }}
6+
:members:
7+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
extensions = ['sphinx.ext.apidoc']
2+
3+
apidoc_separate_modules = True
4+
apidoc_template_dir = '_templates/default'
5+
apidoc_modules = [
6+
{
7+
'path': 'src/pkg_default',
8+
'destination': 'generated/default',
9+
},
10+
{
11+
'path': 'src/pkg_custom',
12+
'destination': 'generated/custom',
13+
'template_dir': '_templates/custom',
14+
},
15+
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Test apidoc template directory
2+
==============================
3+
4+
This project exercises the per-module ``template_dir`` support added to the
5+
``sphinx.ext.apidoc`` extension.
6+

0 commit comments

Comments
 (0)