PyYAML
PyYAML is a YAML 1.1 parser and emitter for Python, providing safe and unsafe loaders, a complete Unicode-aware parser, pickle-compatible serialisation, and a capable extension API for custom tags and representers. Current version is 6.0.3 (released September 2025), which adds Python 3.14 and experimental free-threading support. The 6.x line follows an irregular maintenance cadence with patch releases typically spaced 1–2 years apart; a 7.0 dev branch exists but has no published release date.
Warnings
- breaking yaml.load() now requires an explicit Loader argument. Calling yaml.load(data) without Loader raises TypeError in 6.0+. Previously it issued a DeprecationWarning (5.1–5.4) before becoming a hard error.
- breaking yaml.load() / yaml.full_load() with FullLoader were vulnerable to arbitrary code execution (CVE-2020-14343) on untrusted input in versions before 5.4. yaml.Loader (UnsafeLoader) remains dangerous in all versions.
- gotcha PyYAML implements YAML 1.1, not YAML 1.2. Values like 'yes', 'no', 'on', 'off', 'true', 'false' (all case variants) are parsed as booleans. The two-letter country code 'NO' becomes Python False. Octal literals use the 0777 syntax (not 0o777). These differ from YAML 1.2 and JSON.
- gotcha yaml.safe_dump() escapes non-ASCII characters to \uXXXX by default, making UTF-8 content unreadable in the output file.
- gotcha Sexagesimal (base-60) number parsing: a YAML 1.1 value like '1:30' is parsed as the integer 90, not a string. This silently corrupts time-string fields.
- gotcha yaml.safe_load_all() returns a lazy generator. If the stream is closed before the generator is exhausted (e.g., outside a 'with' block), iteration silently yields nothing or raises an error.
- gotcha Tabs are not valid YAML indentation. Files indented with tabs instead of spaces raise a yaml.scanner.ScannerError that can be cryptic to diagnose.
Install
-
pip install pyyaml -
pip install pyyaml libyaml
Imports
- yaml
import yaml
- yaml.safe_load
import yaml data = yaml.safe_load(stream)
- yaml.safe_dump
import yaml text = yaml.safe_dump(data, allow_unicode=True)
- yaml.YAMLError
from yaml import YAMLError
- yaml.safe_load_all
import yaml for doc in yaml.safe_load_all(stream): ...
Quickstart
import yaml
# --- Parse YAML (safe, no arbitrary code execution) ---
raw = """
service:
host: localhost
port: 8080
debug: false
tags:
- web
- api
"""
config = yaml.safe_load(raw)
print(config['service']['host']) # 'localhost'
print(config['service']['port']) # 8080 (int, not str)
print(type(config['service']['debug'])) # <class 'bool'>
# --- Dump back to YAML text ---
output = yaml.safe_dump(config, allow_unicode=True, sort_keys=False)
print(output)
# --- Load multiple documents ---
multi = """
---
name: alpha
---
name: beta
"""
import io
docs = list(yaml.safe_load_all(io.StringIO(multi)))
print(docs) # [{'name': 'alpha'}, {'name': 'beta'}]
# --- Error handling ---
try:
yaml.safe_load("key: [unclosed")
except yaml.YAMLError as exc:
print(f"Parse error: {exc}")