Skip to main content

Human-friendly YAML formatting with intelligent sequence handling and priority key ordering

Project description

YAML for Humans

Human-friendly YAML formatting for PyYAML that makes YAML more readable and intuitive.

Features

  • Empty line preservation: Maintains empty lines from original YAML for better readability
  • Intelligent sequence formatting: Strings on same line as dash (- value), objects on separate lines
  • Indented sequences: Dashes are properly indented under their parent containers
  • Priority key ordering: Important keys like name, image, command appear first in mappings
  • Multi-document support: Handle multiple YAML documents with proper --- separators
  • Kubernetes manifest ordering: Automatic resource ordering following best practices
  • Valid YAML output: All generated YAML passes standard YAML validation
  • Drop-in replacement: Compatible with existing PyYAML code

Quick Start

from yaml_for_humans import dumps, dump, load_with_formatting

# Your data
data = {
    'containers': [
        {
            'ports': [8080, 9090],
            'name': 'web-server',  # name will appear first
            'image': 'nginx:latest',
            'command': ['/bin/sh', '-c', 'nginx -g "daemon off;"']
        }
    ]
}

# Generate human-friendly YAML
yaml_output = dumps(data)
print(yaml_output)

# Or load existing YAML with formatting preservation
formatted_data = load_with_formatting('existing-config.yaml')
preserved_output = dumps(formatted_data, preserve_empty_lines=True)

Output:

containers:
  -
    name: web-server          # Priority keys first
    image: nginx:latest
    command:
      - /bin/sh               # Strings inline with dash
      - -c
      - nginx -g "daemon off;"
    ports:
      - 8080
      - 9090

Comparison with Standard PyYAML

Standard PyYAML Output

containers:
- command:
  - /bin/sh
  - -c
  - nginx -g "daemon off;"
  image: nginx:latest
  name: web-server
  ports:
  - 8080
  - 9090

YAML for Humans Output

containers:
  -
    name: web-server
    image: nginx:latest
    command:
      - /bin/sh
      - -c
      - nginx -g "daemon off;"
    ports:
      - 8080
      - 9090

Key Differences

  1. Indented sequences: Dashes are indented under parent containers for better hierarchy visualization
  2. Priority key ordering: Important keys (apiVersion, kind, metadata, name, image, imagePullPolicy, env, envFrom, command, args) appear first
  3. Smart formatting: Complex objects use separate lines, simple strings stay inline
  4. Consistent indentation: Maintains visual hierarchy throughout the document

Whitespace Preservation

YAML for Humans can preserve empty lines and whitespace from the original YAML to maintain document structure and readability:

from yaml_for_humans import load_with_formatting, dumps

# Load a real Kustomization file with strategic empty lines
data = load_with_formatting('tests/test-data/kustomization-compressed.yaml')

# Preserve original whitespace structure
preserved_output = dumps(data, preserve_empty_lines=True)
print("With whitespace preservation:")
print(preserved_output)

# Standard compact output  
compact_output = dumps(data, preserve_empty_lines=False)
print("\nCompact output:")
print(compact_output)

With whitespace preservation:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../.overlays/gitlab-registry-access/
  - ../../.overlays/postgres-headless-2023/
  - django/

labels:
  -
    includeSelectors: true
    pairs:
      env: prod

images:
  -
    name: application
    newName: v3.3.2
  -
    name: nginx
    newTag: 1.27.4

configMapGenerator:
  -
    behavior: create
    envs:
      - vars.env
    name: env
  -
    files:
      - nginx.conf
    name: proxy-config

secretGenerator:
  -
    behavior: create
    envs:
      - secrets.env
    name: env

patches:
  -
    path: patches/sidecars/nginx-front.yaml
    target:
      kind: Deployment
      labelSelector: component=django
  -
    path: patches/init-containers/migrate.yaml
    target:
      kind: Deployment
      labelSelector: component=django
  -
    path: patches/init-containers/collectstatic.yaml
    target:
      kind: Deployment
      labelSelector: component=django

Compact output:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../.overlays/gitlab-registry-access/
  - ../../.overlays/postgres-headless-2023/
  - django/
labels:
  -
    includeSelectors: true
    pairs:
      env: prod
images:
  -
    name: application
    newName: v3.3.2
  -
    name: nginx
    newTag: 1.27.4
configMapGenerator:
  -
    behavior: create
    envs:
      - vars.env
    name: env
  -
    files:
      - nginx.conf
    name: proxy-config
secretGenerator:
  -
    behavior: create
    envs:
      - secrets.env
    name: env
patches:
  -
    path: patches/sidecars/nginx-front.yaml
    target:
      kind: Deployment
      labelSelector: component=django
  -
    path: patches/init-containers/migrate.yaml
    target:
      kind: Deployment
      labelSelector: component=django
  -
    path: patches/init-containers/collectstatic.yaml
    target:
      kind: Deployment
      labelSelector: component=django

This feature is especially useful for:

  • Kustomization files where empty lines separate different resource types and configurations
  • Kubernetes manifests where empty lines logically group related settings
  • CI/CD pipelines where empty lines help distinguish workflow stages
  • Configuration files where whitespace enhances visual structure and readability

CLI Empty Line Preservation

The command-line tool preserves empty lines by default:

# Default behavior (no empty line preservation)
cat kustomization.yaml | huml

# Preserve empty lines
cat kustomization.yaml | huml -P

Installation

Install the core library:

uv add yaml-for-humans

Or install with CLI support:

uv add yaml-for-humans[cli]

Development Installation

For development, install in editable mode:

# Install the package in editable mode
uv pip install -e .

# Or with CLI dependencies for development
uv pip install -e .[cli]

Then import and use:

from yaml_for_humans import dumps, dump, load_with_formatting

Command Line Interface (Optional)

The huml command-line utility converts YAML or JSON input to human-friendly YAML. It accepts input through stdin pipes or file processing:

# Convert JSON to human-friendly YAML
echo '{"name": "web", "ports": [80, 443]}' | huml

# Process existing YAML files
cat config.yaml | huml

# Use with kubectl
kubectl get deployment -o yaml | huml

# Process multi-document YAML (auto-detected)
cat manifests.yaml | huml

# Process JSON input (automatic detection)
echo '{"containers": [...]}' | huml

# Custom indentation
cat config.yaml | huml --indent 4

# Custom stdin timeout (default: 2000ms)
cat config.yaml | huml --timeout 100

# Use unsafe YAML loader (allows arbitrary Python objects - use with caution)
cat config-with-python-objects.yaml | huml --unsafe-inputs

# Process JSON Lines format (one JSON object per line)
cat logs.jsonl | huml

# Handle Kubernetes API responses with items arrays
kubectl get deployments -o json | huml  # Automatically splits items into documents

# Process file inputs instead of stdin
huml --inputs config.yaml,deploy.json

# Process multiple files with glob patterns  
huml --inputs "*.json,configs/*.yaml"

# Process all files in a directory (add trailing slash)
huml --inputs /path/to/configs/

# Mix glob patterns, directories, and explicit files
huml --inputs "*.json,/configs/,specific.yaml"

# Output to file or directory
kubectl get all -o json | huml --output ./k8s-resources/

Stdin Input Handling

The CLI automatically detects input format and handles:

  • JSON objects: Single objects or arrays
  • JSON Lines: Multiple JSON objects, one per line
  • YAML documents: Single or multi-document with --- separators
  • Kubernetes API responses: Objects with items arrays are split into separate documents
  • Format detection: Automatic detection based on content analysis

CLI Options

  • -i, --inputs TEXT: Comma-delimited list of JSON/YAML file paths to process. Supports:
    • Explicit file paths: config.yaml,deploy.json
    • Glob patterns: *.json,configs/*.yaml
    • Directories: /path/to/directory/ (must end with /)
    • Mixed combinations: *.json,/configs/,specific.yaml
  • -o, --output TEXT: Output file or directory path (if ends with /, treated as directory)
  • --auto: Automatically create output directories if they don't exist
  • --indent INTEGER: Indentation level (default: 2)
  • -t, --timeout INTEGER: Stdin timeout in milliseconds (default: 2000)
  • -u, --unsafe-inputs: Use unsafe YAML loader (allows arbitrary Python objects, use with caution)
  • -P, --preserve-empty-lines: Preserve empty lines from original YAML (default: false)
  • --help: Show help message
  • --version: Show version information

Input Processing Behavior

  • File Globbing: Patterns like *.json and configs/*.yaml are expanded to match files
  • Directory Processing: Paths ending with / process all valid JSON/YAML files in the directory
  • Invalid File Handling: Files that can't be parsed or aren't JSON/YAML are skipped with warnings
  • Robust Processing: Processing continues even if some files fail, reporting errors but not stopping
  • Format Detection: Files are validated based on extension (.json, .yaml, .yml, .jsonl) and content analysis

Multi-Document Support

Basic Multi-Document Usage

from yaml_for_humans import dumps_all, dump_all

documents = [
    {'config': {'version': '1.0', 'features': ['auth', 'logging']}},
    {'services': [{'name': 'web', 'image': 'nginx'}]},
    {'metadata': {'created': '2025-01-01'}}
]

# Generate multi-document YAML
yaml_output = dumps_all(documents)
print(yaml_output)

Output:

config:
  version: '1.0'
  features:
    - auth
    - logging

---
services:
  -
    name: web
    image: nginx

---
metadata:
  created: '2025-01-01'

Kubernetes Manifests

from yaml_for_humans import dumps_kubernetes_manifests

manifests = [
    {'apiVersion': 'apps/v1', 'kind': 'Deployment', ...},
    {'apiVersion': 'v1', 'kind': 'Service', ...},
    {'apiVersion': 'v1', 'kind': 'ConfigMap', ...},
    {'apiVersion': 'v1', 'kind': 'Namespace', ...}
]

# Automatically orders resources: Namespace, ConfigMap, Service, Deployment
ordered_yaml = dumps_kubernetes_manifests(manifests)

API Reference

For detailed API documentation, see API.md.

Testing

Run the test suite with pytest:

uv run pytest tests/ -v

Test Coverage

  • Unit tests: Core emitter functionality, key ordering, YAML validity
  • Integration tests: Real-world examples including Kubernetes manifests, Docker Compose files, CI/CD pipelines
  • Round-trip tests: Ensure generated YAML can be parsed back correctly

Examples

Run the example scripts to see the formatting in action:

uv run python examples/kubernetes_example.py
uv run python examples/docker_compose_example.py
uv run python examples/multi_document_example.py
uv run python examples/kubernetes_manifests_example.py

The examples demonstrate:

  • Kubernetes deployments with priority key ordering
  • Docker Compose files with intelligent sequence formatting
  • Multi-document YAML with proper separators
  • Kubernetes manifest ordering and resource prioritization

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yaml_for_humans-1.3.1.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yaml_for_humans-1.3.1-py3-none-any.whl (35.4 kB view details)

Uploaded Python 3

File details

Details for the file yaml_for_humans-1.3.1.tar.gz.

File metadata

  • Download URL: yaml_for_humans-1.3.1.tar.gz
  • Upload date:
  • Size: 24.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.18

File hashes

Hashes for yaml_for_humans-1.3.1.tar.gz
Algorithm Hash digest
SHA256 5f0f312e8dc48f1b0de88ca29cf5e17b6db0a37354935da56d697a41af37dd1d
MD5 d2d9ea058a7dfde9d605d9df026b7cc1
BLAKE2b-256 88b2d92cc1798988c3433888ed6a7e3c0c23ba5d30bfc287bc91309686c3035b

See more details on using hashes here.

File details

Details for the file yaml_for_humans-1.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for yaml_for_humans-1.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f0dc74e3cf0e2895c1699a3bfc9e85183c102bdb8f8c4e53011020d5c94ba7bd
MD5 4531ded975736d0cad9bed719dc0b242
BLAKE2b-256 9fb1024ffc2dd33365bca172d8e561b825e86149035e8bb442ab81e348c5a8cb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page