Metadata-Version: 2.4
Name: rs-turboyaml
Version: 0.2.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Text Processing :: Markup
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
License-File: LICENSE
Summary: A YAML 1.2 subset parser built for speed, written in Rust.
Keywords: yaml,parser,rust,fast,serialization
Author-email: "lemon-nades.net" <alex.riehm@gmail.com>
License-Expression: BSD-2-Clause
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://git.lemon-nades.net/Alrie/turboyaml
Project-URL: Issues, https://git.lemon-nades.net/Alrie/turboyaml/issues
Project-URL: Repository, https://git.lemon-nades.net/Alrie/turboyaml

# 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 **25–45× 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

```sh
pip install rs-turboyaml
```

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

## Usage

### Python

```python
import turboyaml

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

# Options (both default False):
#   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)
```

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`:

```python
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

```rust
let value = turboyaml::parse(input)?;
```

## Supported

- Block **mappings** and **sequences**, arbitrarily nested
- 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:`)
- 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.
- **One document per stream**; 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`)
- Document markers (`---`, `...`) and directives (`%YAML`)

Multi-document streams and multi-line quoted/plain scalars are also out of scope (for multi-line text, use a block scalar). 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
- Exact YAML 1.1 boolean parity with ruamel.yaml (for `yaml_1_1_bools=True`)
- The official [YAML test suite](https://github.com/yaml/yaml-test-suite) — the supported subset matches its expected output; see [docs/yaml-test-suite.md](docs/yaml-test-suite.md) for the conformance breakdown

See [spec.md](spec.md) for the normative specification.

Built with [PyO3](https://pyo3.rs) + [maturin](https://maturin.rs).

