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 (.tomlviatomllib, 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
CircularReferenceErrorwith the chain spelled out:Circular reference detected: item_1 -> item_2 -> item_3 -> item_1. - Unknown variables raise
ExpansionError(Jinja2StrictUndefined). - A top-level key with a null value (
slug: ~) is a required override: referencing it before it has been overridden raisesExpansionErrorinstead 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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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.