Skip to main content

YAML-io

This Python library enables YAML anchors to be imported from external files via custom directives. It also enables imported anchors to be re-exported, so one file can unify many imports and then export them as one source.

This has a few benefits:

  • Re-use the same aliases in multiple files without repeating yourself
  • Use aliases without worrying about reordering your file, because the anchors are defined elsewhere
  • Use multiple layers of imports to logically separate concerns and create versions of files that update all downstream files simultaneously

Install

pip install yaml-io

Requires Python 3.11+ and PyYAML 5.4+.

Usage

import yaml_io

data = yaml_io.load("workspace/acme/actions.yml")

yaml_io.load accepts a path, an open file object, or a YAML string. For multi-document streams, use yaml_io.load_all, which returns a list.

Importing yaml_io has no side effects. It does not patch PyYAML, so yaml.safe_load and everything else in your process behaves exactly as it always did.

If you would rather go through PyYAML directly, pass the loader explicitly:

import yaml
import yaml_io

with open("workspace/acme/actions.yml") as f:
    data = yaml.load(f, Loader=yaml_io.YamlIOLoader)

YamlIOLoader is built on PyYAML's SafeConstructor, so it is as safe as yaml.safe_load.

load_imports_exports is also present, returning (data, exported) where exported maps names to yaml.Node objects. It is deprecated in favor of yaml_io.load.

Try it

The examples/ directory holds a complete, working config tree: two versioned policy files, two package files that select between them, and two workspaces that differ only by which package they import.

git clone https://github.com/superstrong/yaml-io
cd yaml-io
pip install yaml-io
python examples/show.py

That prints both workspaces fully resolved, showing the same alias landing on different values depending on one import line. See examples/README.md for a walkthrough, including how to break it on purpose and what error each mistake produces.

Directives

Mark directives in your YAML like:

#!import ../../global/prod-default/base-package.yml as base

and refer to imported anchors as:

- *base.progress_check_model

Anchors defined directly in a file are exported automatically. Imported anchors are not: to pass one further downstream, re-export it explicitly.

#!export base.progress_check_model

A re-exported anchor loses its original prefix and picks up the prefix of whoever imports it next. Export several at once with commas, or use * to re-export everything from one import:

#!export base.model_a, base.model_b
#!export base.*

Rules worth knowing:

  • Import paths are relative to the file containing the directive.
  • Directives must start at column 0. Anything indented is an ordinary YAML comment, so #!import inside a block scalar is left alone.
  • Paths containing spaces must be quoted: #!import "my dir/base.yml" as base.
  • Directives are file-scoped. In a multi-document file, imported anchors are available in every document, while anchors defined inside a document stay in that document, matching YAML's own scoping.
  • Anchor names (&name) may not contain dots. Aliases (*prefix.name) may contain exactly one.

Versioning Example

A versioned file containing all the anchors we want to define once. Imagine we have multiple files and many anchors.

# ./global/versions/v1.2/actions.yml

defs:
  one: &anchor1 {name: first, retries: 3}
  two: &anchor2 {name: second, retries: 5}

A router-like file where we refer to the versioned files and export them for re-use:

# ./global/prod-default/base-package.yml

#!import ../versions/v1.2/actions.yml as a

#!export a.anchor1, a.anchor2

This file has no content of its own, only directives. Loading it directly returns None, which is expected; its job is to forward anchors.

The most downstream file, where all anchors are resolved and used as aliases, such as ./workspace/acme/actions.yml:

# ./workspace/acme/actions.yml

#!import ../../global/prod-default/base-package.yml as base

steps:
  - *base.anchor1
  - *base.anchor2

Loading that last file yields:

{"steps": [{"name": "first", "retries": 3},
           {"name": "second", "retries": 5}]}
  • One advantage to using the base-package intermediary is the ability to change everything from v1.2 to v1.3 with a small number of changes when you're ready.

  • One advantage to using the prod-default folder is you can create other folders, such as prod-beta or uat-default, and point specific files there instead for testing.

The same file may be imported along several paths. A diamond, where two intermediaries both import one versioned file, resolves once and is shared.

Errors

All errors inherit from yaml_io.YamlIOError, itself a ValueError.

Error Raised when
CircularImportError A file transitively imports itself
ImportResolutionError An #!import target cannot be read
DirectiveError An #!import or #!export line is malformed
ExportError An #!export names an anchor that does not exist
AnchorCollisionError Two distinct anchors compete for one name

Errors from the YAML itself are PyYAML's own, and report the real filename and the correct line number, since directive lines are blanked rather than removed.

Metadata

Release files for yaml-io 0.2.1

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

Source distribution (sdist)

Source distribution for yaml-io 0.2.1
File Size Uploaded
yaml_io-0.2.1.tar.gz 21.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yaml-io 0.2.1
File Interpreter ABI Platform
yaml_io-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 32.6 kB

Release files / yaml_io-0.2.1.tar.gz

Download URL yaml_io-0.2.1.tar.gz
Size 21.1 kB
Tags Source
SHA-256 checksum
How to use checksums
10663629e922a0b5ea12d89055864849ba750d387e71127567a7f5fd7e69dfd9
BLAKE2b-256 checksum
How to use checksums
b13916c0fb9d575fd64641c88bd354ecebd697fb463e8c8bd0b3247129751475
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.

Transparency log

Release files / yaml_io-0.2.1-py3-none-any.whl

Download URL yaml_io-0.2.1-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3328aacae3a55c86ce6cac67b73a3efb1337a4ac62f38f04e663d8777271bbc0
BLAKE2b-256 checksum
How to use checksums
6dc26568b5a8c10fe35e4bbe80e6cd92b1bd9fc609f4c7953af3189fe3931d90
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

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