Skip to main content

Ouroboros Jinja

Expand Jinja2 templates that back-reference other values in the same document — the snake eats its own tail.

# defaults.yaml
slug: ~
domain: "{{ slug }}.nimbus.fi"
volume-name: "{{ slug }}-volume"
permanent-ip-name: "{{ domain }}"
# server.toml
name = "Prominence 2: Hasturian Era"
slug = "hasturian"
import ouroboros_jinja

config = ouroboros_jinja.load("defaults.yaml", "server.toml")
# {
#   "slug": "hasturian",
#   "domain": "hasturian.nimbus.fi",
#   "volume-name": "hasturian-volume",
#   "permanent-ip-name": "hasturian.nimbus.fi",
#   "name": "Prominence 2: Hasturian Era"
# }

API

  • expand(*mappings) — deep-merge mappings (later ones win) and expand every string value as a Jinja2 template.
  • loads(*yaml_texts) — parse YAML texts, merge and expand.
  • load(*paths) — read files (.toml via tomllib, everything else as YAML), merge and expand.

Templates may reference any top-level key, including nested content ({{ an_object.description }}) and lists ({% for port in ports %}). Values are expanded lazily and recursively, in dependency order.

Merging

When several documents are given, nested mappings are merged key by key, so a later document can override one leaf without restating its siblings:

# assets.yaml
assets:
    tractor:
        name: "Aurora"
    trailer:
        name: "Beatrice"
stack:
    engine: "{{ assets.tractor.name }}"
    payload: "{{ assets.trailer.name }}"
# addon.yaml
assets:
    tractor:
        name: "Charlie"

load("assets.yaml", "addon.yaml") keeps assets.trailer and only replaces assets.tractor.name, so stack.engine expands to "Charlie" and stack.payload to "Beatrice".

Anything that is not a mapping on both sides is replaced outright — a list in a later document wins over an earlier list, it is not concatenated. The input mappings are never mutated.

Semantics

  • Reference cycles raise CircularReferenceError with the chain spelled out: Circular reference detected: item_1 -> item_2 -> item_3 -> item_1.
  • Unknown variables raise ExpansionError (Jinja2 StrictUndefined).
  • A top-level key with a null value (slug: ~) is a required override: referencing it before it has been overridden raises ExpansionError instead of silently interpolating "None".
  • Only strings containing {{ or {% are touched; other values (ints, lists, …) pass through unchanged.

Testing

uv run pytest

Metadata

Release files for ouroboros-jinja 1.1.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 ouroboros-jinja 1.1.0
File Size Uploaded Provenance Actions
ouroboros_jinja-1.1.0.tar.gz 29.5 kB Without provenance Details for ouroboros_jinja-1.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ouroboros-jinja 1.1.0
File Interpreter ABI Platform Actions
ouroboros_jinja-1.1.0-py3-none-any.whl Python 3 none any Details for ouroboros_jinja-1.1.0-py3-none-any.whl

Total release size: 34.7 kB

Release files / ouroboros_jinja-1.1.0.tar.gz

Download URL ouroboros_jinja-1.1.0.tar.gz
Size 29.5 kB
Tags Source
SHA-256 checksum
How to use checksums
4ac0a368e1bc48e491cec72a0891531b5f8499f8305c8c71aa43b725bd04a81f
BLAKE2b-256 checksum
How to use checksums
a53aaaaaa51bd0b623540a804060f7628806d87f3baea9a5f19c13731eebb0fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / ouroboros_jinja-1.1.0-py3-none-any.whl

Download URL ouroboros_jinja-1.1.0-py3-none-any.whl
Size 5.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
986b81707125bac470c0d31abb4dfa37c538a7698e9848c447cdf7e77ae1f476
BLAKE2b-256 checksum
How to use checksums
aba5e5d6017c13f055f208fc66da1fcf3a79f37f9286b71fa8290486a85e4b53
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for ouroboros-jinja 1.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.

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