Skip to content

Commit f6cd9aa

Browse files
committed
refactor: Update code base for mkdocstrings 0.28
See mkdocstrings/mkdocstrings#727.
1 parent ad6f4ef commit f6cd9aa

File tree

8 files changed

+357
-89
lines changed

8 files changed

+357
-89
lines changed

docs/configuration.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Configuration
2+
3+
This page lists the available configuration options and what they achieve.
4+
5+
[](){#option-extra}
6+
## `extra`
7+
8+
- **:octicons-package-24: Type [`dict`][] :material-equal: `{}`{ title="default value" }**
9+
10+
The `extra` option lets you inject additional variables into the Jinja context used when rendering templates. You can then use this extra context in your [overridden templates](https://mkdocstrings.github.io/usage/theming/#templates).
11+
12+
Local `extra` options will be merged into the global `extra` option:
13+
14+
```yaml title="in mkdocs.yml (global configuration)"
15+
plugins:
16+
- mkdocstrings:
17+
handlers:
18+
shell:
19+
options:
20+
extra:
21+
hello: world
22+
```
23+
24+
```md title="in docs/some_page.md (local configuration)"
25+
::: your_package.your_module.your_func
26+
handler: shell
27+
options:
28+
extra:
29+
foo: bar
30+
```
31+
32+
...will inject both `hello` and `foo` into the Jinja context when rendering `your_package.your_module.your_func`.
33+
34+
[](){#option-heading_level}
35+
## `heading_level`
36+
37+
- **:octicons-package-24: Type [`int`][] :material-equal: `2`{ title="default value" }**
38+
39+
The initial heading level to use.
40+
41+
When injecting documentation for an object,
42+
the object itself and its members are rendered.
43+
For each layer of objects, we increase the heading level by 1.
44+
45+
The initial heading level will be used for the first layer.
46+
If you set it to 3, then headings will start with `<h3>`.
47+
48+
If the [heading for the root object][show_root_heading] is not shown,
49+
then the initial heading level is used for its members.
50+
51+
```yaml title="in mkdocs.yml (global configuration)"
52+
plugins:
53+
- mkdocstrings:
54+
handlers:
55+
shell:
56+
options:
57+
heading_level: 2
58+
```
59+
60+
```md title="or in docs/some_page.md (local configuration)"
61+
::: path.to.module
62+
handler: shell
63+
options:
64+
heading_level: 3
65+
```
66+
67+
/// admonition | Preview
68+
type: preview
69+
70+
//// tab | With level 3 and root heading
71+
<h3><code>module</code> (3)</h3>
72+
<p>Docstring of the module.</p>
73+
<h4><code>ClassA</code> (4)</h4>
74+
<p>Docstring of class A.</p>
75+
<h4><code>ClassB</code> (4)</h4>
76+
<p>Docstring of class B.</p>
77+
<h5><code>method_1</code> (5)</h5>
78+
<p>Docstring of the method.</p>
79+
////
80+
81+
//// tab | With level 3, without root heading
82+
<p>Docstring of the module.</p>
83+
<h3><code>ClassA</code> (3)</h3>
84+
<p>Docstring of class A.</p>
85+
<h3><code>ClassB</code> (3)</h3>
86+
<p>Docstring of class B.</p>
87+
<h4><code>method_1</code> (4)</h4>
88+
<p>Docstring of the method.</p>
89+
////
90+
///
91+
92+
[](){#option-show_root_heading}
93+
## `show_root_heading`
94+
95+
- **:octicons-package-24: Type [`bool`][] :material-equal: `False`{ title="default value" }**
96+
97+
Show the heading of the object at the root of the documentation tree
98+
(i.e. the object referenced by the identifier after `:::`).
99+
100+
While this option defaults to false for backwards compatibility, we recommend setting it to true. Note that the heading of the root object can be a level 1 heading (the first on the page):
101+
102+
```md
103+
# ::: path.to.object
104+
```
105+
106+
```yaml title="in mkdocs.yml (global configuration)"
107+
plugins:
108+
- mkdocstrings:
109+
handlers:
110+
shell:
111+
options:
112+
show_root_heading: false
113+
```
114+
115+
```md title="or in docs/some_page.md (local configuration)"
116+
::: path.to.Class
117+
handler: shell
118+
options:
119+
show_root_heading: true
120+
```
121+
122+
[](){#option-show_root_toc_entry}
123+
## `show_root_toc_entry`
124+
125+
- **:octicons-package-24: Type [`bool`][] :material-equal: `True`{ title="default value" }**
126+
<!-- - **:octicons-project-template-24: Template :material-null:** (N/A) -->
127+
128+
If the root heading is not shown, at least add a ToC entry for it.
129+
130+
If you inject documentation for an object in the middle of a page,
131+
after long paragraphs, and without showing the [root heading][show_root_heading],
132+
then you will not be able to link to this particular object
133+
as it won't have a permalink and will be "lost" in the middle of text.
134+
In that case, it is useful to add a hidden anchor to the document,
135+
which will also appear in the table of contents.
136+
137+
In other cases, you might want to disable the entry to avoid polluting the ToC.
138+
It is not possible to show the root heading *and* hide the ToC entry.
139+
140+
```yaml title="in mkdocs.yml (global configuration)"
141+
plugins:
142+
- mkdocstrings:
143+
handlers:
144+
shell:
145+
options:
146+
show_root_toc_entry: true
147+
```
148+
149+
```md title="or in docs/some_page.md (local configuration)"
150+
## Some heading
151+
152+
Lots of text.
153+
154+
::: path.to.object
155+
handler: shell
156+
options:
157+
show_root_toc_entry: false
158+
159+
## Other heading.
160+
161+
More text.
162+
```
163+
164+
/// admonition | Preview
165+
type: preview
166+
167+
//// tab | With ToC entry
168+
**Table of contents**
169+
[Some heading](#permalink-to-some-heading){ title="#permalink-to-some-heading" }
170+
[`object`](#permalink-to-object){ title="#permalink-to-object" }
171+
[Other heading](#permalink-to-other-heading){ title="#permalink-to-other-heading" }
172+
////
173+
174+
//// tab | Without ToC entry
175+
**Table of contents**
176+
[Some heading](#permalink-to-some-heading){ title="#permalink-to-some-heading" }
177+
[Other heading](#permalink-to-other-heading){ title="#permalink-to-other-heading" }
178+
////
179+
///

duties.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ def check_types(ctx: Context) -> None:
8989
ctx.run(
9090
tools.mypy(*PY_SRC_LIST, config_file="config/mypy.ini"),
9191
title=pyprefix("Type-checking"),
92+
# TODO: Update when Pydantic supports 3.14.
93+
nofail=sys.version_info >= (3, 14),
9294
)
9395

9496

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ validation:
1616
nav:
1717
- Home:
1818
- Overview: index.md
19+
- Configuration: configuration.md
1920
- Changelog: changelog.md
2021
- Credits: credits.md
2122
- License: license.md
@@ -107,6 +108,7 @@ markdown_extensions:
107108

108109
plugins:
109110
- search
111+
- autorefs
110112
- markdown-exec
111113
- gen-files:
112114
scripts:

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,5 @@ dev = [
106106
"mkdocstrings[python]>=0.25",
107107
# YORE: EOL 3.10: Remove line.
108108
"tomli>=2.0; python_version < '3.11'",
109+
"pydantic>=2.10",
109110
]
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""Configuration and options dataclasses."""
2+
3+
from __future__ import annotations
4+
5+
import sys
6+
from dataclasses import field
7+
from typing import TYPE_CHECKING, Annotated, Any
8+
9+
# YORE: EOL 3.10: Replace block with line 2.
10+
if sys.version_info >= (3, 11):
11+
from typing import Self
12+
else:
13+
from typing_extensions import Self
14+
15+
try:
16+
# When Pydantic is available, use it to validate options (done automatically).
17+
# Users can therefore opt into validation by installing Pydantic in development/CI.
18+
# When building the docs to deploy them, Pydantic is not required anymore.
19+
20+
# When building our own docs, Pydantic is always installed (see `docs` group in `pyproject.toml`)
21+
# to allow automatic generation of a JSON Schema. The JSON Schema is then referenced by mkdocstrings,
22+
# which is itself referenced by mkdocs-material's schema system. For example in VSCode:
23+
#
24+
# "yaml.schemas": {
25+
# "https://squidfunk.github.io/mkdocs-material/schema.json": "mkdocs.yml"
26+
# }
27+
from inspect import cleandoc
28+
29+
from pydantic import Field as BaseField
30+
from pydantic.dataclasses import dataclass
31+
32+
_base_url = "https://mkdocstrings.github.io/shell/configuration"
33+
34+
def Field( # noqa: N802, D103
35+
*args: Any,
36+
description: str,
37+
parent: str | None = None,
38+
**kwargs: Any,
39+
) -> None:
40+
def _add_markdown_description(schema: dict[str, Any]) -> None:
41+
url = f"{_base_url}/#{parent or schema['title']}"
42+
schema["markdownDescription"] = f"[DOCUMENTATION]({url})\n\n{schema['description']}"
43+
44+
return BaseField(
45+
*args,
46+
description=cleandoc(description),
47+
field_title_generator=lambda name, _: name,
48+
json_schema_extra=_add_markdown_description,
49+
**kwargs,
50+
)
51+
except ImportError:
52+
from dataclasses import dataclass # type: ignore[no-redef]
53+
54+
def Field(*args: Any, **kwargs: Any) -> None: # type: ignore[misc] # noqa: D103, N802
55+
pass
56+
57+
58+
if TYPE_CHECKING:
59+
from collections.abc import MutableMapping
60+
61+
62+
# YORE: EOL 3.9: Remove block.
63+
_dataclass_options = {"frozen": True}
64+
if sys.version_info >= (3, 10):
65+
_dataclass_options["kw_only"] = True
66+
67+
68+
# YORE: EOL 3.9: Replace `**_dataclass_options` with `frozen=True, kw_only=True` within line.
69+
@dataclass(**_dataclass_options) # type: ignore[call-overload]
70+
class ShellInputOptions:
71+
"""Accepted input options."""
72+
73+
extra: Annotated[
74+
dict[str, Any],
75+
Field(description="Extra options."),
76+
] = field(default_factory=dict)
77+
78+
heading_level: Annotated[
79+
int,
80+
Field(description="The initial heading level to use."),
81+
] = 2
82+
83+
show_root_heading: Annotated[
84+
bool,
85+
Field(
86+
description="""Show the heading of the object at the root of the documentation tree.
87+
88+
The root object is the object referenced by the identifier after `:::`.
89+
""",
90+
),
91+
] = False
92+
93+
show_root_toc_entry: Annotated[
94+
bool,
95+
Field(
96+
description="If the root heading is not shown, at least add a ToC entry for it.",
97+
),
98+
] = True
99+
100+
@classmethod
101+
def coerce(cls, **data: Any) -> MutableMapping[str, Any]:
102+
"""Coerce data."""
103+
return data
104+
105+
@classmethod
106+
def from_data(cls, **data: Any) -> Self:
107+
"""Create an instance from a dictionary."""
108+
return cls(**cls.coerce(**data))
109+
110+
111+
# YORE: EOL 3.9: Replace `**_dataclass_options` with `frozen=True, kw_only=True` within line.
112+
@dataclass(**_dataclass_options) # type: ignore[call-overload]
113+
class ShellOptions(ShellInputOptions): # type: ignore[override,unused-ignore]
114+
"""Final options passed as template context."""
115+
116+
117+
# YORE: EOL 3.9: Replace `**_dataclass_options` with `frozen=True, kw_only=True` within line.
118+
@dataclass(**_dataclass_options) # type: ignore[call-overload]
119+
class ShellInputConfig:
120+
"""Python handler configuration."""
121+
122+
options: Annotated[
123+
ShellInputOptions,
124+
Field(description="Configuration options for collecting and rendering objects."),
125+
] = field(default_factory=ShellInputOptions)
126+
127+
128+
# YORE: EOL 3.9: Replace `**_dataclass_options` with `frozen=True, kw_only=True` within line.
129+
@dataclass(**_dataclass_options) # type: ignore[call-overload]
130+
class ShellConfig(ShellInputConfig): # type: ignore[override,unused-ignore]
131+
"""Shell handler configuration."""
132+
133+
options: dict[str, Any] = field(default_factory=dict) # type: ignore[assignment]

0 commit comments

Comments
 (0)