{"id":8825,"library":"annotatedyaml","title":"Annotated YAML","description":"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.","status":"active","version":"1.0.2","language":"en","source_language":"en","source_url":"https://github.com/home-assistant-libs/annotatedyaml","tags":["yaml","configuration","secrets","home-assistant","typing"],"install":[{"cmd":"pip install annotatedyaml","lang":"bash","label":"Basic Install"},{"cmd":"pip install annotatedyaml[secrets]","lang":"bash","label":"Install with Secrets Support"}],"dependencies":[{"reason":"Core YAML parsing and dumping engine.","package":"ruamel.yaml","optional":false},{"reason":"Required for encrypting and decrypting secrets within YAML files.","package":"cryptography","optional":true}],"imports":[{"note":"Top-level `load` function is the primary API; avoid importing from internal modules like `loader` directly as paths may change.","wrong":"from annotated_yaml.loader import load","symbol":"load","correct":"from annotated_yaml import load"},{"note":"Top-level `dump` function is the primary API; avoid importing from internal modules like `dumper` directly as paths may change.","wrong":"from annotated_yaml.dumper import dump","symbol":"dump","correct":"from annotated_yaml import dump"},{"note":"`AnnotatedBase` for creating typed configuration models resides in the `base` submodule.","wrong":"from annotated_yaml import AnnotatedBase","symbol":"AnnotatedBase","correct":"from annotated_yaml.base import AnnotatedBase"},{"note":"The `Secrets` class for handling encrypted values is located in the `base` submodule.","symbol":"Secrets","correct":"from annotated_yaml.base import Secrets"}],"quickstart":{"code":"import io\nfrom annotated_yaml import load, dump\n\nyaml_config_str = io.StringIO(\"\"\"\napp_name: MyConfigApp\nversion: 1.0.0\ndatabase:\n  host: localhost\n  port: 5432\nfeatures:\n  - user_profiles\n  - notifications\n\"\"\")\n\n# Load configuration from a string (or file-like object)\nconfig = load(yaml_config_str)\n\nprint(f\"Application Name: {config['app_name']}\")\nprint(f\"Database Host: {config['database']['host']}\")\nprint(f\"Enabled Features: {', '.join(config['features'])}\")\n\n# You can also dump the configuration back to YAML\nprint(\"\\n--- Dumped YAML ---\")\ndump(config, io.StringIO().write) # Dumps to a string, or sys.stdout to print directly\n","lang":"python","description":"This quickstart demonstrates basic loading and dumping of YAML data. For secrets support, install `annotatedyaml[secrets]` and set the `ENCRYPTED_SECRETS_KEY` environment variable."},"warnings":[{"fix":"Upgrade your Python environment to 3.13 or higher. If unable to upgrade, consider using an older version of `annotatedyaml` if available and compatible, or an alternative YAML library.","message":"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.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Thoroughly test existing YAML configurations and loading logic when upgrading from `0.x.x` to `1.0.0+`. Consult the `ruamel.yaml` changelog for `0.18.0` if you suspect behavior differences.","message":"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.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Ensure you install `annotatedyaml[secrets]`. Before loading YAML with secrets, set `os.environ[\"ENCRYPTED_SECRETS_KEY\"]` to your decryption key. Generate a strong key for production use.","message":"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.","severity":"gotcha","affected_versions":"All versions with secrets support"},{"fix":"Familiarize yourself with `ruamel.yaml`'s documentation, especially regarding round-trip preservation and comment handling. Test your YAML inputs thoroughly with `annotatedyaml`.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Change your import statements from `import annotatedyaml` to `import annotated_yaml` or `from annotated_yaml import ...`.","cause":"The correct Python package name is `annotated_yaml`, not `annotatedyaml` for imports.","error":"ModuleNotFoundError: No module named 'annotatedyaml'"},{"fix":"Import `load` directly from the top-level package: `from annotated_yaml import load`.","cause":"You are attempting to import an internal module path, which is not part of the stable public API and may change.","error":"ImportError: cannot import name 'load' from 'annotated_yaml.loader'"},{"fix":"Ensure `pip install annotatedyaml[secrets]` is run, and set a non-empty string value for `os.environ[\"ENCRYPTED_SECRETS_KEY\"]` before calling `annotated_yaml.load()`.","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.","error":"RuntimeError: encrypted_secrets_key must be set when secrets are used"},{"fix":"Review 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.","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.","error":"TypeError: 'int' object is not subscriptable"}]}