What is a handler in mkdocstrings
mainmkdocstrings requires a specific handler (e.g., Python, TypeScript, C, etc.).repository·main·Indexed 24 days ago
https://github.com/mkdocstrings/mkdocstringsA language-agnostic plugin for MkDocs that automatically generates documentation from source code using a handler-based architecture. It uses an injection model with the `::: identifier` syntax to render documentation directly into Markdown files. Supported language handlers include Python, C, Crystal, GitHub Actions, MATLAB, TypeScript, VBA, and shell scripts.
mkdocstrings requires a specific handler (e.g., Python, TypeScript, C, etc.).mkdocstrings is language-agnostic. It relies on handlers to bridge the gap between source code and documentation. Each handler is responsible for collecting and rendering documentation for a specific language (e.g., Python, TypeScript, C).
Instead of generating separate Markdown files, mkdocstrings uses an injection model. You place an identifier in your existing Markdown content using the ::: identifier syntax. The identifier and any accompanying YAML configuration are passed to the appropriate handler to render the documentation directly into your page.
[identifier][] or [title][identifier].intersphinx, mkdocstrings can reference API items from other projects if they provide an inventory that you load in your configuration.Code blocks within docstrings and those inserted by mkdocstrings (like Source code) follow standard Markdown syntax highlighting rules.
Since version 0.15, the CSS class used for code blocks depends on your configuration. To target mkdocstrings code blocks specifically without affecting other code blocks in your documentation, it is recommended to use the pymdownx.highlight extension and use the following CSS selector:
.doc-contents .highlight
Since version 0.18, mkdocstrings provides a new Python handler based on Griffe. To use it, add the python extra to your mkdocstrings dependency in your pyproject.toml:
[project]
dependencies = [
"mkdocstrings[python]>=0.18",
]When generating documentation pages automatically, you must also automate the MkDocs navigation (nav). By combining mkdocs-gen-files with mkdocs-literate-nav, you can build a navigation tree programmatically in a Python script and output it to a SUMMARY.md file.
mkdocs-literate-nav to your dependencies.mkdocs.yml to use the plugin and point to your generated summary:plugins:
- search
- gen-files:
scripts:
- scripts/gen_ref_pages.py
- literate-nav:
nav_file: SUMMARY.md
- mkdocstringsmkdocs.yml navigation, defer the code reference section to the generated folder:nav:
- Code Reference: reference/(Note: The trailing slash is required so mkdocs-literate-nav looks for SUMMARY.md inside that directory.)
Update your generation script to use mkdocs_gen_files.Nav() to build the tree and write the SUMMARY.md at the end.
import mkdocs_gen_files
from pathlib import Path
nav = mkdocs_gen_files.Nav()
root = Path(__file__).parent.parent
src = root / "src"
for path in sorted(src.rglob("*.py")):
module_path = path.relative_to(src).with_suffix("")
doc_path = path.relative_to(src).with_suffix(".md")
full_doc_path = Path("reference", doc_path)
parts = tuple(module_path.parts)
if parts[-1] == "__init__":
parts = parts[:-1]
elif parts[-1] == "__main__":
continue
nav[parts] = doc_path.as_posix()
with mkdocs_gen_files.open(full_doc_path, "w") as fd:
ident = ".".join(parts)
fd.write(f"::: {ident}")
mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root))
# Write the literate navigation file
with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file:
nav_file.writelines(nav.build_literate_nav())The mkdocstrings package is a common base and does not include language support by default. You must install it along with one or more language handlers.
To install mkdocstrings with Python support using pip extras, use:
pip install 'mkdocstrings[python]'Alternatively, you can install the specific handler directly:
pip install mkdocstrings-pythonUsing conda:
conda install -c conda-forge mkdocstrings mkdocstrings-pythonAvailable handlers include C, Crystal, GitHub Actions, Python, MATLAB, TypeScript, VBA, and shell scripts.
If you need to maintain compatibility with older workflows, you can explicitly install the legacy Python handler using the python-legacy extra:
[project]
dependencies = [
"mkdocstrings[python-legacy]>=0.18",
]By default, indented code blocks within docstrings might not have a language assigned. You can set a default language for these blocks using the pymdownx.highlight extension in your mkdocs.yml.
For example, to ensure all indented code blocks in your docstrings are treated as Python, set default_lang: python.
markdown_extensions:
- pymdownx.highlight:
default_lang: pythonYou can create custom handlers by subclassing mkdocstrings.BaseHandler. A custom handler package should use namespace packages, typically following this structure:
📁 your_repository
└─╴📁 mkdocstrings_handlers
└─╴📁 custom_handler
├─╴📁 templates
│ ├─╴📁 material
│ ├─╴📁 mkdocs
│ └─╴📁 readthedocs
└─╴📄 __init__.pyNote: There is no __init__.py in the mkdocstrings_handlers directory.
To kickstart a new handler, you can use the official Copier template:
pipx install copier
copier gh:mkdocstrings/handler-template my_handlerTo prevent __init__ modules from appearing as expandable/collapsible items in your navigation (which can clutter the API view), you can use mkdocs-section-index. This plugin allows you to bind the documentation of an __init__ module directly to its parent section/folder.
mkdocs-section-index to your dependencies.mkdocs.yml plugins list:plugins:
- search
- gen-files:
scripts:
- scripts/gen_ref_pages.py
- literate-nav:
nav_file: SUMMARY.md
- section-index
- mkdocstringsIn your generation script, when an __init__ module is encountered, rename its target documentation path to index.md. This tells the plugin to treat the module's content as the index for that directory/section.
# Inside your generation loop
if parts[-1] == "__init__":
parts = parts[:-1]
doc_path = doc_path.with_name("index.md")
full_doc_path = full_doc_path.with_name("index.md")
# ... proceed to write the file ...Developers can extend or alter the behavior of existing handlers (e.g., the Python handler) by creating third-party packages that register additional template folders. This is primarily used to add specific support for other libraries within a handler.
An extension is a Python package that defines a specific entry-point in its pyproject.toml. The entry-point must provide a get_templates_path function that returns a pathlib.Path or str pointing to a directory containing templates.
Template Directory Structure:
The directory must contain one subfolder for each supported theme (e.g., material, mkdocs, readthedocs). The extension is responsible for ensuring the handler uses these templates by mutating collected data, as per the specific handler's extension support documentation.
[project.entry-points."mkdocstrings.python.templates"]
extension-name = "extension_package:get_templates_path"from pathlib import Path
def get_templates_path() -> Path:
return Path(__file__).parent / "templates"You can override the default theme templates by providing a custom templates directory. Use the custom_templates option within the mkdocstrings plugin configuration in your mkdocs.yml file.
Your custom directory must follow a specific hierarchy: templates/<handler>/<theme>/. You do not need to replicate the entire tree; you only need to include the specific handler, theme, and template files you wish to override.
For example, to override parameters.html and exceptions.html for the Python handler using the Material theme, structure your files as follows:
📁 templates/
└── 📁 python/
└── 📁 material/
├── 📄 parameters.html
└── 📄 exceptions.htmlplugins:
- mkdocstrings:
custom_templates: templates