Working with YAML files/shaare/d2D1ag
Working with YAML files
- YAML (“YAML Ain’t Markup Language”) focuses on human readability. Indentation replaces braces and brackets, comments are allowed, and quoting is usually optional.
- DevOps tooling (Kubernetes, Ansible, GitHub Actions, many app configs) standardizes on YAML for its clarity and brevity.
- JSON is excellent for machine-to-machine communication, but its strict syntax (no comments, heavy quoting) can feel verbose to humans maintaining config files.
- Python’s standard library lacks YAML support; PyYAML is the community-standard package to fill that gap.
YAML Syntax and Features
- Structure comes from spaces for indentation: tabs are discouraged.
- Mappings use
key: value; sequences use a leading hyphen (-) plus a space. - Scalars include strings, numbers, booleans (
true / false,yes / no), andnull. - Comments begin with
#. - Multi-line scalars can be literal (
|) or folded (>). - *Anchors (&) and aliases ()** avoid repetition by re-using defined blocks.
- YAML is a superset of JSON: most valid JSON documents are also valid YAML.
import yaml, json
snippet = """
service: &svc
name: user-api
port: 8080
enabled: true
tags:
- api
- user
- internal
staging:
<<: *svc
replicas: 2
production:
<<: *svc
replicas: 4
"""
parsed = yaml.safe_load(snippet)
print(parsed)
multiline_demo = """
literal: |
line 1
line 2
line 3
folded: >
This is a long string that
could go out of screen, so
we will break this up into
multiple lines to improve
readability.
"""
print("\n")
print(yaml.safe_load(multiline_demo))
Deserializing YAML with yaml.safe_load
- Prefer
yaml.safe_load(or passingLoader=yaml.SafeLoader) to prevent arbitrary-code execution; avoidyaml.loadon untrusted data. - Accepts a string or an open text file handle and returns native Python structures.
- Wrap calls in
try / except yaml.YAMLErrorto catch malformed input.
import yaml
from pathlib import Path
compose = Path("compose.yaml")
try:
with compose.open("r", encoding="utf-8") as file:
config = yaml.safe_load(file)
print(f"Compose version: {config["version"]}")
for svc, options in config["services"].items():
print(f"{svc.capitalize()} image\t: {options["image"]}")
except yaml.YAMLError as e:
print("YAML error:")
print(e)
Example of compose.yaml
version: '3.8'
services:
web:
image: myapp:latest
ports:
- "8000:80"
redis:
image: redis:alpine
Serializing Python Objects with yaml.dump
- Use
yaml.dump(obj, indent=2, default_flow_style=False, sort_keys=False)for readable block-style output. - Set
streamto an open file handle to write directly; leave itNoneto return a string.
import yaml
from pathlib import Path
python_cfg = {
"service": {"name": "listener-service", "port": 6789, "workers": 4, "enabled": False},
"queues": ["high", "default", "low"],
"retry_policy": None,
}
output_path = Path("listener_config.yaml")
with output_path.open("w", encoding="utf-8") as file:
yaml.dump(python_cfg, file, sort_keys=False, default_flow_style=False)
Example of listener_config.yaml
service:
name: listener-service
port: 6789
workers: 4
enabled: false
queues:
- high
- default
- low
retry_policy: null
(97)