Skip to main content

A YAML round-trip library that preserves comments and insertion order

Project description

yarutsk

A Python YAML library that round-trips documents while preserving comments and insertion order.

What it does

Most YAML libraries silently drop comments on load. yarutsk keeps them attached to their keys — both inline (key: value # like this) and block-level (# above a key) — so a load → modify → dump cycle leaves the rest of the file intact.

import io
import yarutsk

doc = yarutsk.load(io.StringIO("""
# database config
host: localhost  # primary
port: 5432
"""))

doc["port"] = 5433

out = io.StringIO()
yarutsk.dump(doc, out)
print(out.getvalue())
# # database config
# host: localhost  # primary
# port: 5433

YamlMapping is a subclass of dict and YamlSequence is a subclass of list, so they work everywhere a dict or list is expected:

import json

doc = yarutsk.loads("name: Alice\nscores: [10, 20, 30]")

isinstance(doc, dict)           # True
isinstance(doc["scores"], list) # True
json.dumps(doc)                 # '{"name": "Alice", "scores": [10, 20, 30]}'

Installation

Built with Maturin. From the repo root:

pip install maturin
maturin develop

API

Loading and dumping

# Load from stream (StringIO / BytesIO)
doc  = yarutsk.load(stream)            # first document
docs = yarutsk.load_all(stream)        # all documents as a list

# Load from string
doc  = yarutsk.loads(text)
docs = yarutsk.loads_all(text)

# Dump to stream
yarutsk.dump(doc, stream)
yarutsk.dump_all(docs, stream)

# Dump to string
text = yarutsk.dumps(doc)
text = yarutsk.dumps_all(docs)

load / loads return a YamlMapping, YamlSequence, YamlScalar, or None (for empty input). Nested nodes are also YamlMapping or YamlSequence; scalar leaves are returned as native Python primitives (int, float, bool, str, or None).

YamlScalar

Top-level scalar documents are wrapped in a YamlScalar node:

doc = yarutsk.loads("42")
doc.value                              # 42 (Python int)
doc.to_dict()                          # same as .value

YamlMapping

YamlMapping is a subclass of dict with insertion-ordered keys. All standard dict operations work directly:

# Standard dict interface (inherited)
doc["key"]                             # get (KeyError if missing)
doc["key"] = value                     # set (preserves position if key exists)
del doc["key"]                         # delete
"key" in doc                           # membership test
len(doc)                               # number of entries
for key in doc: ...                    # iterate over keys in order
doc.keys()                             # KeysView in insertion order
doc.values()                           # ValuesView in insertion order
doc.items()                            # ItemsView of (key, value) pairs
doc.get("key")                         # returns None if missing
doc.get("key", default)                # returns default if missing
doc.pop("key")                         # remove & return (KeyError if missing)
doc.pop("key", default)                # remove & return, or default
doc.setdefault("key", default)         # get or insert default
doc.update(other)                      # merge from dict or YamlMapping
doc == {"a": 1}                        # equality comparison

# Works with any dict-expecting library
isinstance(doc, dict)                  # True
json.dumps(doc)                        # works

# Conversion
doc.to_dict()                          # deep conversion to plain Python dict

# Comments
doc.get_comment_inline("key")          # -> str | None
doc.get_comment_before("key")          # -> str | None
doc.set_comment_inline("key", text)
doc.set_comment_before("key", text)

# Sorting
doc.sort_keys()                        # alphabetical, in-place
doc.sort_keys(reverse=True)            # reverse alphabetical
doc.sort_keys(key=lambda k: len(k))    # custom key function on key strings
doc.sort_keys(recursive=True)          # also sort all nested mappings

YamlSequence

YamlSequence is a subclass of list. All standard list operations work directly:

# Standard list interface (inherited)
doc[0]                                 # get by index (negative indices supported)
doc[0] = value                         # set by index
del doc[0]                             # delete by index
value in doc                           # membership test
len(doc)                               # number of items
for item in doc: ...                   # iterate over items
doc.append(value)                      # add to end
doc.insert(idx, value)                 # insert before index
doc.pop()                              # remove & return last item
doc.pop(idx)                           # remove & return item at index
doc.remove(value)                      # remove first occurrence (ValueError if missing)
doc.extend(iterable)                   # append items from list or YamlSequence
doc.index(value)                       # index of first occurrence
doc.count(value)                       # number of occurrences
doc.reverse()                          # reverse in-place
doc == [1, 2, 3]                       # equality comparison

# Works with any list-expecting library
isinstance(doc, list)                  # True
json.dumps(doc)                        # works

# Conversion
doc.to_dict()                          # deep conversion to plain Python list

# Comments (addressed by integer index)
doc.get_comment_inline(idx)            # -> str | None
doc.get_comment_before(idx)            # -> str | None
doc.set_comment_inline(idx, text)
doc.set_comment_before(idx, text)

# Sorting (preserves comment metadata)
doc.sort()                             # natural order, in-place
doc.sort(reverse=True)
doc.sort(key=lambda v: len(v))         # custom key function on item values

Sorting preserves all comments — each entry or item carries its inline and before-key comments with it when reordered.

Running tests

The repo contains three test suites. You need Rust (nightly) and Python 3.12+ with uv. Python 3.12 is the minimum — YamlSequence subclasses list, which requires PyO3's extends = PyList support introduced in Python 3.12.

# 1. Clone with the yaml-test-suite submodule
git clone --recurse-submodules https://github.com/theyugin/yarutsk
cd yarutsk

# 2. Create a virtual environment and install dev dependencies
uv sync --group dev

# 3. Build the extension in dev (debug) mode
uv run maturin develop

# 4. Run the suites
uv run pytest tests/test_yarutsk.py -v          # core library tests
uv run pytest tests/test_sort.py -v             # key-ordering tests
uv run pytest tests/test_yaml_suite.py -q       # yaml-test-suite compliance

test_yaml_suite.py requires the yaml-test-suite submodule and PyYAML (both available after the steps above). Round-trip tests that fail due to YAML normalisation (flow→block, anchors, folded scalars) are marked xfail and do not count as failures.

Benchmarks

Benchmarks compare yarutsk against PyYAML and ruamel.yaml using pytest-benchmark:

uv sync --group benchmark
uv run pytest benchmarks/ -v --benchmark-min-rounds=10

ruamel.yaml is the closest analogue to yarutsk (it also preserves comments), so it is the primary point of comparison.

Internals

The scanner and parser are vendored from yaml-rust2 (MIT licensed) with one targeted modification: the comment-skipping loop in the scanner now emits Comment tokens instead of discarding them. Everything else — block/flow parsing, scalar type coercion, multi-document support — comes from yaml-rust2 unchanged. The builder layer wires those tokens to the data model, and a hand-written block-style emitter serialises it back out.

YamlMapping and YamlSequence are PyO3 pyclasses that extend Python's built-in dict and list types. A Rust inner field stores the full YAML data model (including comments); the parent dict/list is kept in sync on every mutation so that all standard Python operations work transparently.

Disclaimer

This library was created with Claude Code (Anthropic). The design, implementation, tests, and this README were written by Claude under human direction.

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

yarutsk-0.0.5.tar.gz (84.2 kB view details)

Uploaded Source

Built Distributions

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

yarutsk-0.0.5-cp314-cp314-win_amd64.whl (321.5 kB view details)

Uploaded CPython 3.14Windows x86-64

yarutsk-0.0.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (441.6 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

yarutsk-0.0.5-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (828.7 kB view details)

Uploaded CPython 3.14macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

yarutsk-0.0.5-cp313-cp313-win_amd64.whl (324.6 kB view details)

Uploaded CPython 3.13Windows x86-64

yarutsk-0.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (444.3 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

yarutsk-0.0.5-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (828.3 kB view details)

Uploaded CPython 3.13macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

yarutsk-0.0.5-cp312-cp312-win_amd64.whl (325.1 kB view details)

Uploaded CPython 3.12Windows x86-64

yarutsk-0.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (445.0 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

yarutsk-0.0.5-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (829.4 kB view details)

Uploaded CPython 3.12macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file yarutsk-0.0.5.tar.gz.

File metadata

  • Download URL: yarutsk-0.0.5.tar.gz
  • Upload date:
  • Size: 84.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for yarutsk-0.0.5.tar.gz
Algorithm Hash digest
SHA256 a8c7812f6249e11aa32a244dbb7e27eb41010bd200277d92c7383ed031875e55
MD5 2b20eade89c081a904fae53fa8fd59d3
BLAKE2b-256 c52d1581c0e9e18cfca8b02eaf0585a0496527f6cfaacff098e36ebc72b9fd80

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5.tar.gz:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: yarutsk-0.0.5-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 321.5 kB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for yarutsk-0.0.5-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 3815d146e90f5393665b3687f0b26c4dfaa680b5d7693e4110b67ed32a2fe787
MD5 7530962534d66f75bd109660db79bf2b
BLAKE2b-256 0e7b50b45ee6e47eb860f96aea1021b95d5419f2a9d49dce316b7ce87cd109ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp314-cp314-win_amd64.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for yarutsk-0.0.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 88e78a89039c35f28e14d3468ff9f4417b90b73fed5b9bccef6259fccf975225
MD5 28bc8252930d788e85a3527c2eb87cbc
BLAKE2b-256 c3a8bbad20fe78c5129ae6e390a5dd6eec638cff635a28653b74612f4677fd76

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for yarutsk-0.0.5-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 087af2d6340e62ba32acda1d671fc69affab3361bda6e56bbc09696fb0e8039a
MD5 021db7246e2d55d0441ff4b01d66bbf4
BLAKE2b-256 e0e1744cdad95974733d87d3bf5b5c2462a4d9d93d51a174cc67315b53da382e

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: yarutsk-0.0.5-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 324.6 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for yarutsk-0.0.5-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 fdc05a621f53479b7dd44df7997b05c4c308be79ef782e469eb33e5cda16383a
MD5 e27c5c54f5ecec08079b57bac91dc170
BLAKE2b-256 7bca1e875dac078676f1ea82799ed71cda2e6f526d49ac0c9dd202fc834f17c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp313-cp313-win_amd64.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for yarutsk-0.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 084db108fe4b01c9ad29dbb21b769bad954a537dad75a2a19355817d50a9491e
MD5 64bc1281ce4c3e85d32b2ab2f74198e3
BLAKE2b-256 1b5b75f4b7ef1c8c6b46d15f29045d9790d32d82529063ef12c346d01b68b59d

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for yarutsk-0.0.5-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 cb5448f56d8c0463bb78dbccad69db217804b7e8e155e19066bc8fd8904277e6
MD5 8c41dbad60898a3d2cda7f873d267761
BLAKE2b-256 3f99f7b022bb4cfda50d2935e585f3ccdc48ee9c3f2907fafdce3789219d2e84

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: yarutsk-0.0.5-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 325.1 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for yarutsk-0.0.5-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 f49498090047ff24b22d8ec4bb0d4ab9081f3b781771d61a540d9aaded925995
MD5 7a91a0f9392dd05dcfc62f875328de48
BLAKE2b-256 02b8565408942e291080cee07cd333e8d452531bd9c33e6d599fbc0f27dadddd

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp312-cp312-win_amd64.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for yarutsk-0.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 488414207ae08a490e4711dc406f88823a956fcb149f0f2ecabc3a38103348f3
MD5 a4a354c3464a0e28db69a42c420c5f34
BLAKE2b-256 1a67bc7b10439c9f2fc8a52e885e77508dbdaf5802279e4dafded342d47cbd0a

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file yarutsk-0.0.5-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for yarutsk-0.0.5-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 b935b75d93ebe145163d00d5a8f3189fa87021a2dbf5a222368a09c638f1f427
MD5 0e9b79c5c6f4e982eee7b37b9b42ecb4
BLAKE2b-256 10e1ecfbf37566cfa60b421cf89df2c801e90ecd176fe1b2e14ce5ecf8b106af

See more details on using hashes here.

Provenance

The following attestation bundles were made for yarutsk-0.0.5-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: ci.yml on theyugin/yarutsk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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