TOML configuration loader with include/merge/interpolation
Project description
tomlstack
tomlstack is a lightweight TOML config loader for Python 3.11+ with:
- top-level
includeloading - include-tree inspection with raw and resolved paths
- deterministic merge by include order
${path}interpolation with cycle/undefined checks- node-level provenance (
origin,history,dependencies)
tomlstack does not try to be a configuration framework. It addresses two missing pieces in TOML: file composition and safe interpolation, while keeping files self-contained and explainable.
Install
pip install tomlstack
Quick Start
main.toml:
include = [
"./base.toml",
"./prod.toml",
]
[db]
url = "postgres://${db.user}:${db.pass}@${db.host}:${db.port}"
base.toml:
[db]
user = "alice"
pass = "secret"
host = "localhost"
port = 5432
Python:
from tomlstack import TomlNode, load
cfg = load("main.toml")
print(cfg["db"]["url"].raw) # raw interpolation string
print(cfg["db"]["url"].value) # resolved value
print(cfg["db"]["url"].origin)
print(cfg["db"]["url"].history)
print(cfg["db"]["url"].dependencies)
print(cfg["db"]["url"].explain())
print(cfg.raw) # raw configuration snapshot
print(cfg.to_dict()) # resolved configuration snapshot
Include Semantics
- top-level
includeonly; nestedincludeis treated as normal data - syntax: string or list of strings
- valid include path forms:
./...or../...@label/...(label fromtomlstack.anchors)- absolute path
- any other form raises an error with a path-format hint
Meta Include Directives
[tomlstack.anchors]
proj = "./shared"
- anchors are local to the file that declares them
- anchor path values must be absolute or start with
./or../
Merge Rules
Load order for current file:
- merge first include
- merge second include
- ...
- merge current file (highest priority)
Conflict behavior:
- dict: recursive merge, later wins on key conflict
- list: later value replaces whole list
- scalar: later value replaces earlier
Interpolation Semantics
- interpolation is resolved lazily by
cfg.resolve(),cfg.to_dict(), ornode.value - path syntax supports dot and list index:
${db.apps[0]} - full-string interpolation (
"${db.port}") keeps source type - embedded interpolation (
"postgres://${db.host}:${db.port}") allows only:str,int,float,bool,date,time,datetime
- formatting syntax:
${path:spec} - for
date/time/datetime, formatting usesstrftime - otherwise uses Python
format(value, spec) - invalid interpolation syntax and formatting failures raise
InterpolationError - undefined references raise
InterpolationUndefinedError - interpolation cycles raise
InterpolationCycleError
Invalid TOML raises TomlFormatError; invalid include paths and anchors raise
IncludeError.
Public API
cfg = load("f.toml")cfg.raw— raw configuration snapshotcfg.resolve()cfg.to_dict()— resolved configuration snapshotcfg.include_tree—IncludeNodeload-occurrence treecfg.include_tree.render()— render raw include referencescfg.include_tree.render(absolute=True)— include references with resolved pathsnode: TomlNode = cfg["proj"][0]["path"]["foo"]node.rawnode.valuenode.originnode.historynode.dependencies— direct interpolation dependenciesnode.explain()— transitive interpolation tracenode.preview()cfg.to_toml()->NotImplementedError
cfg.raw, cfg.to_dict(), node.raw, and node.value return independent data
snapshots; mutating their dictionaries or lists does not modify the loaded
configuration. TomlNode instances are created by configuration navigation and are
not constructed directly.
History records definitions of the same data path from lowest to highest priority.
When a list or value type is replaced, its old child paths are discarded. Resolving an
interpolation does not change the history of the node containing the expression.
Each history entry is a TomlFile with its raw reference and resolved absolute
path.
Dependencies describe interpolation separately from merge history. A full replacement
such as target = "${source}" leaves target.history at the file that defined
target, while target.dependencies records the source path and its history.
Current Limitations
- interpolation path parser supports unquoted dot keys and numeric list indices
- no nested interpolation expressions
to_toml()is not implemented yet
Release To PyPI
Build package:
uv run --with build python -m build
Upload to TestPyPI first:
uv run --with twine python -m twine upload --repository testpypi dist/*
Verify install from TestPyPI:
python -m pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple tomlstack
Upload to PyPI:
uv run --with twine python -m twine upload dist/*
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tomlstack-0.2.0rc1.tar.gz.
File metadata
- Download URL: tomlstack-0.2.0rc1.tar.gz
- Upload date:
- Size: 73.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7852d48ce4104d35eac527ef9081a8e731f33295dfa010423522d8b1ef133e1a
|
|
| MD5 |
ff265e28cfb7d14625feeb86f27a8b1d
|
|
| BLAKE2b-256 |
60fb294f694aa8b65b887080ae2ea5132266609a12e73b757e540e61efd5dd88
|
Provenance
The following attestation bundles were made for tomlstack-0.2.0rc1.tar.gz:
Publisher:
publish-pypi.yml on WXZhao7/tomlstack
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tomlstack-0.2.0rc1.tar.gz -
Subject digest:
7852d48ce4104d35eac527ef9081a8e731f33295dfa010423522d8b1ef133e1a - Sigstore transparency entry: 1934956926
- Sigstore integration time:
-
Permalink:
WXZhao7/tomlstack@1b6be07de0f10ac3b65e90a26c6293ec5fe14a5e -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/WXZhao7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@1b6be07de0f10ac3b65e90a26c6293ec5fe14a5e -
Trigger Event:
push
-
Statement type:
File details
Details for the file tomlstack-0.2.0rc1-py3-none-any.whl.
File metadata
- Download URL: tomlstack-0.2.0rc1-py3-none-any.whl
- Upload date:
- Size: 16.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8b52f614b75dbeec20215402c5a9b57f6a40cef4f9bb94a5239c41e82152212
|
|
| MD5 |
b492cac592b4133013b20b2456a689f9
|
|
| BLAKE2b-256 |
d9e2d985591a0523e3880aaa2bae82deedbdab675441d4d15d7fcc77a256e01d
|
Provenance
The following attestation bundles were made for tomlstack-0.2.0rc1-py3-none-any.whl:
Publisher:
publish-pypi.yml on WXZhao7/tomlstack
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tomlstack-0.2.0rc1-py3-none-any.whl -
Subject digest:
c8b52f614b75dbeec20215402c5a9b57f6a40cef4f9bb94a5239c41e82152212 - Sigstore transparency entry: 1934957129
- Sigstore integration time:
-
Permalink:
WXZhao7/tomlstack@1b6be07de0f10ac3b65e90a26c6293ec5fe14a5e -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/WXZhao7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@1b6be07de0f10ac3b65e90a26c6293ec5fe14a5e -
Trigger Event:
push
-
Statement type: