natizon
natizon (short for "native-ZON") is a pure Python parser and serializer for
ZON (Zig Object Notation). Built on top of
Lark, it provides a familiar, json-like interface for decoding ZON strings
directly into Python data structures, and for encoding Python data structures back into ZON text.
It relies strictly on standard Python types, without AST wrappers and so on.
[!NOTE]
natizonis slightly more lenient than the officialstd.zonparser. This flexibility is intentional, making it easier to consume and work with data in Python environments.For example, you can safely parse ZON containing unquoted keywords like
iforfn, butdumps()will always normalize these to.@"if"and.@"fn"to guarantee strict compatibility.
Installation
pip install natizon
or:
uv add natizon
Usage
natizon exposes loads() and dumps() functions that work similarly to the standard library's json module.
[!TIP] Looking to parse
build.zig.zon?Check out this Python script for Parsing and validating build.zig.zon to see how to:
- load Zig 0.16 package metadata using
natizon,- validate fields with
Pydantic,- and print a pretty JSON dump using
Rich.
Parsing
from natizon import loads
zon_data = r"""
.{
.package_name = "network_tools",
.version = "2.1.0",
.supported_platforms = .{ .linux, .macos, .windows },
.dependencies = .{
.lib_a = .{ .url = "https://server.com/a.tar" },
.lib_b = .{ .path = "../local_b" }
}
}
"""
# Parses directly into standard Python dicts and lists
parsed_data = loads(zon_data)
print(parsed_data["package_name"]) # "network_tools"
print(parsed_data["supported_platforms"]) # ["linux", "macos", "windows"]
Serialization
You can serialize standard Python objects back into ZON text using dumps():
from enum import Enum
from natizon import dumps
class Difficulty(Enum):
EASY = "easy"
HARD = "hard"
game_config = {
"title": "Neon Dash",
"difficulty": Difficulty.HARD,
"player_stats": {"level": 10, "xp": 1500},
}
zon_string = dumps(game_config, indent=2)
print(zon_string)
Output:
.{
.title = "Neon Dash",
.difficulty = .HARD,
.player_stats = .{
.level = 10,
.xp = 1500,
},
}
[!NOTE] While
loads()anddumps()are designed to be compatible, some ZON-specific constructs do not roundtrip exactly:
- Enum literals (e.g.,
.linux) are parsed into Python strings and will serialize back as quoted strings ("linux"). If you want to preserve them as ZON Enum literals, convert them to yourEnumsubclass member (e.g.,Color.RED) instead.- Enum flags (
enum.Flag,enum.IntFlag) are not serializable, as their bitwise nature lacks a canonical ZON representation. To include them in your output, convert them to a standardEnumtag, integer, or array first.- Char literals (e.g.,
'a') are parsed into Python integers and will serialize back as integers (97).- Empty arrays (
[]) serialize to.{}, whichloads()parses as an empty dict by default. UseEmptyContainerMode.SEQUENCEif you need them to parse back as lists/tuples.
Advanced Usage
Validation
dumps() automatically validates your data before serialization. However, if you need to check if an object is
serializable without triggering the full serialization process, you can use validate_zon_serializable():
from natizon import validate_zon_serializable
user_settings = {
"theme": "dark",
"font_size": 14,
"notifications": True,
}
# Raises TypeError if the object is not serializable,
# or ValueError if a circular reference is detected.
try:
validate_zon_serializable(user_settings)
print("Data is valid!")
except (TypeError, ValueError) as e:
print(f"Validation failed: {e}")
Custom Serialization
If you have custom classes that you want to serialize into ZON, you can implement the ZonEncodable protocol. Simply
define a to_zon() method that returns a ZonSerializable type.
from dataclasses import dataclass
from natizon import dumps, ZonSerializable
@dataclass
class ByteSize:
bytes: int
def to_zon(self) -> ZonSerializable:
return f"{self.bytes}B"
data = {
"cache_limit": ByteSize(1024),
"buffer_size": ByteSize(2048),
}
print(dumps(data, indent=2))
Output:
.{
.cache_limit = "1024B",
.buffer_size = "2048B",
}
ZON to Python Type Mapping
When you pass a ZON string to natizon.loads(), the parser automatically converts ZON primitives and structures into
their closest Python types.
Here's breakdown:
Primitives and Literals
| ZON Type | ZON Example | Python Type | Python Value | Notes |
|---|---|---|---|---|
| Null | null |
NoneType |
None |
|
| Boolean | true, false |
bool |
True, False |
|
| Integer | 42, 0x2A |
int |
42 |
|
| Float | 3.14, inf, nan |
float |
3.14 |
Supports ZON-specific keywords: nan and inf. |
| Char Literal | 'a' |
int |
97 |
Evaluates to the integer Unicode code point. |
| String | "Hello" |
str |
"Hello" |
Handles standard escapes and Unicode \u{...}. |
| Multiline String | \\Line 1 |
str |
"Line 1" |
Strips the \\ prefix and joins multiple lines with newlines. |
| Enum Literal | .linux |
str |
"linux" |
Parsed simply as strings. |
| Quoted Identifier | .@"complex-key!" |
str |
"complex-key!" |
Slices off the @ prefix and evaluates the string. |
Structures and Containers
| ZON Type | ZON Example | Python Type | Python Value | Notes |
|---|---|---|---|---|
| Array | .{ 1, 2, 3 } |
list |
[1, 2, 3] |
Parses as a tuple if use_tuples=True is set. |
| Struct | .{ .x = 1 } |
dict |
{"x": 1} |
Raises ValueError if duplicate field names are encountered. |
| Empty Container | .{} |
dict |
{} |
Parses using Array rules if empty_mode is set to SEQUENCE. |
Configuration
use_tuples(bool, defaultFalse): IfTrue, parses ZON arrays (e.g.,.{ 1, 2, 3 }) as Pythontuples instead oflists.empty_mode(EmptyContainerMode, defaultEmptyContainerMode.DICT): Controls whether an empty container.{}becomes an empty dictionary ({}) or an empty sequence ([]/()).
from natizon import EmptyContainerMode, loads
data = loads(".{}", use_tuples=True, empty_mode=EmptyContainerMode.SEQUENCE)
print(data) # Output: ()
Python to ZON Type Mapping
When you pass a Python object to natizon.dumps(), it is converted to its natural ZON representation.
| Python Type | Python Value | ZON Output | Notes |
|---|---|---|---|
NoneType |
None |
null |
|
bool |
True, False |
true, false |
|
int |
42, -7 |
42, -7 |
|
float |
3.14 |
3.14 |
nan, inf, and -inf are serialized as ZON keywords. |
str |
"hello\nworld" |
"hello\\nworld" |
Special characters are escaped; output is always a quoted string. |
Enum |
Color.RED |
.RED |
Maps to ZON Enum Literals using the member name. |
Sequence |
[1, 2, 3] |
.{ 1, 2, 3 } |
Maps all Sequence types (e.g., list, tuple, deque, range). |
Mapping |
{"x": 1} |
.{ .x = 1 } |
Keys become ZON identifiers; non-plain keys use .@"..." syntax. |
ZonEncodable |
obj.to_zon() |
Variable | Custom: User defines the serialization (can return any supported type above, e.g., str, dict). |
Note: For Mapping types, only string keys are supported. Non-string keys will result in a TypeError.
Configuration
indent(int | str | None, defaultNone): If a non-negative integer, indents with that many spaces per level. If a string (like"\t"), uses that string to indent each level. IfNone, outputs a compact, single-line representation.sort_keys(bool, defaultFalse): IfTrue, dictionary keys are output in sorted order.
License
This project is licensed under the Apache License 2.0. See the LICENSES directory for the full license text.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 natizon-0.4.1.tar.gz.
File metadata
- Download URL: natizon-0.4.1.tar.gz
- Upload date:
- Size: 22.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2c92651c55610790ec84ae5e9bac12969113c1318abefb7539b80cb35f162a6f
|
|
| MD5 |
b627784a49f53a1fe2abcb2ba23a3c18
|
|
| BLAKE2b-256 |
bb8f9ca003e923f1efeac57762f315edbff7cc15290fec56a1f3a7cc5bf66272
|
Provenance
The following attestation bundles were made for natizon-0.4.1.tar.gz:
Publisher:
release.yml on BratishkaErik/natizon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
natizon-0.4.1.tar.gz -
Subject digest:
2c92651c55610790ec84ae5e9bac12969113c1318abefb7539b80cb35f162a6f - Sigstore transparency entry: 2164870371
- Sigstore integration time:
-
Permalink:
BratishkaErik/natizon@ebff216e877551d27f7da0c1e65c02e829b01307 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/BratishkaErik
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ebff216e877551d27f7da0c1e65c02e829b01307 -
Trigger Event:
push
-
Statement type:
File details
Details for the file natizon-0.4.1-py3-none-any.whl.
File metadata
- Download URL: natizon-0.4.1-py3-none-any.whl
- Upload date:
- Size: 23.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a3d89f00ca9bf9b4b748c842c84a502b2c34b2df44746ee02ff52c15995f708
|
|
| MD5 |
a3a5eb98f2e1722e73c43fb46ba46a5b
|
|
| BLAKE2b-256 |
4ef4bdb476c09bfe268ca804f1112697f12eb6df6beb0f8022c34c9f8331ca9c
|
Provenance
The following attestation bundles were made for natizon-0.4.1-py3-none-any.whl:
Publisher:
release.yml on BratishkaErik/natizon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
natizon-0.4.1-py3-none-any.whl -
Subject digest:
2a3d89f00ca9bf9b4b748c842c84a502b2c34b2df44746ee02ff52c15995f708 - Sigstore transparency entry: 2164870340
- Sigstore integration time:
-
Permalink:
BratishkaErik/natizon@ebff216e877551d27f7da0c1e65c02e829b01307 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/BratishkaErik
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ebff216e877551d27f7da0c1e65c02e829b01307 -
Trigger Event:
push
-
Statement type: