Skip to main content

Minimal Liquid-like templating

Project description

micro-liquid


Table of Contents

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 (include and render). Or any tag other than if and for.
  • Relational operators like == and <.
  • Membership operators like contains and in.
  • Filters.
  • Literal Booleans, integers, floats or null/nil/None.
  • {% break %} and {% continue %} tags.
  • Nested variables.
  • forloop helper variables.
  • for tag arguments like limit and reversed.

Other notable behavior

  • We use Python truthiness, not Liquid or Ruby truthiness.
  • Any Iterable can 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

micro_liquid-0.1.0.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

micro_liquid-0.1.0-py3-none-any.whl (25.2 kB view details)

Uploaded Python 3

File details

Details for the file micro_liquid-0.1.0.tar.gz.

File metadata

  • Download URL: micro_liquid-0.1.0.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.10

File hashes

Hashes for micro_liquid-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1ccb6f738231f237ab7e2d32f7e642df81bcc4ea786d24976a62e31165ba5d0b
MD5 1c24fcdad5f23760254a1d64b3948d37
BLAKE2b-256 f435398c85906f5551d05ba136a87c4ee2cd492695f13b9d51902c1bda484101

See more details on using hashes here.

File details

Details for the file micro_liquid-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: micro_liquid-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.10

File hashes

Hashes for micro_liquid-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aaf4ae7e31d0eff99279ed06de26b85b459e71997c1e1a822f95d1839d098788
MD5 706a7b1b6c901f751d67f87d1e507725
BLAKE2b-256 4ff06e3754cbdebce5552411b98dc12d765a3253239ffff785e1f6452648a74c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page