A fast YAML subset parser/dumper for Python powered by Rust
Project description
naay
Vote naay to complicated yaml syntax and parsers.
The intent of this project is to define a tiny strict YAML subset where all values are strings, plus support for | block literals,
anchors, merges, and YAML-compatible single-line comments — implemented with a Rust core and a
Python binding. Standalone # ... lines and inline comments attached to mappings/sequences are
retained in their original positions when you round-trip through the Rust core. Speed of parsing and dumping is a chief concern. As well as a very small syntax.
The syntax used retains full compatablility with yaml while only supporting a very limited subset of yaml.
Good for configs or basic human editable data transfer.
This version enforces a root _naay_version field that must match the current release string:
_naay_version: "1.0"
Note: The Python binding exposes plain
dict/list/strobjects, so comment metadata is dropped as soon as you convert the parsed tree into native Python types. Use the Rust API directly if you need to preserve comments while mutating the tree.
Layout
naay-core/– Rust library that parses/dumps the restricted YAML subset.naay-py/– Python extension module usingpyo3that exposesloads/dumps.examples/– Example YAML and Python usage.
Building (with maturin)
-
Install Rust and maturin:
pip install maturin
-
Build and install the Python extension (from
naay-pydirectory):cd naay-py maturin develop
This will build the
naayPython module in your current environment.
Python usage
import naay
from pathlib import Path
text = Path("examples/campaign.yaml").read_text(encoding="utf-8")
data = naay.loads(text)
print("Loaded data:", data)
out = naay.dumps(data)
print("Round-tripped YAML:")
print(out)
Benchmarks
Numbers below were collected on Windows 11 (Ryzen 9 7950X / Python 3.13.2) using
uv run python examples/demo.py (which exercises the real YAML fixtures) and a
small synthetic benchmark (snippet shown later). Each value is the average wall
clock time per operation.
examples/stress_test0.yaml (500 runs)
| Engine | Load avg (ms) | Dump avg (ms) | Relative to naay (native) |
|---|---|---|---|
naay (native) |
0.13 | 0.06 | baseline |
naay (pure-python) |
0.96 | 0.45 | ~7× slower loads, ~8× slower dumps (still >10× faster than PyYAML loads) |
PyYAML safe_* |
10.64 | 7.91 | ~82× slower loads, ~132× slower dumps |
ruamel.yaml (safe) |
3.02 | 4.18 | ~23× slower loads, ~70× slower dumps |
examples/stress_test1.yaml (20 runs, deeply nested)
| Engine | Load avg (ms) | Dump avg (ms) | Notes |
|---|---|---|---|
naay (native) |
4.91 | 5.89 | baseline |
naay (pure-python) |
9.82 | 7.78 | ~2× slower than native; still stack-safe |
PyYAML safe_* |
fail | fail | hit Python recursion depth on the first iteration |
ruamel.yaml (safe) |
33.80 | fail | ~7× slower on load; dump also exceeded recursion depth |
The pure-Python rows above use _naay_pure.parser, the fallback shipped alongside the wheel
for platforms where compiling the Rust extension is not possible.
Synthetic dense map (1,500 flat scalars, 200 runs)
| Engine | Load avg (ms) | Dump avg (ms) |
|---|---|---|
naay (native) |
0.88 | 0.68 |
naay (pure-python) |
6.01 | 3.23 |
PyYAML safe_* |
82.41 | 45.77 |
ruamel.yaml (safe) |
19.96 | 40.09 |
Even on this uniform synthetic workload, naay (native) loads about 93× faster than
PyYAML and 23× faster than ruamel, while dumping is 68× faster than PyYAML and
59× faster than ruamel. The pure-Python fallback still loads ~13× faster than PyYAML and
dumps ~14× faster, so the all-Python wheel remains viable when the Rust extension is unavailable.
The synthetic numbers come from examples/synthetic_dense_bench.py. Reproduce them with:
uv run python examples/synthetic_dense_bench.py --runs 200 --keys 1500
The helper accepts --runs and --keys flags if you want to probe different shapes or
shorter smoke tests.
Spec
Required Preamble
- The document root must be a mapping containing
_naay_version: "1.0"as its first key. - No other document-level metadata or directives are permitted.
Scalars
- Every non-block scalar is interpreted as a UTF-8 string; numbers/booleans are not auto-coerced.
- Quoted scalars may use single or double quotes; escaping follows standard YAML rules.
- Multiline content is emitted and parsed via the
|block literal style only; folded scalars (>) are not allowed. - Trailing whitespace is preserved inside quoted and block scalars but trimmed for bare scalars.
Sequences
- Denoted with
-items at consistent indentation; nested collections are indented by two spaces. - Empty sequences are serialized as
[]and parsed equivalently anywhere (top-level, nested, inline). - Inline sequences (
[a, b]) are not part of the subset; use block form instead.
Mappings
- Keys must be plain strings; quoting is required when keys contain whitespace or reserved characters
:#?. - Empty mappings serialize as
{}and parse equivalently at any depth. - Inline mappings (
{a: b}) are allowed only for a single key/value emitted inline after- key:; multi-key inline maps are parsed but immediately expanded into block form.
Anchors and Aliases
- Anchors are declared via
&namepreceding a nested block; aliases via*nameanywhere a value is allowed. - The merge key
<<supports alias merging; merged values must themselves be mappings. - Anchors cannot reference scalars that lack a nested block (mirrors YAML behavior).
Comments
- Full-line comments begin with
#at any indentation; these are preserved when using the Rust dumper. - Inline comments (after content, starting with
#) are preserved when associated with sequences/mappings. - Comments are dropped when parsing through the Python API (which returns
dict/list/str).
Indentation and Formatting
- Only spaces are allowed; tabs cause a parse error.
- Indentation increments must be exactly two spaces for nested blocks.
- Empty lines are discarded; trailing whitespace on content lines is trimmed before parsing.
Serialization Guarantees
- Empty lists/maps always emit as
[]/{}so downstream tools can distinguish them from empty strings. - Scalars containing newlines are emitted as
|blocks with consistent two-space indentation. - The dumper preserves comment placement, anchor structure, and ordering of keys/sequences as supplied.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file naay-2025.12.5.post6.tar.gz.
File metadata
- Download URL: naay-2025.12.5.post6.tar.gz
- Upload date:
- Size: 32.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b75ef32da7acd0dd737b356bb9f69c3f09042bc9b5fc2c340aa31abf157c53df
|
|
| MD5 |
cf0bfac9f59e92265cf7b8283fdec6b7
|
|
| BLAKE2b-256 |
141b272d624e3bfea74cba5f7d9e58cb06d4d57188ab8579173df6eed281ccba
|
Provenance
The following attestation bundles were made for naay-2025.12.5.post6.tar.gz:
Publisher:
release.yml on rbroderi/naay
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
naay-2025.12.5.post6.tar.gz -
Subject digest:
b75ef32da7acd0dd737b356bb9f69c3f09042bc9b5fc2c340aa31abf157c53df - Sigstore transparency entry: 744261841
- Sigstore integration time:
-
Permalink:
rbroderi/naay@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Branch / Tag:
refs/tags/v2025.12.05-7 - Owner: https://github.com/rbroderi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Trigger Event:
release
-
Statement type:
File details
Details for the file naay-2025.12.5.post6-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: naay-2025.12.5.post6-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 158.5 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71a99c7ca1a8caf07d1217461d9b9e7c337467a4c1e90a71f5c844e820f79b7c
|
|
| MD5 |
7b9eb6fc2ab294dd1ae8e45baf521298
|
|
| BLAKE2b-256 |
be7856f6bac2df5c3bda001592dd37440549a89b6a4f487fba2217412cc2fe15
|
Provenance
The following attestation bundles were made for naay-2025.12.5.post6-cp313-cp313-win_amd64.whl:
Publisher:
release.yml on rbroderi/naay
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
naay-2025.12.5.post6-cp313-cp313-win_amd64.whl -
Subject digest:
71a99c7ca1a8caf07d1217461d9b9e7c337467a4c1e90a71f5c844e820f79b7c - Sigstore transparency entry: 744262067
- Sigstore integration time:
-
Permalink:
rbroderi/naay@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Branch / Tag:
refs/tags/v2025.12.05-7 - Owner: https://github.com/rbroderi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Trigger Event:
release
-
Statement type:
File details
Details for the file naay-2025.12.5.post6-cp313-cp313-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: naay-2025.12.5.post6-cp313-cp313-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 302.9 kB
- Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b59bee63ae1557410a5db4c3796332c277db381fe80ad902eaad113a8d8954a7
|
|
| MD5 |
c1bd2ae4aed04df49c0da918fc311fdd
|
|
| BLAKE2b-256 |
847e9ab61b0a5e2eaae871ff383c5cdb13c40453d5b66097df8ec2c589162521
|
Provenance
The following attestation bundles were made for naay-2025.12.5.post6-cp313-cp313-manylinux_2_34_x86_64.whl:
Publisher:
release.yml on rbroderi/naay
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
naay-2025.12.5.post6-cp313-cp313-manylinux_2_34_x86_64.whl -
Subject digest:
b59bee63ae1557410a5db4c3796332c277db381fe80ad902eaad113a8d8954a7 - Sigstore transparency entry: 744262178
- Sigstore integration time:
-
Permalink:
rbroderi/naay@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Branch / Tag:
refs/tags/v2025.12.05-7 - Owner: https://github.com/rbroderi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Trigger Event:
release
-
Statement type:
File details
Details for the file naay-2025.12.5.post6-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: naay-2025.12.5.post6-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 258.9 kB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
121a37c1279d162ceddf3efe7f0a45d2e6db7ea4e9c1ea45406dfd4e6572eebf
|
|
| MD5 |
361b13ad789eff7bc44d1f42c3b5a202
|
|
| BLAKE2b-256 |
bce37b7a98918237dca90e5a3db97b9fe0e6c9ae2f805ccf12f4b31df323171d
|
Provenance
The following attestation bundles were made for naay-2025.12.5.post6-cp313-cp313-macosx_11_0_arm64.whl:
Publisher:
release.yml on rbroderi/naay
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
naay-2025.12.5.post6-cp313-cp313-macosx_11_0_arm64.whl -
Subject digest:
121a37c1279d162ceddf3efe7f0a45d2e6db7ea4e9c1ea45406dfd4e6572eebf - Sigstore transparency entry: 744261930
- Sigstore integration time:
-
Permalink:
rbroderi/naay@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Branch / Tag:
refs/tags/v2025.12.05-7 - Owner: https://github.com/rbroderi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af721fec51e7e3739e2f5cfa87545844a2ac9c79 -
Trigger Event:
release
-
Statement type: