Skip to content

Commit

Permalink
feat: Allow extensions to add templates
Browse files Browse the repository at this point in the history
An extension here is simply a Python package
that defines an entry-point for a specific handler.

For example, an extension can add templates to the Python handler
thanks to this entry-point:

```toml
[project.entry-points."mkdocstrings.python.templates"]
extension-name = "extension_package:get_templates_path"
``

This entry-point assumes that the extension provides
a `get_templates_path` function directly under
the `extension_package` package. This function doesn't
accept any argument and returns the path to a directory
containing templates. The directory must contain one
subfolder for each supported theme, for example:

```
templates/
    material/
    readthedocs/
    mkdocs/
```

mkdocstrings will add the folders corresponding
to the user-selected theme, and to the handler's defined
fallback theme, as usual.

The names of the extension templates must not
overlap with the handler's original templates.

The extension is then responsible, in collaboration
with its target handler, for mutating the collected
data in order to instruct the handler to use one of
the extension template when rendering particular objects.

For example, the Python handler will look for a `template`
attribute on objects, and use it to render the object.
This `template` attribute will be set by Griffe extensions
(Griffe is the tool used by the Python handler to collect data).
  • Loading branch information
pawamoy committed May 12, 2023
1 parent 2c05d78 commit 0067246
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies = [
"mkdocs>=1.2",
"mkdocs-autorefs>=0.3.1",
"pymdown-extensions>=6.3",
"importlib-metadata>=1.4; python_version < '3.8'",
"typing-extensions>=4.1; python_version < '3.10'",
]

Expand Down
30 changes: 30 additions & 0 deletions src/mkdocstrings/handlers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from __future__ import annotations

import importlib
import sys
import warnings
from contextlib import suppress
from pathlib import Path
Expand All @@ -31,6 +32,12 @@
from mkdocstrings.inventory import Inventory
from mkdocstrings.loggers import get_template_logger

# TODO: remove once support for Python 3.7 is dropped
if sys.version_info < (3, 8):
from importlib_metadata import entry_points
else:
from importlib.metadata import entry_points

CollectorItem = Any


Expand Down Expand Up @@ -93,12 +100,23 @@ def __init__(self, handler: str, theme: str, custom_templates: str | None = None
self._theme = theme
self._custom_templates = custom_templates

# add selected theme templates
themes_dir = self.get_templates_dir(handler)
paths.append(themes_dir / theme)

# add extended theme templates
extended_templates_dirs = self.get_extended_templates_dirs(handler)
for templates_dir in extended_templates_dirs:
paths.append(templates_dir / theme)

# add fallback theme templates
if self.fallback_theme and self.fallback_theme != theme:
paths.append(themes_dir / self.fallback_theme)

# add fallback theme of extended templates
for templates_dir in extended_templates_dirs:
paths.append(templates_dir / self.fallback_theme)

for path in paths:
css_path = path / "style.css"
if css_path.is_file():
Expand Down Expand Up @@ -179,6 +197,18 @@ def get_templates_dir(self, handler: str) -> Path:

raise FileNotFoundError(f"Can't find 'templates' folder for handler '{handler}'")

def get_extended_templates_dirs(self, handler: str) -> list[Path]:
"""Load template extensions for the given handler, return their templates directories.
Arguments:
handler: The name of the handler to get the extended templates directory of.
Returns:
The extensions templates directories.
"""
discovered_extensions = entry_points(group=f"mkdocstrings.{handler}.templates")
return [extension.load()() for extension in discovered_extensions]

def get_anchors(self, data: CollectorItem) -> tuple[str, ...] | set[str]:
"""Return the possible identifiers (HTML anchors) for a collected item.
Expand Down

0 comments on commit 0067246

Please sign in to comment.