Metadata-Version: 2.4
Name: py-yaml12
Version: 0.2.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Typing :: Typed
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Text Processing :: Markup
License-File: LICENSE
Summary: A modern YAML 1.2 parser and emitter for Python, written in Rust.
Keywords: yaml,parser,serializer,rust,pyo3,abi3
Author: Tomasz Kalinowski
Maintainer: Tomasz Kalinowski
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Documentation, https://posit-dev.github.io/py-yaml12/
Project-URL: Homepage, https://github.com/posit-dev/py-yaml12
Project-URL: Issues, https://github.com/posit-dev/py-yaml12/issues
Project-URL: Repository, https://github.com/posit-dev/py-yaml12

# yaml12

A YAML 1.2 parser/formatter for Python, implemented in Rust for speed
and correctness. Built on the excellent
[`saphyr`](https://github.com/saphyr-rs/saphyr) crate.

Compared with YAML 1.1's type library, YAML 1.2's recommended core
schema uses more conservative type inference for unquoted values. The
[YAML 1.1 versus 1.2 quick
reference](https://posit-dev.github.io/py-yaml12/user-guide/yaml-in-2-minutes.html#why-yaml-12)
summarizes the differences.

For almost every use case, `yaml12` lets you work with plain builtin
Python types end to end: `dict`, `list`, `int`, `float`, `str`, and
`None`. JSON is a subset of YAML 1.2, so all valid JSON is also valid
YAML and parses the same way.

- Parse YAML text or files with `parse_yaml()` and `read_yaml()`.
- Serialize Python values with `format_yaml()` or `write_yaml()`.
- 100% compliance with the [yaml-test-suite](https://github.com/yaml/yaml-test-suite).
- Advanced YAML features (document streams, tags, complex mapping keys) are supported and
  round-trip cleanly when needed. `Yaml` is the wrapper type for tagged nodes and unhashable
  mapping keys.

## Installation

The package ships prebuilt wheels for CPython 3.10+ and PyPy 3.11. Install from PyPI:

```bash
pip install py-yaml12
```

Wheel coverage:

| Platform | CPython architectures | PyPy 3.11 architectures |
|---|---|---|
| Linux (glibc) | x86-64, x86, ARM64, ARMv7, ppc64le, s390x | x86-64, x86 |
| Linux (musl) | x86-64, x86, ARM64, ARMv7 | — |
| macOS | Apple silicon, Intel | Apple silicon, Intel |
| Windows | x86-64, x86, ARM64 | x86-64 |

CPython 3.14 free-threaded builds use separate `cp314t` wheels for the
same CPython platforms. Free-threading support is currently beta.

## Development install

You can install the development version of `yaml12` from github.
Clone the repository and install in editable mode:

```bash
git clone https://github.com/posit-dev/py-yaml12.git
cd py-yaml12
python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install --group test
pip install -e . --no-build-isolation
```

To install the latest main branch without cloning:

```bash
pip install git+https://github.com/posit-dev/py-yaml12.git
```

Python 3.10 or newer is required. Building from source also requires Rust 1.83 or newer.

## Quick start

```python
from yaml12 import parse_yaml, format_yaml, Yaml

yaml_text = """
title: A modern YAML parser and emitter written in Rust
properties: [fast, correct, safe, simple]
features:
  tags: preserve
  streams: multi
"""

doc = parse_yaml(yaml_text)

assert doc == {
    "title": "A modern YAML parser and emitter written in Rust",
    "properties": ["fast", "correct", "safe", "simple"],
    "features": {"tags": "preserve", "streams": "multi"},
}

round_tripped = parse_yaml(format_yaml(doc))
assert round_tripped == doc

# Long strings wrap at 80 columns by default.
narrow_yaml = format_yaml(doc, width=40)

# None disables wrapping.
unwrapped_yaml = format_yaml(doc, width=None)

# Tagged values (advanced)
from yaml12 import Yaml

tagged = parse_yaml("!expr 1 + 1")
assert tagged == Yaml(value="1 + 1", tag="!expr")
```

## Reading and writing files

Filesystem paths beginning with `~` are expanded using `os.path.expanduser()`.

```python
from yaml12 import read_yaml, write_yaml

value_out = {"alpha": 1, "nested": [True, None]}

write_yaml(value_out, "my.yaml")
value_in = read_yaml("my.yaml")
assert value_in == value_out

# Append another YAML document instead of replacing the file.
next_value = {"beta": 2}
write_yaml(next_value, "my.yaml", append=True)
assert read_yaml("my.yaml", multi=True) == [value_out, next_value]

# Multi-document streams
docs_out = [{"foo": 1}, {"bar": [2, None]}]
write_yaml(docs_out, "my-multi.yaml", multi=True)
docs_in = read_yaml("my-multi.yaml", multi=True)
assert docs_in == docs_out
```

## Tag handlers

Handlers let you opt into custom behavior for tagged nodes while
keeping the default parser strict and safe.

```python
from yaml12 import parse_yaml

yaml_text = """
- !upper [rust, python]
- !expr 6 * 7
"""

handlers = {
    "!expr": lambda value: eval(value),
    "!upper": lambda value: [x.upper() for x in value],
}

doc = parse_yaml(yaml_text, handlers=handlers)
assert doc == [["RUST", "PYTHON"], 42]
```

## Non-string mapping keys and tags

YAML mappings can use keys that themselves collections, or that carry
tags. Such keys cannot always be represented directly in a Python
`dict`, so `yaml12` wraps them in `Yaml` to make the key hashable.

```python
from yaml12 import Yaml, parse_yaml, format_yaml

obj = {
    "seq": [1, 2],
    "map": {"key": "value"},
    "tagged": Yaml("1 + 1", "!expr"),
    Yaml("foo", "!custom-key"): "bar",
}

yaml_text = format_yaml(obj)
round_tripped = parse_yaml(yaml_text)
assert round_tripped == obj
```

## Documentation

Online docs: https://posit-dev.github.io/py-yaml12/

To build or serve the docs locally:

```bash
pip install --group docs
pip install --upgrade great-docs
great-docs build       # or: great-docs preview
```

## Tests

From the repo root:

```bash
cargo fmt
cargo check
cargo test
cargo build
cargo clippy
.venv/bin/pip install -e . --no-build-isolation
.venv/bin/python -m pytest tests_py
```

## Release process

See the [release checklist](https://github.com/posit-dev/py-yaml12/blob/main/RELEASE.md)
for the version, artifact, tag, and publication checklist.

