Skip to main content

varstore

Hierarchical variable store with optional recursive shell-style template rendering.

Formerly varmgr. The expand engine from the mrjk/python-expandvars fork is included as batteries (varstore.expand) — no separate expandvars install is required.

Table of Contents

Goal

varstore manages configuration variables across sources, scopes, and layers:

  • Sources with numeric priority (level, lower = higher priority)
  • Scopes listing sources and nested scopes
  • Layers of key/value data per source
  • Raw lookup (StoreManager) vs rendered lookup (RenderableStoreManager)
  • Default template engine = shell expandvars ($VAR / ${VAR}); alternate py_stringtemplate available

Install

Python 3.10+. Zero hard runtime dependencies beyond the stdlib.

pip install mrjk.varstore

Import as varstore:

from varstore import StoreManager, RenderableStoreManager, Source

Editable / from source:

mise trust && mise install
uv sync --all-groups

Core concepts

Sources

Named origins with optional priority level (lower = higher priority):

Source("app_cli", level=300, help="Application main CLI")
Source("app_defaults", level=999, help="Application defaults")

Scopes

Scopes list sources (and other scopes) to resolve against:

store.set_scopes({
    "scope_app": ["app_cli", "app_env", "app_defaults"],
    "scope_project": ["project_cli", "project_env", "project_defaults", "scope_app"],
})

Layers

Key/value payloads attached to a registered source:

store.set_layer("app_cli", {"app_name": "myapp", "debug": True})

Resolution APIs

  1. StoreManager — raw storage: get_value / get_values return stored values as-is (templates are not expanded).
  2. RenderableStoreManager — same raw API, plus get_renderer(scope).render_var(...) / render_values(...) for expansion.

Quickstart

from varstore import StoreManager, Source

store = StoreManager()

store.add_sources([
    Source("app_cli", level=300, help="Application main CLI"),
    Source("app_env", level=300, help="Application environment variables"),
    Source("app_defaults", level=999, help="Application defaults"),
])

store.set_scopes({
    "scope_app": ["app_cli", "app_env", "app_defaults"],
})

store.set_layer("app_cli", {
    "app_name": "myapp",
    "debug": True,
})

app_name = store.get_value("app_name")  # "myapp"

Template rendering

get_value always returns the raw stored value. Use a Renderer to expand templates.

from varstore import RenderableStoreManager, Source

store = RenderableStoreManager()

# ... add_sources / set_scopes ...

store.set_layer("project_env", {
    "project_name": "myproject",
    "env": "prod",
    "stack_name": "${project_name}-${env}",
})

assert store.get_value("stack_name") == "${project_name}-${env}"

renderer = store.get_renderer(scope_name="scope_project")
assert renderer.render_var("stack_name") == "myproject-prod"

values = renderer.render_values()

Default engine is expandvars (shell-style). Alternate Python string.Template:

renderer = store.get_renderer(scope_name="scope_project", engine="py_stringtemplate")

Circular references raise TemplateRenderingCircularValueError. Undefined vars raise UndefinedVarError (customizable via render settings).

String-only expand API

For expansion without a store:

from varstore.expand import expand, expandvars, ExpandParser

expandvars("$HOME/bin")
expand("${FOO:-default}", environ={"FOO": "bar"})
ExpandParser(environ={"PATH": "/usr/bin"}).expand("$PATH:/opt/bin")

Inspection

store.show_sources_help()
layers = store.inspect_var("log_level", scope="scope_project")
names = store.get_source_names(scope="scope_stack")
value, report = renderer.render_var("stack_name", debug=True)

Migration from varmgr

Before (varmgr) After (varstore)
from lib.store import ... from varstore import ...
VarMgrError / VarMgrAppError / VarMgrUserError VarStoreError / VarStoreAppError / VarStoreUserError
pip install git+...python-expandvars@develop not needed — engine is vendored

Behavior of sources, scopes, layers, priority, and expand syntax is unchanged.

Development

mise trust && mise install
uv sync --all-groups

With mise activated, task and uv are on your PATH. After uv sync, project tools live in .venv.

task               # list root tasks
task test_core     # unit + coverage + lint (no docs)
task test          # full CI gate (core + docs)
task fix_lint      # auto-fix formatters
task docs          # serve docs (Zensical)

More targets: cd ci && task, cd docs && task.

Running tests

task test_core
# or
uv run pytest

Release

./scripts/release.sh patch   # bump, commit, tag
git push && git push --tags

Tag push v* triggers PyPI publish (configure Trusted Publishing / pypi environment). Docs: Zensical under docs/ (task docs).

Metadata

Release files for mrjk.varstore 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mrjk.varstore 0.1.2
File Size Uploaded Provenance Actions
mrjk_varstore-0.1.2.tar.gz 26.5 kB Without provenance Details for mrjk_varstore-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mrjk.varstore 0.1.2
File Interpreter ABI Platform Actions
mrjk_varstore-0.1.2-py3-none-any.whl Python 3 none any Details for mrjk_varstore-0.1.2-py3-none-any.whl

Total release size: 52.9 kB

Release files / mrjk_varstore-0.1.2.tar.gz

Download URL mrjk_varstore-0.1.2.tar.gz
Size 26.5 kB
Tags Source
SHA-256 checksum
How to use checksums
9c7783ee0612d625bfba3994ac20d7945cfd7c4cf4bf84a2e4b1f9281f583a3d
BLAKE2b-256 checksum
How to use checksums
8fca9184af2ffcfee93f173e2c54a66da563d96bf0dd06ce8d0eaded7dd7d7f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","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 / mrjk_varstore-0.1.2-py3-none-any.whl

Download URL mrjk_varstore-0.1.2-py3-none-any.whl
Size 26.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
713cb011c42a1bfb2d172559826fc7979954a7b2c23cfbed802cac425474d9fb
BLAKE2b-256 checksum
How to use checksums
be5014cdbc31d6ed8f33ea3726778cfd2f34f73689610fb3bb64a7436176a0b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","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 mrjk.varstore 0.1.2

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.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files No provenance

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