Skip to content

Write a template plugin¤

To show how to write a template plugin, we will create a new, minimal Python package.

Its structure will be like the following:

.
├── setup.py
└── src
    └── package_name
        ├── __init__.py
        └── data
            └── my_template

In src/package_name/__init__.py, we are simply going to import the Template class from shellman, and define an instance of it:

# __init__.py

import os
from shellman import Template

data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")

my_template = Template(data_path, "my_template")

In setup.py, we then add a shellman entrypoint pointing to that template:

# setup.py

from setuptools import setup

setup(..., entrypoints={"shellman": ["my_template_name = package_name:my_template"]})

Instead of pointing to an instance of Template, you can also point to a dictionary of templates. This is useful if you want to set aliases for the same template (like my_template, my_template.md, my_template.markdown).

# __init__.py

import os
from shellman import Template

data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")

my_template = Template(data_path, "my_template")

template_dict = {
    "my_template": my_template,
    "my_template.md": my_template,
    "my_template.markdown": my_template,
}
# setup.py

from setuptools import setup

setup(..., entrypoints={"shellman": ["unused_dict_name = package_name:template_dict"]})

Similarly, you could do it with entrypoints only:

# setup.py

from setuptools import setup

setup(
    ...,
    entrypoints={
        "shellman": [
            "my_template = package_name:my_template",
            "my_template.md = package_name:my_template",
            "my_template.markdown = package_name:my_template",
        ]
    },
)

The template itself¤

Please read Jinja2's documentation for more information about how to write templates.

You can also take a look at the source code for the builtin templates on GitHub.

Adding context and Jinja filters¤

You can specify a default context and default filters to use within your template:

def do_url(obj):
    return "https://{}/{}/{}".format(obj.domain, obj.namespace, obj.name)


my_template = Template(data_path, "my_template", context={"indent": 4}, filters={"url": do_url})

In your template, you will then have access to the {{ my_object|url }} filter, as well as the {{ indent }} variable, which could be used like {{ indent * " " }}.