Metadata-Version: 2.1
Name: minijinja
Version: 0.30.2
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Environment :: Web Environment
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Topic :: Text Processing :: Markup :: HTML
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
License-File: LICENSE
Summary: An experimental Python binding of the Rust MiniJinja template engine.
Keywords: jinja,template-engine
Author-email: Armin Ronacher <armin.ronacher@active-4.com>
Maintainer-email: Armin Ronacher <armin.ronacher@active-4.com>
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Repository, https://github.com/mitsuhiko/minijinja
Project-URL: Issue Tracker, https://github.com/mitsuhiko/minijinja/issues
Project-URL: Donate, https://github.com/sponsors/mitsuhiko

<div align="center">
  <img src="https://github.com/mitsuhiko/minijinja/raw/main/artwork/logo.png" alt="" width=320>
  <p><strong>MiniJinja for Python: a powerful template engine for Rust and Python</strong></p>

[![Build Status](https://github.com/mitsuhiko/minijinja/workflows/Tests/badge.svg?branch=main)](https://github.com/mitsuhiko/minijinja/actions?query=workflow%3ATests)
[![License](https://img.shields.io/github/license/mitsuhiko/minijinja)](https://github.com/mitsuhiko/minijinja/blob/main/LICENSE)
[![Crates.io](https://img.shields.io/crates/d/minijinja.svg)](https://crates.io/crates/minijinja)
[![rustc 1.61.0](https://img.shields.io/badge/rust-1.61%2B-orange.svg)](https://img.shields.io/badge/rust-1.61%2B-orange.svg)
[![Documentation](https://docs.rs/minijinja/badge.svg)](https://docs.rs/minijinja)

</div>

`minijinja-py` is an experimental binding of
[MiniJinja](https://github.com/mitsuhiko/minijinja) to Python.  It has somewhat
limited functionality compared to the Rust version.  These bindings use
[maturin](https://www.maturin.rs/) and [pyo3](https://pyo3.rs/).

You might want to use MiniJinja instead of Jinja2 when the full feature set
of Jinja2 is not required and you want to have the same rendering experience
of a data set between Rust and Python.

With these bindings MiniJinja can render some Python objects and values
that are passed to templates, but there are clear limitations with regards
to what can be done.

To install MiniJinja for Python you can fetch the package [from PyPI](https://pypi.org/project/minijinja/):

```
$ pip install minijinja
```

## Basic API

The basic API is hidden behind the `Environment` object.  It behaves almost entirely
like in `minijinja` with some Python specific changes.  For instance instead of
`env.set_debug(True)` you use `env.debug = True`.  Additionally instead of using
`add_template` or attaching a `source` you either pass a dictionary of templates
directly to the environment or a `loader` function.

```python
from minijinja import Environment

env = Environment(templates={
    "template_name": "Template source"
})
```

To render a template you can use the `render_template` method:

```python
result = env.render_template('template_name', var1="value 1", var2="value 2")
print(result)
```

## Purpose

MiniJinja attemps a certain level of compatibiliy with Jinja2, but it does not
try to achieve this at all costs.  As a result you will notice that quite a few
templates will refuse to render with MiniJinja despite the fact that they probably
look quite innocent.  It is however possible to write templates that render to the
same results for both Jinja2 and MiniJinja.  This raises the question why you might
want to use MiniJinja.

The main benefit would be to achieve the exact same results in both Rust and Python.
Additionally MiniJinja has a stronger sandbox than Jinja2 and might perform ever so
slightly better in some situations.  However you should be aware that due to the
marshalling that needs to happen in either direction there is a certain amount of
loss of information.

## Dynamic Template Loading

MiniJinja's Python bindings inherit the underlying behavior of how MiniJinja loads
templates.  Templates are loaded on first use and then cached.  The templates are
loaded via a "source" (called `loader` in MiniJinja's Python bindings).  To trigger
a reload you can call `env.reload()` or alternatively set `env.reload_before_render`
to `True`.

```python
def my_loader(name):
    segments = []
    for segment in name.split("/"):
        if "\\" in segment or segment in (".", ".."):
            return None
        segments.append(segment)
    try:
        with open(os.path.join(TEMPLATES, *segments)) as f:
            return f.read()
    except (IOError, OSError):
        pass

env = Environment(loader=my_loader)
env.reload_before_render = True
print(env.render_template("index.html"))
```

Alternatively templates can manually be loaded and unloaded with `env.add_template`
and `env.remove_template`.

## Auto Escaping

The default behavior is to use auto escaping file files ending in `.html`.  You can
customize this behavior by overriding the `auto_escape_callback`:

```python
env = Environment(auto_escape_callback=lambda x: x.endswith((".html", ".foo")))
```

MiniJinja uses [markupsafe](https://github.com/pallets/markupsafe) if it's available
on the Python side.  It will honor `__html__`.

## State Access

Functions passed to the environment such as filters or global functions can
optionally have the template state passed by using the `pass_state` parameter.
This is similar to `pass_context` in Jinja2.  It can be used to look at the
name of the template or to look up variables in the context.

```python
from minijinja import pass_state

@pass_state
def my_filter(state, value):
    return state.lookup("a_variable") + value

env.add_filter("add_a_variable", my_filter)
```

## Runtime Behavior

MiniJinja uses it's own runtime model which is not matching the Python
runtime model.  As a result there are clear gaps in beahvior between the
two and only limited effort is made to bridge them.  For instance you will
be able to call some methods of types, but for instance builtins such as
dicts and lists do not expose their methods on the MiniJinja side.  This
means that it's very intentional that if you pass a dictionary to MiniJinja,
the Python `.items()` method is unavailable.

Here is what this means for some basic types:

* Python dictionaries and lists (as well as other objects that behave as sequences)
  appear in the MiniJinja side as native lists.  They do not expose any specific
  other behavior and when they move back to the Python side they will appear as basic
  lists.  Specifically this means that a tuple (which does not exist in MiniJinja)
  when moving from Python to MiniJinja turns into a list and will remain a list when
  it moves back.
* Python objects are represented in MiniJinja similarly to dicts, but they retain all
  their meaningful Python APIs.  This means they stringify via `__str__` and they
  allow the MiniJinja code to call their non-underscored methods.  Note that there is
  no extra security layer in use at the moment so take care of what you pass there.
* MiniJinja's python binding understand what `__html__` is when it exists on a string
  subclass.  This means that a `markupsafe.Markup` object will appear as safe string in
  MiniJinja.  This information can also flow back to Python again.

## Sponsor

If you like the project and find it useful you can [become a
sponsor](https://github.com/sponsors/mitsuhiko).

## License and Links

- [Documentation](https://docs.rs/minijinja/)
- [Examples](https://github.com/mitsuhiko/minijinja/tree/main/examples)
- [Issue Tracker](https://github.com/mitsuhiko/minijinja/issues)
- [MiniJinja Playground](https://mitsuhiko.github.io/minijinja-playground/)
- License: [Apache-2.0](https://github.com/mitsuhiko/minijinja/blob/main/LICENSE)

