Python API
The Python API mirrors the CLI closely: you can load raw stack files, resolve
them into concrete values, apply them to os.environ, and optionally encrypt
or serialize the result.
The examples below use the repository’s sample stacks under examples/ so the
behavior is easier to reason about.
Loading an environment stack
Loading a stack returns an unresolved Env object. Variable references and
modifiers are still present at this stage:
export ENVPATH=./examples/default
>>> import envstack
>>> env = envstack.load_environ("default")
>>> env["ENV"]
'prod'
>>> env["DEPLOY_ROOT"]
'${ROOT}/${ENV}'
>>> env["STACK"]
'default'
This is the programmatic equivalent of:
Select raw values without expanding their references:
envstack default -u PATH PYTHONPATH
envstack default -u PYTHONPATH -q
Both -u/--unresolved and -r/--resolve accept zero or more variable
names. Without names they show all values; -q prints only the value of one
selected variable. Unknown variable names are omitted.
Put stack names before these options: use envstack dev -u, not
envstack -u dev. Arguments after -u now select variables, just as they do
after -r.
Resolving a stack into concrete values
To evaluate variable references such as ${ROOT}/${ENV}, resolve the loaded
environment:
>>> resolved = envstack.resolve_environ(env)
>>> resolved["ENV"]
'prod'
>>> resolved["ROOT"]
'/mnt/pipe'
>>> resolved["DEPLOY_ROOT"]
'/mnt/pipe/prod'
This matches the CLI’s resolved mode:
For the full expansion grammar, including ${VAR:=default},
${VAR:-default}, and ${VAR:?message}, see
Variable expansion.
Loading inherited stacks
The dev example includes default, then overrides a few values:
>>> dev = envstack.resolve_environ(envstack.load_environ("dev"))
>>> dev["ENV"]
'dev'
>>> dev["LOG_LEVEL"]
'DEBUG'
>>> dev["DEPLOY_ROOT"]
'/mnt/pipe/dev'
>>> dev["PATH"].startswith("/mnt/pipe/dev/bin:/mnt/pipe/prod/bin:")
True
That pattern is often the most useful API workflow:
>>> resolved = envstack.resolve_environ(envstack.load_environ("dev"))
Initializing os.environ
If you want to apply a stack to the current Python process, use init():
>>> import os
>>> envstack.init("dev")
>>> os.getenv("ENV")
'dev'
>>> os.getenv("DEPLOY_ROOT")
'/mnt/pipe/dev'
init() updates os.environ and refreshes sys.path from the resolved
PYTHONPATH. This makes it useful for bootstrap scripts and embedded tool
launchers.
To restore the prior process environment:
>>> envstack.revert()
>>> os.getenv("ENV") is None
True
Building environments in Python
You can also author an environment directly:
>>> from envstack.env import Env, resolve_environ
>>> env = Env({"FOO": "bar", "BAR": "${FOO}"})
>>> resolve_environ(env)
{'FOO': 'bar', 'BAR': 'bar'}
This is useful when generating derived environments before writing them to disk:
Structured values
envstack supports lists and dictionaries in stack files. The data example
shows how unresolved and resolved values differ:
>>> data_env = envstack.load_environ("data")
>>> data_env["DICT"]
{'a': 1, 'b': 2, 'c': '${INT}'}
>>> resolved = envstack.resolve_environ(data_env)
>>> resolved["DICT"]
{'a': '1', 'b': '2', 'c': '5'}
>>> resolved["CHAR_LIST"]
['a', 'b', 'c', 'world']
Encryption workflow
The examples/encryption/ stacks provide a concrete encryption example.
Point ENVPATH at both example roots:
>>> os.environ["ENVPATH"] = "examples/default:examples/encryption"
Load the keys stack first so the decryption keys are present in the process
environment:
>>> keys = envstack.resolve_environ(envstack.load_environ("keys"))
>>> os.environ.update({k: str(v) for k, v in keys.items()})
Now encrypted values from secrets.env will resolve automatically:
>>> secrets = envstack.resolve_environ(envstack.load_environ("secrets"))
>>> secrets["KEY"]
'This is encrypted'
>>> secrets["SECRET"]
'my_super_secret_password'
>>> secrets["PASSWORD"]
'password'
You can also encrypt a plain environment in memory:
>>> from envstack.env import Env, encrypt_environ
>>> plain = Env({"SECRET": "super_secret", "PASSWORD": "my_password"})
>>> encrypted = encrypt_environ(plain)
>>> type(encrypted["SECRET"]).__name__
'EncryptedNode'
Common patterns
Load raw stack data:
>>> env = envstack.load_environ("default")
Load and resolve in one step:
>>> resolved = envstack.resolve_environ(envstack.load_environ("dev"))
Apply a stack to the current process:
Restore the previous process environment:
Configuration variables
See Runtime context for the complete control-variable table,
when settings are read, and collision behavior. The default-stack environment
setting is DEFAULT_NAMESPACE; ENVPATH uses the host platform’s path delimiter
(: on POSIX and ; on Windows).