micro-liquid
Table of Contents
- Install
- Example
- About
- What's included?
- What's not included?
- Undefined variables
- Serializing objects
- License
Install
pip install micro-liquid
Example
from micro_liquid import Template
template = Template("Hello, {{ you }}!")
print(template.render({"you": "World"})) # Hello, World!
About
Micro Liquid implements minimal, Liquid-like templating. You can think of it as a non-evaluating alternative to f-strings or t-strings, where templates are data and not necessarily string literals inside Python source files.
Full-featured Liquid (Python Liquid or Shopify/liquid, for example) caters for situations where end users manage their own templates. In this scenario, it's reasonable to expect some amount of application/display logic to be embedded within template text. In other scenarios we'd very much want to keep application logic out of template text.
With that in mind, Micro Liquid offers a greatly reduced feature set, implemented in a single Python file, so you can copy and paste it and hack on it if needed.
Here, developers are expected to fully prepare data passed to Template.render() instead of manipulating and inspecting it within template markup.
What's included?
Micro Liquid support variable substitution:
Hello, {{ some_variable }}. How are you?
Conditional expressions:
{% if some_variable %}
more markup
{% elsif another_variable %}
alternative markup
{% else %}
default markup
{% endif %}
And looping:
{% for x in y %}
more markup with {{ x }}
{% else %}
default markup (y was empty or not iterable)
{% endfor %}
Micro Liquid expressions can use logical and, or and not, and group terms with parentheses.
{% if not some_variable and another_variable %}
some markup with {{ some_variable }} and {{ another_variable }}.
{% endif %}
Short circuit evaluation works too, with last value semantics. Here you might use a string literal.
Hello, {{ user.name or "guest" }}!
Control whitespace before and after markup delimiters with - and ~. ~ will remove newlines but retain space and tab characters. - strips all whitespace.
<ul>
{% for x in y ~%}
<li>{{ x }}</li>
{% endfor -%}
</ul>
What's not included?
If you need any of these features, and many more, try Python Liquid or Python Liquid2 instead.
- Assignment, captures and snippets (
includeandrender). Or any tag other thanifandfor. - Relational operators like
==and<. - Membership operators like
containsandin. - Filters.
- Literal Booleans, integers, floats or null/nil/None.
{% break %}and{% continue %}tags.- Nested variables.
forloophelper variables.fortag arguments likelimitandreversed.
Other notable behavior
- We use Python truthiness, not Liquid or Ruby truthiness.
- Any
Iterablecan be looped over with the{% for %}tag. Non-iterable objects are silently ignored. - Looping over dictionaries (or any Mapping) iterates key/value pairs.
Undefined variables
When a template variable or property can't be resolved, an instance of the undefined type is used instead. That is, an instance of micro_liquid.Undefined or a subclass of it.
The default undefined type renders nothing when output, evaluates to False when tested for truthiness and is an empty iterable when looped over. You can pass an alternative undefined type as the undefined keyword argument to the Template constructor to change this behavior.
from micro_liquid import StrictUndefined
from micro_liquid import Template
t = Template("{{ foo.nosuchthing }}", undefined=StrictUndefined)
print(t.render({"foo": {}}))
# micro_liquid.UndefinedVariableError: 'foo.nosuchthing' is undefined
# -> '{{ foo.nosuchthing }}':1:3
# |
# 1 | {{ foo.nosuchthing }}
# | ^^^ 'foo.nosuchthing' is undefined
Or implement your own.
from typing import Iterator
from micro_liquid import Template
from micro_liquid import Undefined
class MyUndefined(Undefined):
def __str__(self) -> str:
return "<MISSING>"
def __bool__(self) -> bool:
return False
def __iter__(self) -> Iterator[object]:
yield from ()
t = Template("{{ foo.nosuchthing }}", undefined=MyUndefined)
print(t.render({"foo": {}})) # <MISSING>
Serializing objects
By default, when outputting an object with {{ and }}, lists, dictionaries and tuples are rendered in JSON format. For all other objects we render the result of str(obj).
You can change this behavior by passing a callable to the Template constructor or render function as the serializer keyword argument. The callable should accept an object and return its string representation suitable for output.
This example shows how one might define a serializer that can dump data classes with json.dumps.
import json
from dataclasses import asdict
from dataclasses import dataclass
from dataclasses import is_dataclass
from micro_liquid import Template
@dataclass
class SomeData:
foo: str
bar: int
def json_default(obj: object) -> object:
if is_dataclass(obj) and not isinstance(obj, type):
return asdict(obj)
raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable")
def my_serializer(obj: object) -> str:
return (
json.dumps(obj, default=json_default)
if isinstance(obj, (list, dict, tuple))
else str(obj)
)
template = Template("{{ some_object }}", serializer=my_serializer)
data = {"some_object": [SomeData("hello", 42)]}
print(template.render(data)) # [{"foo": "hello", "bar": 42}]
TODO: Walk syntax tree
License
micro-liquid is distributed under the terms of the MIT license.
Metadata
Release files for micro-liquid 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| micro_liquid-0.1.0.tar.gz | 15.5 kB | Without provenance | Details for micro_liquid-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| micro_liquid-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for micro_liquid-0.1.0-py3-none-any.whl |
Total release size: 40.7 kB
Release files / micro_liquid-0.1.0.tar.gz
| Download URL | micro_liquid-0.1.0.tar.gz |
|---|---|
| Size | 15.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1ccb6f738231f237ab7e2d32f7e642df81bcc4ea786d24976a62e31165ba5d0b
|
|
BLAKE2b-256 checksum How to use checksums |
f435398c85906f5551d05ba136a87c4ee2cd492695f13b9d51902c1bda484101
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.10
|
Release files / micro_liquid-0.1.0-py3-none-any.whl
| Download URL | micro_liquid-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
aaf4ae7e31d0eff99279ed06de26b85b459e71997c1e1a822f95d1839d098788
|
|
BLAKE2b-256 checksum How to use checksums |
4ff06e3754cbdebce5552411b98dc12d765a3253239ffff785e1f6452648a74c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.10
|
Security for micro-liquid 0.1.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.