Annotated YAML
Annotated YAML is a Python library that provides advanced YAML parsing and dumping capabilities, supporting secrets management and deep integration with Python's type hinting system. It builds upon `ruamel.yaml` and targets modern Python environments. The current version is 1.0.2, with a frequent release cadence, primarily for bug fixes and platform support within the 1.x series.
Common errors
-
ModuleNotFoundError: No module named 'annotatedyaml'
cause The correct Python package name is `annotated_yaml`, not `annotatedyaml` for imports.fixChange your import statements from `import annotatedyaml` to `import annotated_yaml` or `from annotated_yaml import ...`. -
ImportError: cannot import name 'load' from 'annotated_yaml.loader'
cause You are attempting to import an internal module path, which is not part of the stable public API and may change.fixImport `load` directly from the top-level package: `from annotated_yaml import load`. -
RuntimeError: encrypted_secrets_key must be set when secrets are used
cause YAML content contains `!secret` tags, but the `ENCRYPTED_SECRETS_KEY` environment variable is either unset or empty, or the `secrets` optional dependency is not installed.fixEnsure `pip install annotatedyaml[secrets]` is run, and set a non-empty string value for `os.environ["ENCRYPTED_SECRETS_KEY"]` before calling `annotated_yaml.load()`. -
TypeError: 'int' object is not subscriptable
cause You are attempting to access a dictionary-like item (e.g., `config['key']['subkey']`) on a value that is an integer (or another non-subscriptable type) in the YAML structure.fixReview your YAML structure and Python code. The path you are trying to access might contain a scalar value where you expect a mapping. Consider using `AnnotatedBase` to define typed structures and catch such errors early.
Warnings
- breaking Annotated YAML requires Python 3.13 or newer. Projects on older Python versions (e.g., 3.10, 3.11, 3.12) are not supported and will fail during installation or runtime.
- breaking Version 1.0.0 introduced significant internal refactoring and updated its core `ruamel.yaml` dependency to `>=0.18.0`. While primary `load`/`dump` APIs are generally stable, users relying on specific `ruamel.yaml` internals or behaviors might experience subtle changes from pre-1.0 versions.
- gotcha Handling encrypted secrets requires the `cryptography` library to be installed (`pip install annotatedyaml[secrets]`) and the `ENCRYPTED_SECRETS_KEY` environment variable to be set with a valid key. Missing either will lead to runtime errors when accessing `!secret` values.
- gotcha Annotated YAML uses `ruamel.yaml` internally, which has some behavioral differences compared to `PyYAML` (e.g., preserving comments, handling duplicate keys differently). Users accustomed to `PyYAML` might encounter unexpected parsing results or serialization outputs.
Install
-
pip install annotatedyaml -
pip install annotatedyaml[secrets]
Imports
- load
from annotated_yaml.loader import load
from annotated_yaml import load
- dump
from annotated_yaml.dumper import dump
from annotated_yaml import dump
- AnnotatedBase
from annotated_yaml import AnnotatedBase
from annotated_yaml.base import AnnotatedBase
- Secrets
from annotated_yaml.base import Secrets
Quickstart
import io
from annotated_yaml import load, dump
yaml_config_str = io.StringIO("""
app_name: MyConfigApp
version: 1.0.0
database:
host: localhost
port: 5432
features:
- user_profiles
- notifications
""")
# Load configuration from a string (or file-like object)
config = load(yaml_config_str)
print(f"Application Name: {config['app_name']}")
print(f"Database Host: {config['database']['host']}")
print(f"Enabled Features: {', '.join(config['features'])}")
# You can also dump the configuration back to YAML
print("\n--- Dumped YAML ---")
dump(config, io.StringIO().write) # Dumps to a string, or sys.stdout to print directly