jinja_md.py
The markata.plugins.jinja_md
plugin enables Jinja2 templating within your markdown
content. This allows you to dynamically generate content using Python expressions and
access to the full Markata context.
Installation
This plugin is built-in and enabled by default through the 'default' plugin. If you want to be explicit, you can add it to your list of plugins:
hooks = [ "markata.plugins.jinja_md", ]
Uninstallation
Since this plugin is included in the default plugin set, to disable it you must explicitly add it to the disabled_hooks list if you are using the 'default' plugin:
disabled_hooks = [ "markata.plugins.jinja_md", ]
Configuration
Configure Jinja markdown settings in your markata.toml
:
[markata.jinja_md] # List of files to ignore for Jinja processing ignore = [ "README.md", "CHANGELOG.md" ]
Functionality
Template Variables
Your markdown has access to:
post
: The current post being renderedmarkata
: The Markata instance with all configuration and posts
Example Usage
Access Post Metadata
# {{ post.title }} {{ post.description }} Published on: {{ post.date.strftime('%Y-%m-%d') }}
Generate Link Lists
{# One-liner list of all posts #} {{ '\n'.join(markata.map('f"* [{title}]({slug})"', sort='slug')) }} {# For-loop with filtering #} {% for post in markata.map('post', filter='"git" in tags') %} * [{{ post.title }}]({{ post.slug }}) {% endfor %}
Include Raw Files
{# Include file contents without processing #} {% include_raw 'code/example.py' %}
Jinja Extensions
The plugin supports:
- Custom extensions via entrypoints
- Built-in extensions like include_raw
- Silent undefined variables
- Custom error messages
Error Handling
The plugin provides:
- Custom error messages for template syntax errors
- Silent handling of undefined variables
- Detailed error reporting with file and line info
Dependencies
This plugin depends on:
- Jinja2 for template processing
- The
render_markdown
plugin for final HTML rendering
Function
register_jinja_extensions function
Gets jinja extensions from entrypoints and loads them in.
Returns: List of jinja Extensions
register_jinja_extensions source
def register_jinja_extensions(config: dict) -> List[Extension]: """ Gets jinja extensions from entrypoints and loads them in. Returns: List of jinja Extensions """ import pkg_resources return [ ep.load() for ep in pkg_resources.iter_entry_points(group="markata.jinja_md") ]
Class
_SilentUndefined class
silence undefined variable errors in jinja templates.
Example
template = '{{ variable }}' post.content = Template( template, undefined=_SilentUndefined).render()
_SilentUndefined source
class _SilentUndefined(Undefined): """ silence undefined variable errors in jinja templates. # Example ```python template = '{{ variable }}' post.content = Template( template, undefined=_SilentUndefined).render() ``` """ def _fail_with_undefined_error(self, *args, **kwargs): return ""
Class
PostTemplateSyntaxError class
Custom error message for post template syntax errors.
PostTemplateSyntaxError source
class PostTemplateSyntaxError(TemplateSyntaxError): """ Custom error message for post template syntax errors. """
Function
pre_render function
jinja_md hook for markata to render your markdown post as a jinja template.
The post itself is exposed as post
, and the markata instance is exposed
as markata
.
pre_render source
def pre_render(markata: "Markata") -> None: """ jinja_md hook for markata to render your markdown post as a jinja template. The post itself is exposed as `post`, and the markata instance is exposed as `markata`. """ config = markata.config.jinja_md ignore_spec = pathspec.PathSpec.from_lines("gitwildmatch", config.ignore) # for post in markata.iter_articles(description="jinja_md"): # jinja_env = jinja2.Environment( # extensions=[IncludeRawExtension, *register_jinja_extensions(config)], # ) jinja_env = markata.config.jinja_env jinja_env.undefined = _SilentUndefined for post in markata.filter("jinja==True"): if post.get("jinja", True) and not ignore_spec.match_file(post["path"]): try: key = markata.make_hash("jina_md", "pre_render", post.content) content_from_cache = markata.precache.get(key) if content_from_cache is None and post.content is not None: post.content = jinja_env.from_string(post.content).render( __version__=__version__, markata=markata, body=post.article_html, config=markata.config, post=post, ) with markata.cache: markata.cache.set(key, post.content) else: post.content = content_from_cache # prevent double rendering post.jinja = False except TemplateSyntaxError as e: errorline = post.content.split("\n")[e.lineno - 1] msg = f""" Error while processing post {post["path"]} {errorline} """ raise PostTemplateSyntaxError(msg, lineno=e.lineno) except UndefinedError as e: raise UndefinedError(f"{e} in {post['path']}")