Skip to content

Commit

Permalink
feat: Add Jinja blocks to module, class, function and attribute templ…
Browse files Browse the repository at this point in the history
…ates
  • Loading branch information
pawamoy committed Jul 14, 2023
1 parent 3d8724e commit 299fe48
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 142 deletions.
96 changes: 80 additions & 16 deletions docs/usage/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,33 +69,97 @@ for filepath in sorted(path for path in Path(basedir).rglob("*") if "_base" not
See them [in the repository](https://github.com/mkdocstrings/python/tree/master/src/mkdocstrings_handlers/python/templates/).
See the general *mkdocstrings* documentation to learn how to override them: https://mkdocstrings.github.io/theming/#templates.

In preparation for Jinja2 blocks, which will improve customization,
each one of these templates extends a base version in `theme/_base`. Example:
Each one of these templates extends a base version in `theme/_base`. Example:

```html+jinja title="theme/docstring/admonition.html"
{% extends "_base/docstring/admonition.html" %}
```html+jinja title="theme/class.html"
{% extends "_base/class.html" %}
```

```html+jinja title="theme/_base/docstring/admonition.html"
{{ log.debug() }}
<details class="{{ section.value.kind }}">
<summary>{{ section.title|convert_markdown(heading_level, html_id, strip_paragraph=True) }}</summary>
{{ section.value.contents|convert_markdown(heading_level, html_id) }}
</details>
```

It means you will be able to customize only *parts* of a template
Some of these templates define [Jinja blocks](https://jinja.palletsprojects.com/en/3.0.x/templates/#template-inheritance).
allowing to customize only *parts* of a template
without having to fully copy-paste it into your project:

```jinja title="templates/theme/docstring.html"
{% extends "_base/docstring.html" %}
```jinja title="templates/theme/class.html"
{% extends "_base/class.html" %}
{% block contents %}
{{ block.super }}
Additional contents
{% endblock contents %}
```

WARNING: **Block-level customization is not ready yet. We welcome [suggestions](https://github.com/mkdocstrings/python/issues/new).**
### Available blocks

Only the templates for the **Material for MkDocs** provide Jinja blocks.
The following tables show the block names, description,
and the Jinja context available in their scope.

#### `module.html`

- `heading`: The module heading.
- `labels`: The module labels.
- `contents`: The module contents: docstring and children blocks.
- `docstring`: The module docstring.
- `children`: The module children.

Available context:

- `config`: The handler configuration (dictionary).
- `module`: The [Module][griffe.dataclasses.Module] instance.

#### `class.html`

- `heading`: The class heading.
- `labels`: The class labels.
- `signature`: The class signature.
- `contents`: The class contents: bases, docstring, source and children blocks.
- `bases`: The class bases.
- `docstring`: The class docstring.
- `source`: The class source code.
- `children`: The class children.

Available context:

- `config`: The handler configuration (dictionary).
- `class`: The [Class][griffe.dataclasses.Class] instance.

#### `function.html`

- `heading`: The function heading.
- `labels`: The function labels.
- `signature`: The function signature.
- `contents`: The function contents: docstring and source blocks.
- `docstring`: The function docstring.
- `source`: The function source code.

Available context:

- `config`: The handler configuration (dictionary).
- `function`: The [Function][griffe.dataclasses.Function] instance.

#### `attribute.html`

- `heading`: The attribute heading.
- `labels`: The attribute labels.
- `signature`: The attribute signature.
- `contents`: The attribute contents: docstring block.
- `docstring`: The attribute docstring.

Available context:

- `config`: The handler configuration (dictionary).
- `function`: The [Attribute][griffe.dataclasses.Attribute] instance.

#### Docstring sections

In `docstring/attributes.html`, `docstring/other_parameters.html`, `docstring/parameters.html`, `docstring/raises.html`, `docstring/receives.html`, `docstring/returns.html`, `docstring/warns.html`, and `docstring/yields.html`:

- `table_style`: The section as a table.
- `list_style`: The section as a list.
- `spacy_style`: The section as a Spacy table.

Available context:

- `section`: The [DocstringSection][griffe.docstrings.dataclasses.DocstringSection] instance (see `DocstringSection*` subclasses).

## Style recommendations

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,37 @@
class="doc doc-heading",
toc_label=attribute.name) %}

{% if config.separate_signature %}
<span class="doc doc-object-name doc-attribute-name">{% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}</span>
{% else %}
{% filter highlight(language="python", inline=True) %}
{% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}
{% if attribute.annotation %}: {{ attribute.annotation }}{% endif %}
{% if attribute.value %} = {{ attribute.value }}{% endif %}
{% endfilter %}
{% endif %}
{% block heading scoped %}
{% if config.separate_signature %}
<span class="doc doc-object-name doc-attribute-name">{% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}</span>
{% else %}
{% filter highlight(language="python", inline=True) %}
{% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}
{% if attribute.annotation %}: {{ attribute.annotation }}{% endif %}
{% if attribute.value %} = {{ attribute.value }}{% endif %}
{% endfilter %}
{% endif %}
{% endblock heading %}

{% with labels = attribute.labels %}
{% include "labels.html" with context %}
{% endwith %}
{% block labels scoped %}
{% with labels = attribute.labels %}
{% include "labels.html" with context %}
{% endwith %}
{% endblock labels %}

{% endfilter %}

{% if config.separate_signature %}
{% filter highlight(language="python", inline=False) %}
{% filter format_code(config.line_length) %}
{% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}
{% if attribute.annotation %}: {{ attribute.annotation|safe }}{% endif %}
{% if attribute.value %} = {{ attribute.value|safe }}{% endif %}
{% block signature scoped %}
{% if config.separate_signature %}
{% filter highlight(language="python", inline=False) %}
{% filter format_code(config.line_length) %}
{% if show_full_path %}{{ attribute.path }}{% else %}{{ attribute.name }}{% endif %}
{% if attribute.annotation %}: {{ attribute.annotation|safe }}{% endif %}
{% if attribute.value %} = {{ attribute.value|safe }}{% endif %}
{% endfilter %}
{% endfilter %}
{% endfilter %}
{% endif %}
{% endif %}
{% endblock signature %}

{% else %}
{% if config.show_root_toc_entry %}
Expand All @@ -60,9 +66,13 @@
{% endif %}

<div class="doc doc-contents {% if root %}first{% endif %}">
{% with docstring_sections = attribute.docstring.parsed %}
{% include "docstring.html" with context %}
{% endwith %}
{% block contents scoped %}
{% block docstring scoped %}
{% with docstring_sections = attribute.docstring.parsed %}
{% include "docstring.html" with context %}
{% endwith %}
{% endblock docstring %}
{% endblock contents %}
</div>

{% endwith %}
Expand Down
131 changes: 73 additions & 58 deletions src/mkdocstrings_handlers/python/templates/material/_base/class.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,40 @@
class="doc doc-heading",
toc_label=class.name) %}

{% if config.separate_signature %}
<span class="doc doc-object-name doc-class-name">{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}</span>
{% elif config.merge_init_into_class and "__init__" in class.members -%}
{%- with function = class.members["__init__"] -%}
{%- filter highlight(language="python", inline=True) -%}
{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}
{%- include "signature.html" with context -%}
{%- endfilter -%}
{%- endwith -%}
{% else %}
<code>{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}</code>
{% endif %}
{% block heading scoped %}
{% if config.separate_signature %}
<span class="doc doc-object-name doc-class-name">{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}</span>
{% elif config.merge_init_into_class and "__init__" in class.members -%}
{%- with function = class.members["__init__"] -%}
{%- filter highlight(language="python", inline=True) -%}
{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}
{%- include "signature.html" with context -%}
{%- endfilter -%}
{%- endwith -%}
{% else %}
<code>{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}</code>
{% endif %}
{% endblock heading %}

{% with labels = class.labels %}
{% include "labels.html" with context %}
{% endwith %}
{% block labels scoped %}
{% with labels = class.labels %}
{% include "labels.html" with context %}
{% endwith %}
{% endblock labels %}

{% endfilter %}

{% if config.separate_signature and config.merge_init_into_class %}
{% if "__init__" in class.members %}
{% with function = class.members["__init__"] %}
{% filter format_signature(function, config.line_length, crossrefs=config.signature_crossrefs) %}
{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}
{% endfilter %}
{% endwith %}
{% block signature scoped %}
{% if config.separate_signature and config.merge_init_into_class %}
{% if "__init__" in class.members %}
{% with function = class.members["__init__"] %}
{% filter format_signature(function, config.line_length, crossrefs=config.signature_crossrefs) %}
{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}
{% endfilter %}
{% endwith %}
{% endif %}
{% endif %}
{% endif %}
{% endblock signature %}

{% else %}
{% if config.show_root_toc_entry %}
Expand All @@ -63,47 +69,56 @@
{% endif %}

<div class="doc doc-contents {% if root %}first{% endif %}">
{% if config.show_bases and class.bases %}
<p class="doc doc-class-bases">
Bases: {% for expression in class.bases -%}
<code>{% include "expression.html" with context %}</code>{% if not loop.last %}, {% endif %}
{% endfor -%}
</p>
{% endif %}

{% with docstring_sections = class.docstring.parsed %}
{% include "docstring.html" with context %}
{% endwith %}
{% block contents scoped %}
{% block bases scoped %}
{% if config.show_bases and class.bases %}
<p class="doc doc-class-bases">
Bases: {% for expression in class.bases -%}
<code>{% include "expression.html" with context %}</code>{% if not loop.last %}, {% endif %}
{% endfor -%}
</p>
{% endif %}
{% endblock bases %}

{% if config.merge_init_into_class %}
{% if "__init__" in class.members and class.members["__init__"].has_docstring %}
{% with docstring_sections = class.members["__init__"].docstring.parsed %}
{% block docstring scoped %}
{% with docstring_sections = class.docstring.parsed %}
{% include "docstring.html" with context %}
{% endwith %}
{% endif %}
{% endif %}
{% if config.merge_init_into_class %}
{% if "__init__" in class.members and class.members["__init__"].has_docstring %}
{% with docstring_sections = class.members["__init__"].docstring.parsed %}
{% include "docstring.html" with context %}
{% endwith %}
{% endif %}
{% endif %}
{% endblock docstring %}

{% if config.show_source %}
{% if config.merge_init_into_class %}
{% if "__init__" in class.members and class.members["__init__"].source %}
<details class="quote">
<summary>Source code in <code>{{ class.relative_filepath }}</code></summary>
{{ class.members["__init__"].source|highlight(language="python", linestart=class.members["__init__"].lineno, linenums=True) }}
</details>
{% block source scoped %}
{% if config.show_source %}
{% if config.merge_init_into_class %}
{% if "__init__" in class.members and class.members["__init__"].source %}
<details class="quote">
<summary>Source code in <code>{{ class.relative_filepath }}</code></summary>
{{ class.members["__init__"].source|highlight(language="python", linestart=class.members["__init__"].lineno, linenums=True) }}
</details>
{% endif %}
{% elif class.source %}
<details class="quote">
<summary>Source code in <code>{{ class.relative_filepath }}</code></summary>
{{ class.source|highlight(language="python", linestart=class.lineno, linenums=True) }}
</details>
{% endif %}
{% endif %}
{% elif class.source %}
<details class="quote">
<summary>Source code in <code>{{ class.relative_filepath }}</code></summary>
{{ class.source|highlight(language="python", linestart=class.lineno, linenums=True) }}
</details>
{% endif %}
{% endif %}
{% endblock source %}

{% with obj = class %}
{% set root = False %}
{% set heading_level = heading_level + 1 %}
{% include "children.html" with context %}
{% endwith %}
{% block children scoped %}
{% with obj = class %}
{% set root = False %}
{% set heading_level = heading_level + 1 %}
{% include "children.html" with context %}
{% endwith %}
{% endblock children %}
{% endblock contents %}
</div>

{% endwith %}
Expand Down
Loading

0 comments on commit 299fe48

Please sign in to comment.