Skip to content

Commit f596471

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

File tree

9 files changed

+385
-90
lines changed

9 files changed

+385
-90
lines changed

docs/configuration.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
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_heading: false
147+
show_root_toc_entry: true
148+
```
149+
150+
```md title="or in docs/some_page.md (local configuration)"
151+
## Some heading
152+
153+
Lots of text.
154+
155+
::: path.to.object
156+
handler: shell
157+
options:
158+
show_root_heading: false
159+
show_root_toc_entry: false
160+
161+
## Other heading.
162+
163+
More text.
164+
```
165+
166+
/// admonition | Preview
167+
type: preview
168+
169+
//// tab | With ToC entry
170+
**Table of contents**<br>
171+
[Some heading](#permalink-to-some-heading){ title="#permalink-to-some-heading" }<br>
172+
[`object`](#permalink-to-object){ title="#permalink-to-object" }<br>
173+
[Other heading](#permalink-to-other-heading){ title="#permalink-to-other-heading" }
174+
////
175+
176+
//// tab | Without ToC entry
177+
**Table of contents**<br>
178+
[Some heading](#permalink-to-some-heading){ title="#permalink-to-some-heading" }<br>
179+
[Other heading](#permalink-to-other-heading){ title="#permalink-to-other-heading" }
180+
////
181+
///

docs/css/material.css

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,25 @@
22
.md-main__inner {
33
margin-bottom: 1.5rem;
44
}
5+
6+
/* Custom admonition: preview */
7+
:root {
8+
--md-admonition-icon--preview: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.5 12a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z"/><path d="M12 3.5c3.432 0 6.124 1.534 8.054 3.241 1.926 1.703 3.132 3.61 3.616 4.46a1.6 1.6 0 0 1 0 1.598c-.484.85-1.69 2.757-3.616 4.461-1.929 1.706-4.622 3.24-8.054 3.24-3.432 0-6.124-1.534-8.054-3.24C2.02 15.558.814 13.65.33 12.8a1.6 1.6 0 0 1 0-1.598c.484-.85 1.69-2.757 3.616-4.462C5.875 5.034 8.568 3.5 12 3.5ZM1.633 11.945a.115.115 0 0 0-.017.055c.001.02.006.039.017.056.441.774 1.551 2.527 3.307 4.08C6.691 17.685 9.045 19 12 19c2.955 0 5.31-1.315 7.06-2.864 1.756-1.553 2.866-3.306 3.307-4.08a.111.111 0 0 0 .017-.056.111.111 0 0 0-.017-.056c-.441-.773-1.551-2.527-3.307-4.08C17.309 6.315 14.955 5 12 5 9.045 5 6.69 6.314 4.94 7.865c-1.756 1.552-2.866 3.306-3.307 4.08Z"/></svg>');
9+
}
10+
11+
.md-typeset .admonition.preview,
12+
.md-typeset details.preview {
13+
border-color: rgb(220, 139, 240);
14+
}
15+
16+
.md-typeset .preview>.admonition-title,
17+
.md-typeset .preview>summary {
18+
background-color: rgba(142, 43, 155, 0.1);
19+
}
20+
21+
.md-typeset .preview>.admonition-title::before,
22+
.md-typeset .preview>summary::before {
23+
background-color: rgb(220, 139, 240);
24+
-webkit-mask-image: var(--md-admonition-icon--preview);
25+
mask-image: var(--md-admonition-icon--preview);
26+
}

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: 5 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
@@ -87,6 +88,9 @@ markdown_extensions:
8788
- admonition
8889
- callouts
8990
- footnotes
91+
- pymdownx.blocks.admonition
92+
- pymdownx.blocks.tab:
93+
alternate_style: true
9094
- pymdownx.emoji:
9195
emoji_index: !!python/name:material.extensions.emoji.twemoji
9296
emoji_generator: !!python/name:material.extensions.emoji.to_svg
@@ -107,6 +111,7 @@ markdown_extensions:
107111

108112
plugins:
109113
- search
114+
- autorefs
110115
- markdown-exec
111116
- gen-files:
112117
scripts:

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ classifiers = [
2929
"Typing :: Typed",
3030
]
3131
dependencies = [
32-
"mkdocstrings>=0.18",
32+
"mkdocstrings>=0.28",
3333
"shellman>=1.0.0",
3434
]
3535

@@ -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)