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).

Download files

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

Source Distribution

mrjk_varstore-0.1.2.tar.gz (26.5 kB view details)

Uploaded Source

Built Distribution

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

mrjk_varstore-0.1.2-py3-none-any.whl (26.3 kB view details)

Uploaded Python 3

File details

Details for the file mrjk_varstore-0.1.2.tar.gz.

File metadata

  • Download URL: mrjk_varstore-0.1.2.tar.gz
  • Upload date:
  • Size: 26.5 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for mrjk_varstore-0.1.2.tar.gz
Algorithm Hash digest
SHA256 9c7783ee0612d625bfba3994ac20d7945cfd7c4cf4bf84a2e4b1f9281f583a3d
MD5 7707bf8f8e0c42047ef8eb03777a5f34
BLAKE2b-256 8fca9184af2ffcfee93f173e2c54a66da563d96bf0dd06ce8d0eaded7dd7d7f6

See more details on using hashes here.

File details

Details for the file mrjk_varstore-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: mrjk_varstore-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 26.3 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for mrjk_varstore-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 713cb011c42a1bfb2d172559826fc7979954a7b2c23cfbed802cac425474d9fb
MD5 f6094bba5eefb5efa377c378cc529f41
BLAKE2b-256 be5014cdbc31d6ed8f33ea3726778cfd2f34f73689610fb3bb64a7436176a0b6

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