pyyaml-env-tag
A custom PyYAML !ENV tag that resolves environment variables inline in YAML files, with typed defaults and fallback chains.
Repository Health
Technical Analysis
pyyaml_env_tag is a small, focused extension for PyYAML that adds a !ENV constructor tag, letting YAML documents reference environment variables directly instead of requiring a separate templating or post-processing step. Attach it to any yaml.Loader (or yaml.SafeLoader) via the add_env_tag helper, then use !ENV SOME_VARIABLE in a document to substitute the variable’s value at load time.
Beyond simple substitution, the tag supports sequences of fallback variable names with an optional trailing default (!ENV [PRIMARY, FALLBACK, default]), and resolves both variable values and defaults through YAML’s own implicit scalar resolvers, so a value like true or 42 comes back as a native bool or int rather than a string. It’s used by projects like MkDocs to let configuration files read secrets and environment-specific settings without a separate templating layer.
The library is intentionally minimal: a single module, no runtime dependencies beyond PyYAML itself, and a stable API that has changed little since its first release in 2020.
What You Get
- A
!ENVYAML tag usable as a scalar (!ENV VAR) or a sequence with fallbacks and a default (!ENV [VAR1, VAR2, default]) - The
add_env_tag(loader)helper for quickly attaching the tag to any PyYAMLLoaderorSafeLoader - Lower-level access via
construct_env_tagfor registering the constructor manually withadd_constructor - Automatic type coercion of resolved values and defaults using YAML’s implicit scalar resolvers (bool, int, float, date, null, string)
Common Use Cases
- Reading secrets or environment-specific settings (API keys, hostnames, ports) directly into application YAML config files
- Providing safe fallback values for optional configuration so a YAML file loads correctly in environments where a variable isn’t set
- Building tool configuration formats (like MkDocs’
mkdocs.yml) that need to interpolate deployment-time environment variables - Layering environment-driven overrides on top of static YAML defaults without writing a custom preprocessor
Under The Hood
Architecture
The entire library lives in one module, yaml_env_tag.py. construct_env_tag(loader, node) is the PyYAML constructor: it inspects the node type (ScalarNode vs SequenceNode), extracts one or more variable names via loader.construct_scalar/construct_object, and returns the first variable found in os.environ, falling back to an explicit default (or None) if none match. add_env_tag(loader) is a thin convenience wrapper that calls loader.add_constructor('!ENV', construct_env_tag) and returns the loader, so it can be attached inline in a yaml.load(data, Loader=add_env_tag(yaml.Loader)) call. There is no state, no class hierarchy, and no dependency injection — the whole surface area is two functions.
Tech Stack
Pure Python 3.9+ with a single runtime dependency, PyYAML, which it extends rather than replaces. The project builds via setuptools with a pyproject.toml-only configuration (dynamic version pulled from __version__ in the module itself), ships as both wheel and sdist, and is published to PyPI via a trusted-publishing GitHub Actions workflow (no manual token handling).
Code Quality
A 330-line unittest-based test suite (tests/test_yaml_env_tag.py) exercises scalar and sequence forms, multi-variable fallback chains, default-type coercion (null, bool, int, float, string), and both yaml.Loader and yaml.SafeLoader, using unittest.mock.patch.dict to control the environment per test. CI runs this suite via coverage across a matrix of Ubuntu/Windows/macOS and CPython 3.9-3.13 plus PyPy 3.10, uploads results to Codecov, and separately runs flake8 on pull requests with a 118-character line limit. Type hints are used on the public functions (Any, yaml.Loader, yaml.Node), though the codebase is not fully statically typed end-to-end.
What Makes It Unique
Unlike template-string approaches to environment substitution in YAML (which treat everything as text and require a second parsing pass), pyyaml_env_tag resolves directly into PyYAML’s node-construction pipeline, so substituted values are typed via YAML’s own implicit resolvers rather than always being strings. Its fallback-chain syntax (!ENV [VAR1, VAR2, default]) also lets a single tag express a priority list of variable names plus a default in one compact expression, which the comparable pyyaml-tags and similar template-substitution libraries don’t offer.
Used by 2 apps in this directory
Dokku
Devops · Hosting Control Panel
The smallest PaaS implementation you've ever seen — deploy apps via git push using Docker and Heroku buildpacks on your own server.
Traefik
Devops · Automation · Security
A cloud-native reverse proxy and load balancer that auto-configures itself from Docker, Kubernetes, and other orchestrators — zero manual routing required.