subset of YAML spec that parses much quicker.
  • Rust 78.3%
  • Python 21.7%
Find a file
alrie 4211cafdb6
All checks were successful
CI / Rust: build (release, no features) (push) Successful in 14s
CI / Rust: unit tests (push) Successful in 27s
CI / Rust: integration tests (debug) (push) Successful in 26s
CI / Rust: integration tests (release) (push) Successful in 32s
CI / Rust: performance (push) Successful in 41s
CI / Package: wheel (windows-x86_64) (push) Successful in 51s
CI / Package: wheel (linux-x86_64) (push) Successful in 44s
CI / Package: wheel (macos-aarch64) (push) Successful in 1m0s
CI / Package: wheel (macos-x86_64) (push) Successful in 55s
CI / Package: sdist (push) Successful in 17s
CI / Smoke: wheel (py3.13) (push) Successful in 14s
CI / Smoke: wheel (py3.8) (push) Successful in 14s
CI / Conformance: Python performance (shipped wheel) (push) Successful in 1m45s
CI / Conformance: differential fuzz (PyYAML + ruamel) (push) Successful in 37s
CI / Conformance: YAML test suite (ecosystem + JSON oracles) (push) Successful in 21s
CI / Smoke: sdist (build from source) (push) Successful in 29s
CI / Publish to PyPI (push) Has been skipped
refactored CI
2026-07-03 10:10:03 +02:00
.forgejo/workflows refactored CI 2026-07-03 10:10:03 +02:00
benches Renamed project to turboyaml 2026-06-12 15:15:05 +02:00
docs Added more parity features 2026-07-02 21:44:27 +02:00
examples Renamed project to turboyaml 2026-06-12 15:15:05 +02:00
python/turboyaml Fix edge cases and improve testing 2026-07-02 21:09:31 +02:00
scripts Added more parity features 2026-07-02 21:44:27 +02:00
src Added more parity features 2026-07-02 21:44:27 +02:00
tests Added more parity features 2026-07-02 21:44:27 +02:00
.gitignore Test pypi release 2026-06-13 21:46:20 +02:00
Cargo.toml Fix CI bugs 2026-06-12 22:44:28 +02:00
LICENSE Implement spec and first rust parser 2026-05-31 13:51:09 +02:00
perf_test.py added block scalars feature 2026-06-14 16:05:39 +02:00
pyproject.toml Clean up python setup and tests for pypi wheel release 2026-06-12 22:12:41 +02:00
README.md Added more parity features 2026-07-02 21:44:27 +02:00
spec.md Added more parity features 2026-07-02 21:44:27 +02:00

TurboYAML

Subset of YAML 1.2, built for parsing speed. A Rust parser with Rust and Python bindings.

Valid TurboYAML is always valid YAML 1.2. The reverse need not hold — so parse with TurboYAML and fall back to a full YAML parser when you hit something it deliberately doesn't support.

Why

TurboYAML trades YAML's full feature richness for speed, while keeping a useful, real-world feature set alive. On typical config and data it parses roughly 2545× faster than PyYAML's libyaml C extension, producing native Python objects (dict / list / str / int / float / bool / None) directly — no intermediate tree.

Profile turboyaml (Python) PyYAML (libyaml) speedup
Flat records 9.4M lines/s 372k lines/s 25×
Deep tree 4.1M lines/s 111k lines/s 37×
Inline flow collections 1.5M lines/s 32k lines/s 47×
Block scalars 7.2M lines/s 238k lines/s 30×
Mixed (nested + flow + blocks) 3.0M lines/s 90k lines/s 33×

Measured on one machine over a randomized corpus that includes quoted/escaped scalars and block scalars; reproduce with cargo run --release --features gen --bin perf_test && python perf_test.py. Speedup is the relative metric; absolute throughput varies with document complexity, but both parsers see the same corpus.

Install

pip install rs-turboyaml

The PyPI distribution is rs-turboyaml; the import name is turboyaml.

Usage

Python

import turboyaml

obj = turboyaml.load(text)        # → dict / list / str / int / float / bool / None

# Multi-document streams (--- separated) — mirrors yaml.safe_load_all,
# returning an eager list with one element per document:
docs = turboyaml.load_all(text)   # → [doc0, doc1, ...]

# Options (both default False), accepted by load and load_all:
#   strict=True          → raise ParseError on duplicate mapping keys
#   yaml_1_1_bools=True  → yes/no/on/off/y/n become bool (YAML 1.1 parity)
obj = turboyaml.load(text, yaml_1_1_bools=True)

load reads a single document — a lone leading --- / trailing ... is fine, but a stream with more than one document raises ParseError; use load_all for that.

Fall back to a full parser when a document uses something TurboYAML doesn't cover. Catch the base TurboYamlError so the fallback also triggers on the handful of valid-YAML constructs (e.g. multi-line scalars) that surface as ParseError:

try:
    obj = turboyaml.load(text)        # fast path
except turboyaml.TurboYamlError:      # UnsupportedFeatureError or ParseError
    import yaml
    obj = yaml.safe_load(text)        # full parser is the authority

This is safe because TurboYAML never silently returns data that differs from a full parser — for anything it can't handle it raises (checked in CI by a differential against PyYAML on unsupported constructs).

Rust

let value = turboyaml::parse(input)?;             // one document
let docs  = turboyaml::parse_all(input)?;         // Vec<Value>, one per document

Supported

  • Block mappings and sequences, arbitrarily nested — including a sequence value indented at the same column as its mapping key (key: then - item, the common real-world form)
  • Compact notation — - key: value, - - nested
  • Scalar type inference: null/~, booleans, integers (decimal / 0x / 0o), floats (incl. .inf / .nan), strings
  • Quoted strings (single line) — double-quoted with the YAML 1.2 escape set (\n, \t, \", \uXXXX, …) and single-quoted (literal, '' escape)
  • Flow collections[1, 2], {a: 1} — single-line, nestable
  • Block scalars| literal and > folded, with + / - chomping and explicit indentation indicators (|2, >3)
  • # comments
  • Any scalar type as a mapping key (42:, True:, null:)
  • Document markers — a single leading --- / trailing ..., and multi-document streams (--- separated) via load_all / parse_all; a document body may be inline on the marker line, including a block scalar (--- |, --- >)
  • %YAML 1.2 directive — accepted and ignored (TurboYAML follows the 1.2 core schema)
  • Optional duplicate-key rejection — load(text, strict=True) / parse_strict

Notable differences from full YAML 1.2

  • Indentation is spaces in multiples of two — no tabs, no odd widths.
  • Core-schema booleans by default: the three YAML 1.2 spellings of each — true/True/TRUE and false/False/FALSE — are bool; any other casing (tRuE) and the YAML 1.1 words yes/no/on/off/y/n are strings. Pass yaml_1_1_bools=True to opt into full YAML 1.1 boolean parity (those tokens become bool, matching ruamel.yaml's 1.1 resolver).
  • Quoted strings are single line — for multi-line text, use a block scalar.
  • UTF-8 only, no BOM.

Not supported

These raise a typed UnsupportedFeatureError — distinct from a malformed-input ParseError — so the fallback pattern above can recover them cleanly:

  • Anchors and aliases — &anchor, *alias
  • Tags — !!str, !custom
  • Merge keys (<<:) and explicit/complex keys (? key)
  • Directives other than %YAML 1.2%YAML 1.1 (full YAML 1.1 is not implemented), %TAG, and reserved directives (%FOO)

Multi-line quoted/plain scalars are also out of scope (for multi-line text, use a block scalar), as is a block collection begun on a --- marker line (--- key: value). These (and the items above) raise rather than silently mis-parse, so the fallback recovers them.

Status

Alpha, but extensively validated. Correctness rests on layered, independent checks, all run in CI:

  • Unit + integration tests — hand-written fixtures plus generator round-trips
  • A randomized differential fuzz against PyYAML — 70k+ documents, 0 mismatches
  • A boundary differential proving TurboYAML raises (never silently diverges) on unsupported constructs — the guarantee that makes the fallback safe
  • A multi-document differentialload_all matches yaml.safe_load_all across ~5k randomized streams plus the document-counting edge cases, 0 divergences
  • Exact YAML 1.1 boolean parity with ruamel.yaml (for yaml_1_1_bools=True)
  • The official YAML test suite — checked against the libyaml + ruamel ecosystem (TurboYAML is never more permissive than both) and the suite's expected JSON; see docs/yaml-test-suite.md for the conformance breakdown

See spec.md for the normative specification, and docs/architecture.md for how the parser is built and why it is fast (including the optimizations that didn't work).

Built with PyO3 + maturin.