pyyaml-env-tag

A custom PyYAML !ENV tag that resolves environment variables inline in YAML files, with typed defaults and fallback chains.

Library
PyPI
v1.1
13stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
21/100Needs Attention
Development Activity0
Maintenance0
Community12
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture65
Code Quality80
Innovation55
Learning Curve90

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 !ENV YAML 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 PyYAML Loader or SafeLoader
  • Lower-level access via construct_env_tag for registering the constructor manually with add_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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search