https://github.com/ktav-lang/python
Python bindings for Ktav — a plain configuration format with three rules, zero indentation, and zero quoting. PyO3 over the reference Rust crate, abi3 wheels, json-shaped API.
https://github.com/ktav-lang/python
config config-format configuration ktav parser pyo3 python
Last synced: 2 months ago
JSON representation
Python bindings for Ktav — a plain configuration format with three rules, zero indentation, and zero quoting. PyO3 over the reference Rust crate, abi3 wheels, json-shaped API.
- Host: GitHub
- URL: https://github.com/ktav-lang/python
- Owner: ktav-lang
- License: mit
- Created: 2026-04-24T06:45:21.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-04-24T07:45:51.000Z (2 months ago)
- Last Synced: 2026-04-24T09:08:57.613Z (2 months ago)
- Topics: config, config-format, configuration, ktav, parser, pyo3, python
- Language: Python
- Size: 60.5 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# ktav (Python)
> Python bindings for [Ktav](https://github.com/ktav-lang/spec) — a plain
> configuration format. JSON-shape, no quotes, no commas, dotted keys.
> Powered by Rust under the hood.
**Languages:** **English** · [Русский](README.ru.md) · [简体中文](README.zh.md)
**Specification:** this package implements **Ktav 0.1**. The format is
versioned and maintained independently of this package — see
[`ktav-lang/spec`](https://github.com/ktav-lang/spec) for the formal
document.
---
## Install
```
pip install ktav
```
Wheels are published for every major platform and every supported
Python version:
- **Linux** (manylinux + musllinux) — `x86_64`, `aarch64`
- **macOS** — `x86_64`, `arm64` (Apple Silicon)
- **Windows** — `x64`, `arm64`
Python **3.9+** is required. The wheels target the stable ABI
(`abi3-py39`), so a single wheel per platform serves every supported
CPython release.
If no prebuilt wheel matches your platform, `pip` falls back to the
source distribution and compiles it locally — you need a Rust toolchain
(`rustup`) and the Python development headers.
## Quick start
### Parse — read typed fields straight off the dict
```python
import ktav
src = """
service: web
port:i 8080
ratio:f 0.75
tls: true
tags: [
prod
eu-west-1
]
db.host: primary.internal
db.timeout:i 30
"""
cfg = ktav.loads(src)
service: str = cfg["service"]
port: int = cfg["port"]
ratio: float = cfg["ratio"]
tls: bool = cfg["tls"]
tags: list[str] = cfg["tags"]
db_host: str = cfg["db"]["host"]
db_timeout: int = cfg["db"]["timeout"]
```
### Walk — dispatch on the runtime type
```python
for k, v in cfg.items():
if v is None: kind = "null"
elif isinstance(v, bool): kind = f"bool={v}" # bool first — True is also an int!
elif isinstance(v, int): kind = f"int={v}"
elif isinstance(v, float): kind = f"float={v}"
elif isinstance(v, str): kind = f"str={v!r}"
elif isinstance(v, list): kind = f"array({len(v)})"
elif isinstance(v, dict): kind = f"object({len(v)})"
print(f"{k} -> {kind}")
```
### Build & render — construct a document in code
```python
doc = {
"name": "frontend",
"port": 8443,
"tls": True,
"ratio": 0.95,
"upstreams": [
{"host": "a.example", "port": 1080},
{"host": "b.example", "port": 1080},
],
"notes": None,
}
text = ktav.dumps(doc)
# name: frontend
# port:i 8443
# tls: true
# ratio:f 0.95
# upstreams: [
# { host: a.example port:i 1080 }
# { host: b.example port:i 1080 }
# ]
# notes: null
```
A complete runnable version lives in [`examples/basic.py`](examples/basic.py).
Four entry points mirror the standard library `json` module:
| Function | Purpose |
|-----------------------|----------------------------------------------|
| `ktav.loads(s)` | Parse a Ktav string (or UTF-8 `bytes`). |
| `ktav.dumps(obj)` | Serialise a native Python value. |
| `ktav.load(fp)` | Parse from a file-like object. |
| `ktav.dump(obj, fp)` | Serialise to a file-like object. |
`load` / `dump` accept both text-mode and binary-mode files.
## Type mapping
| Ktav | Python |
|----------------------|----------|
| `null` | `None` |
| `true` / `false` | `bool` |
| `:i ` | `int` |
| `:f ` | `float` |
| bare scalar | `str` |
| `[ ... ]` | `list` |
| `{ ... }` | `dict` |
Ktav keeps **"no magic types"** — a bare `port: 8080` stays a string at
the parser level. Use the typed markers `:i` / `:f` when you want
numbers, or type-coerce at the application layer.
`dict` preserves insertion order (Python 3.7+ guarantee), matching the
ordered-object semantics of Ktav.
Serialisation is the inverse:
- Python `int` → `:i` marker (including arbitrary-precision bigints).
- Python `float` → `:f` marker (decimal point always present;
`NaN` / `±Infinity` are rejected — Ktav 0.1.0 does not represent them).
- Python `tuple` is accepted as an array, for symmetry with `list`.
- Non-`str` keys in a `dict` raise `KtavEncodeError`.
## Errors
```python
import ktav
try:
ktav.loads("x: [")
except ktav.KtavDecodeError as e:
print("decode:", e)
try:
ktav.dumps({"v": float("nan")})
except ktav.KtavEncodeError as e:
print("encode:", e)
# Catching the base class catches either.
try:
ktav.loads("a: 1\na: 2")
except ktav.KtavError:
...
```
| Exception | Raised by | Base |
|---------------------|-------------|---------------------|
| `KtavError` | (base) | `Exception` |
| `KtavDecodeError` | `loads` / `load` | `KtavError` |
| `KtavEncodeError` | `dumps` / `dump` | `KtavError` |
## Philosophy
Ktav is intentionally small. Its five design principles
(from [`spec/CONTRIBUTING.md`](https://github.com/ktav-lang/spec/blob/main/CONTRIBUTING.md)):
1. **Locality** — a line's meaning does not depend on another line.
2. **One sentence** — any new rule fits in one sentence of the spec.
3. **No whitespace sensitivity** (line breaks aside).
4. **No magic types** — the format never decides `"8080"` means a number.
5. **Explicit over clever** — `::` is verbose on purpose.
The Python bindings honour this: they add no schema inference, no
auto-casting, no defaulting. If you want typing, you do it at the
boundary with your own tool — `pydantic`, `dataclasses`, `attrs` —
against the native Python structures this library returns.
## Related projects
- [`ktav-lang/spec`](https://github.com/ktav-lang/spec) — canonical
format specification and language-agnostic conformance test suite.
- [`ktav-lang/rust`](https://github.com/ktav-lang/rust) — reference Rust
implementation. These Python bindings are a thin PyO3 wrapper around
that crate.
## Versioning
This package follows [Semantic Versioning](https://semver.org/) with the
pre-1.0 convention that a MINOR bump is breaking. The package version
and the `ktav` crate version move together. `ktav.__spec_version__`
reports the Ktav format version this binding supports.
## Development
See [CONTRIBUTING.md](CONTRIBUTING.md) for the dev setup, test layout,
and the contribution workflow.
## Support the project
The author has many ideas that could be broadly useful to IT worldwide —
not limited to Ktav. Realizing them requires funding. If you'd like to
help, please reach out at **phpcraftdream@gmail.com**.
## License
MIT. See [LICENSE](LICENSE).