mkdocstrings

repository·main·Indexed 24 days ago

https://github.com/mkdocstrings/mkdocstrings

A 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.

Tokens
9.8K
Snippets
28
Records
41
Agent score
84%

What's inside mkdocstrings

  1. How mkdocstrings works: Handlers and Injection

    main

    Language Handlers

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

    Inline Injection

    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.

    Cross-references

    • Across pages: You can reference any heading produced by a handler using Markdown link syntax like [identifier][] or [title][identifier].
    • Across sites: Similar to Sphinx's intersphinx, mkdocstrings can reference API items from other projects if they provide an inventory that you load in your configuration.
  2. Style mkdocstrings code blocks with CSS

    main

    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

  3. Generate a literate navigation file for automatic API docs

    main

    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.

    Setup

    1. Add mkdocs-literate-nav to your dependencies.
    2. Configure 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
    - mkdocstrings
    1. In your mkdocs.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.)

    Implementation Example

    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())
  4. Install mkdocstrings with language handlers

    main

    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-python

    Using conda:

    conda install -c conda-forge mkdocstrings mkdocstrings-python

    Available handlers include C, Crystal, GitHub Actions, Python, MATLAB, TypeScript, VBA, and shell scripts.

  5. Set default syntax highlighting for indented code blocks in docstrings

    main

    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: python
  6. Create a custom mkdocstrings handler

    main

    You 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__.py

    Note: 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_handler
  7. Bind documentation to sections using mkdocs-section-index

    main

    To 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.

    Setup

    1. Add mkdocs-section-index to your dependencies.
    2. Add it to your mkdocs.yml plugins list:
    plugins:
    - search
    - gen-files:
        scripts:
        - scripts/gen_ref_pages.py
    - literate-nav:
        nav_file: SUMMARY.md
    - section-index
    - mkdocstrings

    Implementation

    In 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 ...
  8. Create a handler extension for mkdocstrings

    main

    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"
  9. Override mkdocstrings templates with custom templates

    main

    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.html
    plugins:
    - mkdocstrings:
        custom_templates: templates