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.

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.

Upgrading from 0.1.x

0.2.0 removes the import-time monkeypatching. Previously import yaml_io reassigned yaml.load and yaml.safe_load, which broke yaml.safe_load for every other consumer in the process. Replace:

import yaml
import yaml_io

with open("some_yaml.yaml") as f:
    data = yaml.safe_load(f)

with:

import yaml_io

data = yaml_io.load("some_yaml.yaml")

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

Metadata

Release files for yaml-io 0.2.0

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.0
File Size Uploaded
yaml_io-0.2.0.tar.gz 15.2 kB Details

Built distribution (wheel)

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

Total release size: 26.5 kB

Release files / yaml_io-0.2.0.tar.gz

Download URL yaml_io-0.2.0.tar.gz
Size 15.2 kB
Tags Source
SHA-256 checksum
How to use checksums
554c258f17d07c659639b4a94e79248b985876b11b4bcd8640953d9bfd668f4f
BLAKE2b-256 checksum
How to use checksums
00e960b651c0b7d0b608a3065232087351a0c822f460accc674e3d70b4c8d737
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.0-py3-none-any.whl

Download URL yaml_io-0.2.0-py3-none-any.whl
Size 11.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8032f513f5272330983632b051601805d8a9e5e3636e661bf7b14c40edfc8320
BLAKE2b-256 checksum
How to use checksums
517f14dfec9224b7978db6d2820e0538df4ed421bfafb670714ba8e019b91dad
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

0.2.1

2 release files

This release

0.2.0 This release

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