Skip to main content

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] natizon is slightly more lenient than the official std.zon parser. 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 if or fn, but dumps() 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

import natizon

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 = natizon.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
import natizon


class Difficulty(Enum):
    EASY = "easy"
    HARD = "hard"


game_config = {
    "title": "Neon Dash",
    "difficulty": Difficulty.HARD,
    "player_stats": {"level": 10, "xp": 1500},
}

zon_string = natizon.dumps(game_config, indent=2)
print(zon_string)

Output:

.{
  .title = "Neon Dash",
  .difficulty = .HARD,
  .player_stats = .{
    .level = 10,
    .xp = 1500,
  },
}

[!NOTE] While loads() and dumps() 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 your Enum subclass 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 standard Enum tag, 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 .{}, which loads() parses as an empty dict by default. Use EmptyContainerMode.SEQUENCE if 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
import natizon
from natizon import 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),
}

zon_string = natizon.dumps(data, indent=2)
print(zon_string)

Output:

.{
  .cache_limit = "1024B",
  .buffer_size = "2048B",
}

[!IMPORTANT] If an object implements the ZonEncodable protocol, dumps() always prefers its to_zon() method over any built-in serialization of the object’s actual type. This means a subclass of str, int, or Enum that defines to_zon() will be serialized as whatever to_zon() returns, not as a string, integer, or enum literal.

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, default False): If True, parses ZON arrays (e.g., .{ 1, 2, 3 }) as Python tuples instead of lists.
  • empty_mode (EmptyContainerMode, default EmptyContainerMode.DICT): Controls whether an empty container .{} becomes an empty dictionary ({}) or an empty sequence ([] / ()).
import natizon
from natizon import EmptyContainerMode

data = natizon.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, default None): If a non-negative integer, indents with that many spaces per level. If a string (like "\t"), uses that string to indent each level. If None, outputs a compact, single-line representation.
  • sort_keys (bool, default False): If True, 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

natizon-0.4.2.tar.gz (22.5 kB view details)

Uploaded Source

Built Distribution

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

natizon-0.4.2-py3-none-any.whl (23.2 kB view details)

Uploaded Python 3

File details

Details for the file natizon-0.4.2.tar.gz.

File metadata

  • Download URL: natizon-0.4.2.tar.gz
  • Upload date:
  • Size: 22.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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

Hashes for natizon-0.4.2.tar.gz
Algorithm Hash digest
SHA256 2ff51fbc015dfdf29de740fb6062033ad39be6184ddacb973c850aee7603a3a5
MD5 13225713d9aec40f14a962c0b333e6b9
BLAKE2b-256 a49ada6bb4cd8ce50d422cd7243b583bb97a20a32107e6d4145f547ab1d58e70

See more details on using hashes here.

Provenance

The following attestation bundles were made for natizon-0.4.2.tar.gz:

Publisher: release.yml on BratishkaErik/natizon

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

File details

Details for the file natizon-0.4.2-py3-none-any.whl.

File metadata

  • Download URL: natizon-0.4.2-py3-none-any.whl
  • Upload date:
  • Size: 23.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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

Hashes for natizon-0.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a39d5efb3be6b9601912ba2d2f8dafd69965ccb5c5ab4498ee7f36a7f709db81
MD5 695fb7ba3159ad3d6581ecc11cbc1062
BLAKE2b-256 dfc129c5c2df6d734903518e9e5b23758a6498423f1cb8aa682e18a9460cdf7d

See more details on using hashes here.

Provenance

The following attestation bundles were made for natizon-0.4.2-py3-none-any.whl:

Publisher: release.yml on BratishkaErik/natizon

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 Sentry Error logging StatusPage Status page