pythonizeyaml
English | 简体中文
pythonizeyaml is a YAML library with a PyYAML-compatible API and a lossless
round-trip engine implemented in Rust. Loading and dumping an untouched document
reproduces its source text, including comments, blank lines, indentation, scalar
styles, document markers, anchors, and multi-document layout.
The parser and emitter are compiled through PyO3 and Maturin. There is no Python YAML runtime dependency.
Comparison with Other YAML Libraries
The table below compares pythonizeyaml 0.6.1 with PyYAML, yamltrip, and
ruamel.yaml.
| Area | pythonizeyaml | PyYAML | yamltrip | ruamel.yaml |
|---|---|---|---|---|
| Primary purpose | PyYAML-style YAML API with lossless round trips | General YAML serializer/parser | Format-preserving YAML file editor and query API | General YAML with strong round-trip support |
| Main API | load, load_all, dump, dump_all, safe_*, full_*, unsafe_*, YAML |
Same function-oriented API, plus lower-level scanner/parser APIs | load/loads return Document; immutable edits plus Editor |
Class-oriented YAML() API; legacy top-level functions are deprecated |
| Document API | load/load_all return mutable Document objects; load_document/load_documents and read_document/read_documents are explicit spellings; style editing on the values themselves |
No mutable document wrapper; use Python values or low-level nodes/events | Document/Editor centered editing and query API |
YAML().load() returns mutable CommentedMap/CommentedSeq documents |
| Return model | Document roots (dict/list subclasses); nested standard Python scalars, RoundTripMap/List/Set, Decimal, Tagged |
Plain Python objects and YAML AST/event/token objects | Document wrapper around plain Python values |
CommentedMap, CommentedSeq, scalar subclasses |
| Backend | Custom Rust parser/emitter through PyO3 | Pure Python plus optional LibYAML C extension | tree-sitter-yaml through Rust yamlpath/yamlpatch |
Python plus optional C parser |
| Unchanged round trip | Exact source text, including comments, blanks, styles, markers, and line layout | No preservation guarantee; output is regenerated | Preserves source and format while patching edits | Preserves comments and styles in round-trip mode, but output remains emitter-controlled |
| Comments and whitespace | Preserved exactly for unchanged documents | Lost or normalized | Preserved | Preserved, generally |
| Indentation and flow style | Original formatting retained; explicit IndentConfig can override |
Regenerated according to dumper settings | Preserved | Retained in normal round-trip workflows, with indentation configurable |
| Scalar quotes/styles | Preserved, including redundant quotes and block styles | Rewritten | Preserved as raw source | Preserved, including preserve_quotes support |
| Mutation model | Mutate loaded Document objects (dict-like/list-like); unchanged bytes are retained |
Mutate plain objects, then regenerate | Immutable Document methods or mutable Editor; minimal patches |
Mutate CommentedMap/CommentedSeq objects |
| Style editing API | values carry style, collection_style, chomping, comments, tags, anchors; set(...) applies fields atomically |
Dumper options and low-level representers; no source style editing API | Path/editor operations preserve selected source formatting | Object attributes and YAML emitter options expose round-trip style controls |
| Structural edit fidelity | Local edits are patched; replaced/new subtrees may be canonically emitted | Full regeneration | Designed for minimal structural patches | Strong preservation of attached comments and formatting |
| YAML schema | PyYAML-compatible YAML 1.1 resolver by default (yes/no booleans, 010 octal, 1:30 sexagesimal); a %YAML 1.2 directive switches to the YAML 1.2 core schema |
YAML 1.1-oriented resolver by default | Focused on editable YAML values; tags are not interpreted | YAML 1.2 by default |
| Large integers | Arbitrary-precision Python int |
Arbitrary-precision Python int |
May lose precision outside signed 64-bit range | Arbitrary-precision Python int |
| Decimal values | Exact binary64-representable decimals become float; others become Decimal; !!decimal forces Decimal |
Normally float; custom constructors needed for Decimal |
Basic scalar conversion; no special big-decimal support | Normally float; custom representers/constructors needed for Decimal |
| Unknown/application tags | Returned as Tagged; never executed |
Depends on loader/constructors; unsafe loaders can construct Python objects | Not interpreted | Preserved; constructors can define behavior |
| Safe loading | safe_load rejects non-standard tags |
safe_load uses SafeLoader |
No separate safe/unsafe object-construction model | YAML(typ="safe") or safe loading APIs |
| Anchors and aliases | Parsed, preserved, resolved to shared Python objects | Resolved; dumper may emit anchors | Detected but not resolved during extraction | Resolved and preserved |
| Multi-document streams | Supported | Supported | Not supported | Supported |
| Custom classes | No constructor/representer plugin API | YAMLObject, constructors, representers |
No custom class serialization | Constructors, representers, and plug-ins |
| Events/nodes | No public scan/parse/event API | Full scanner, parser, composer, node APIs | Tree/query/path API instead | Full event/node APIs |
| Errors | PyYAML-compatible hierarchy | PyYAML hierarchy | YAMLTripError hierarchy |
ruamel-specific YAMLError hierarchy |
| Encoding | UTF-8 input through str/bytes/streams |
Several YAML encodings depending on reader | UTF-8 only | Configurable, broad encoding support |
| Maturity | New 0.6.1 custom implementation | Very mature, widely deployed | Newer focused library, version 0.4.x | Very mature round-trip implementation |
The biggest practical distinctions:
- Compared with PyYAML:
pythonizeyamlkeeps source layout by default, but is much younger and lacks PyYAML's mature event API, custom constructor ecosystem, encoding breadth, and long-term compatibility history. Unlike unsafe PyYAML loaders, it does not execute!!python/...tags. - Compared with yamltrip: yamltrip is optimized around editing and querying
YAML files through
Document/Editor; it explicitly does not support multi-document streams, tag interpretation, anchor resolution, or arbitrary-size integer preservation.pythonizeyamlprovides a PyYAML-style data API and broader YAML semantics, but its structural-edit patching is less specialized than yamltrip's. - Compared with ruamel.yaml: ruamel is the mature reference for mutable
comment-preserving YAML objects.
pythonizeyamlinstead promises exact source replay for unchanged documents and uses Rust-native parsing,Decimalprecision policy, andTaggedvalues. It does not yet offer ruamel's class registration, plug-in ecosystem, or depth of YAML conformance coverage.
Sources: PyYAML repository, yamltrip README, and ruamel.yaml repository.
Requirements
- Python 3.10 or newer
- Rust 1.83 or newer when building from source
- Maturin 1.15 or newer for extension development
Installation
pip install pythonizeyaml
Optional Pydantic integration: pip install "pythonizeyaml[pydantic]" (adds
YAMLModel); add pip install "pythonizeyaml[pydantic-settings]" for
YAMLSettings.
For a source checkout:
poetry install
poetry run maturin develop
Quickstart
import pythonizeyaml as yaml
document = yaml.load(open("config.yaml", encoding="utf-8"))
document["service"]["port"] = 9090
text = yaml.dump(document)
Only the changed scalar is rewritten. Comments and formatting elsewhere remain byte-identical. Pass a writable stream as the second argument to write directly:
with open("config.yaml", "w", encoding="utf-8") as handle:
yaml.dump(document, handle)
Command Line
Installing the wheel also installs a yaml command for quick path-based
edits from the shell:
yaml config.yaml get service.port # 8080
yaml config.yaml set service.port 9090 # rewrites only that scalar
yaml config.yaml set tls.enabled true # creates the missing chain
yaml config.yaml del service.debug
Paths are dot-separated (foo.bar.jay); a numeric segment addresses an item
of the sequence at that point (servers.0.host). set creates missing
intermediate mappings automatically, and values are interpreted as YAML —
true is a boolean, 123 an integer, null is null — so quote them
("'123'") to force a string. Everything the command does not touch keeps
its original comments, indentation, and scalar styles. See
the CLI chapter
for details.
Numeric Resolution
Integers use Python's arbitrary-precision int. Decimal and exponent literals
are compared exactly with IEEE 754 binary64:
from decimal import Decimal
import pythonizeyaml as yaml
assert type(yaml.load("value: 1.5\n")["value"]) is float
assert type(yaml.load("value: 0.1\n")["value"]) is Decimal
assert type(yaml.load("value: 1e400\n")["value"]) is Decimal
Use !!float to force float or !!decimal to force Decimal.
Tags and Safety
The core and common standard YAML tags are resolved, including !!binary,
!!timestamp, !!set, and merge keys. Unknown application tags are returned as
pythonizeyaml.Tagged(tag, value) and preserve their spelling during round trips.
Use safe_load or safe_load_all for untrusted YAML. These functions reject
non-standard tags instead of constructing arbitrary Python objects.
value = yaml.safe_load("enabled: true\n")
full_load/full_load_all return plain data while tolerating unknown tags
(they come back as inert Tagged values), and unsafe_load/unsafe_load_all
are documented aliases of them. Like every loader in this library, they never
construct arbitrary Python objects.
API
The module exposes:
load,load_all,dump,dump_allsafe_load,safe_load_all,safe_dump,safe_dump_allfull_load,full_load_all,unsafe_load,unsafe_load_allround_trip_load,round_trip_load_all,round_trip_dump,round_trip_dump_allYAML,SafeYAML,IndentConfig,DEFAULT_CONFIG,TaggedDocument,DocumentStream, andCommentsload_document,load_documents,read_document, andread_documentsScalarStyle,CollectionStyle,Chomping, andSourceSpanYAMLErrorand its PyYAML-compatible subclassesYAMLModel, and withpydantic-settingsalsoYAMLSettings(optional Pydantic integration)
Loader=, Dumper, sort_keys, default_flow_style, allow_unicode, and
encoding are accepted for migration compatibility and ignored where they
conflict with lossless output.
Advanced Style Documents
load(), load_all(), and load_document() all return mutable, style-aware
Document objects whose values carry the styling API directly. For explicit
control over comments, scalar styles, collection styles, tags, anchors,
aliases, directives, and document markers, style the values you read:
from pythonizeyaml import ScalarStyle, load_document
document = load_document("name: example\nitems:\n - one\n - two\n")
document["name"].style = ScalarStyle.DOUBLE
document["name"].comments.before = ["# service name"]
document["items"].collection_style = "flow"
text = document.dump()
load_document() returns one mutable Document; load_documents() returns a
list-like DocumentStream. Collection roots load as DocumentMapping or
DocumentSequence (dict/list subclasses) and scalar roots as
DocumentScalar. Every value inside a document is a round-trip wrapper — a
dict/list subclass, or a subclass of the scalar's own type — that
compares and hashes like a plain value. Assigned scalars are wrapped and
plain dict/list values are converted, so new subtrees are styleable
immediately. Documents edit like their wrapped dict/list:
document["key"] = value, del document["key"], document["items"].append(x).
Use Document.new() to create styled documents from scratch.
Values expose path, value, span, style, collection_style,
chomping, block_indent_indicator, tag, anchor, and comments. The
set(...) method applies multiple fields atomically. Style changes are
validated before mutation; see StyleError, PathError, and
AliasError for failures. bool and None values are plain (they cannot
be subclassed) and are the only loaded scalars without this API.
For repository setup, testing, and contribution conventions, see
CONTRIBUTING.md.
Indentation Configuration
IndentConfig(mapping=2, sequence=2, offset=0, width=80, preserve_quotes=True)
controls newly created data and explicit re-layout requests. Loaded documents
retain their original layout unless an override is supplied.
Development
cargo test --manifest-path rust/Cargo.toml --no-default-features
poetry run maturin develop
poetry run pytest
poetry build
Tests run against tests/fixtures/; add malformed inputs under
tests/fixtures/invalid/.
Root Scalar Documents
Root scalars load as DocumentScalar, a Document wrapper that keeps source
metadata and scalar styles (quotes, block headers) but is not a str/int
subclass. It compares equal to the wrapped value and coerces through str(),
int(), float(), and bool(); nested scalars are ordinary Python values
with their original style and formatting retained.
Metadata
Release files for pythonizeyaml 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pythonizeyaml-0.6.1.tar.gz | 114.7 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pythonizeyaml-0.6.1-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| pythonizeyaml-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| pythonizeyaml-0.6.1-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 1.6 MB
Release files / pythonizeyaml-0.6.1.tar.gz
| Download URL | pythonizeyaml-0.6.1.tar.gz |
|---|---|
| Size | 114.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
09f51e08a66a0bf29ef7c0345770162b9275a708fd00c7f39f4fee953da722d9
|
|
BLAKE2b-256 checksum How to use checksums |
c62c2e54b4484f6585bb1da9bad6e60f6456a1e51c6d0eedfb794e40ee104c71
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / pythonizeyaml-0.6.1-cp310-abi3-win_amd64.whl
| Download URL | pythonizeyaml-0.6.1-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 433.4 kB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
43d06e13ae398ccfb4b7525b2fd0be21f08c0f1fb99750032692fd418f144c7d
|
|
BLAKE2b-256 checksum How to use checksums |
cc90cf51daa6fb2b5d1b5abbc1a1f6709bf4b9b4e1ebdb612b999ee7551deab3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / pythonizeyaml-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | pythonizeyaml-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 553.9 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
421a335b713899711dd73d8a30379d4141373c40d6a3f8efd692c3ba17457ee1
|
|
BLAKE2b-256 checksum How to use checksums |
9b8cc4a5b3b14a9b161c59e9c0dedc2fb7463e6bc10db7dbc8d8ed8482e7b872
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / pythonizeyaml-0.6.1-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | pythonizeyaml-0.6.1-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 514.1 kB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f62d191c42b2254dab85bc4499271f12bf9ba3ed8b804d11dc36d3e8d22f0fb5
|
|
BLAKE2b-256 checksum How to use checksums |
c26e9f1c67675e98cd3bdad3d1d5e365aecda1efcd870f7419c68b63d66b38fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency log