Skip to main content

Jinja Macro Tags

Jinja Macro Tags introduces an HTML-like syntax to call Jinja macros, as well as a macro registry that automatically imports macros where they are used.

<{panel title="Hello"}>
    <{button "click me" style="primary"}/>
</{panel}>

This is a maintained fork of maximebf/jinja-macro-tags, published on PyPI as jinja-macro-tags-pakal.

Installation

pip install jinja-macro-tags-pakal

Requires Python 3.11+ and Jinja2 2.11+ (Jinja 3.x is supported). Windows, Linux and macOS are supported.

The distribution name differs from the module name, which is still jinja_macro_tags:

import jinja_macro_tags

Quick start

The simplest setup is configure_environment(), which enables both macro tags and the macro registry:

from jinja2 import Environment, FileSystemLoader
from jinja_macro_tags import configure_environment

env = Environment(loader=FileSystemLoader("templates"))
configure_environment(env)
env.macros.register_file("macros.html")

print(env.get_template("form.html").render())

macros.html:

{% macro form(action) -%}
    <form action="{{ action }}" method="post">
        {{ caller() }}
    </form>
{%- endmacro %}

{% macro form_input(name) -%}
    <input type="text" name="{{ name }}">
{%- endmacro %}

templates/form.html:

<{form action="/" }>
    <{form_input name="email" }/>
</{form}>

No {% import %} statement is needed: the registry knows where form and form_input are defined and imports them automatically.

Macro tags

Macro tags let you call macros with a syntax similar to HTML tags. There are two kinds of macro tags: inline and block. Inline tags are the equivalent of calling the macro with {{ macro_name() }}; block tags are the equivalent of the {% call %} directive.

Arguments are written like HTML attributes, but their values are Jinja expressions, so string literals must be quoted (label="ok"), while label=user.name passes a variable. Positional arguments are also supported (<{button "ok"}/>).

Since arguments are separated by whitespace rather than commas, a couple of expression forms are ambiguous and get rejected with a clear error instead of being silently misinterpreted: adjacent string literals (<{button "a" "b"}/>, which Jinja would otherwise concatenate into a single "ab" argument — use ~ if that's what you want), and a bare +/- at the start of an argument (<{button x -1}/>, which could be x - 1 or two separate arguments x, -1 — wrap it in parentheses, <{button (x - 1)}/>, to disambiguate).

Jinja-style tags

Inline tags are enclosed in <{ and }/>:

<{macro_name arg1=value1 arg2=value2 }/>

is equivalent to:

{{ macro_name(arg1=value1, arg2=value2) }}

Block tags start with an opening tag enclosed in <{ and }> and must be closed with </{macro_name}> (the macro name is optional in the closing tag, </{}> works too; when given, it must match the innermost open tag, or you'll get a clear error instead of silently mismatched nesting):

<{macro_name arg1=value1 arg2=value2 }>
    my macro content
</{macro_name}>

is equivalent to:

{% call macro_name(arg1=value1, arg2=value2) %}
    my macro content
{% endcall %}

HTML-style tags

HTML-style tags use an m: namespace prefix instead. Dashes in macro names are converted to underscores, so <m:form-input> calls form_input:

<m:panel title="test panel">
    <m:form-input name="email" />
</m:panel>

Enabling macro tags manually

If you don't use configure_environment(), add the extensions yourself:

from jinja2 import Environment, PackageLoader

env = Environment(loader=PackageLoader(__name__, "templates"))
env.add_extension("jinja_macro_tags.LoadMacroExtension")
env.add_extension("jinja_macro_tags.CallMacroTagExtension")
env.add_extension("jinja_macro_tags.JinjaMacroTagsExtension")  # <{...}/> tags
env.add_extension("jinja_macro_tags.HtmlMacroTagsExtension")   # <m:.../> tags

When added this way, macros are not autoloaded and you still need your {% import %} statements. Set env.autoload_macro_tags = True to let tags autoload macros from the registry.

Macro registry

The macro registry lets you load macros by name. Macros can be registered from templates available through your loader, and also from any Jinja file that your loader can't reach.

Used together with macro tags, the registry means you don't even need to load macros: the tags use it to load them automatically.

The registry requires two things:

  • wrapping your template loader in an instance of jinja_macro_tags.MacroLoader
  • adding the jinja_macro_tags.LoadMacroExtension extension

configure_environment() does both for you:

configure_environment(
    env,
    wrap_loader=True,       # wrap env.loader in a MacroLoader
    with_jinja_tags=True,   # enable <{...}/> tags
    with_html_tags=False,   # enable <m:.../> tags
)

To use the registry without macro tags:

configure_environment(env, with_jinja_tags=False)

Once configured, the registry is available through the macros attribute of the environment.

Register macros from templates available through your loader:

  • register_from_template(template): register all macros defined in the template
  • register(name, template): register the named macro, which is defined in the template
  • register_from_environment(): register macros from every .html template that the loader can list

Register macros from files your environment loader can't reach:

  • register_file(filename, alias=None)
  • register_directory(path, prefix=None)
  • register_package(package_name, package_path="macros", prefix=None)
  • register_loader(loader, prefix=None)

Files added with these methods can be reached from your environment under the __macros__/ prefix.

All registration methods take a replace argument. By default, registering a macro name twice raises an exception; pass replace=True to override the previous definition.

Create macro aliases with alias(name, alias):

env.macros.alias("form_input", "input")   # <{input name="email"}/>

The load_macro directive

To load registered macros explicitly, use the load_macro directive. It takes a list of macro names:

{% load_macro form, form_input %}

You don't need it if you use macro tags with autoloading enabled.

Development

pip install -e ".[test]"
pytest --cov

To run the test suite against every supported Python version (3.11 to 3.14), with both Jinja 2.x and Jinja 3.x:

tox

Changelog

See CHANGELOG.md.

License

MIT, see LICENSE.

Metadata

Release files for jinja-macro-tags-pakal 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jinja-macro-tags-pakal 1.0.0
File Size Uploaded Provenance
jinja_macro_tags_pakal-1.0.0.tar.gz 17.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for jinja-macro-tags-pakal 1.0.0
File Interpreter ABI Platform
jinja_macro_tags_pakal-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.1 kB

Release files / jinja_macro_tags_pakal-1.0.0.tar.gz

Download URL jinja_macro_tags_pakal-1.0.0.tar.gz
Size 17.4 kB
Tags Source
SHA-256 checksum
How to use checksums
06d962cd5638382beb9e2863354db03396ab3551b72192556cb2a2a772b5e0b8
BLAKE2b-256 checksum
How to use checksums
b9c48d85d8522a9227376d21192de93348aa5df8f4b24d1fbd8d94d0635bf9c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.2

Release files / jinja_macro_tags_pakal-1.0.0-py3-none-any.whl

Download URL jinja_macro_tags_pakal-1.0.0-py3-none-any.whl
Size 9.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3bd12a20fdbef0520be133413bb6debf01e32c8e062da472b1f17ac15c00b448
BLAKE2b-256 checksum
How to use checksums
07a4e9f25e6a76e6efbe698d3827dc895bab5ae4fb0bb9c28b30cf5ace366560
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.2

Security for jinja-macro-tags-pakal 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page