Skip to main content

zodify

zodify

Validation for Python dictionaries.

zodify validates configuration and script inputs using ordinary Python types. It is written in pure Python with zero required runtime dependencies.

Documentation | Choosing a validator | PyPI | Changelog

Install

pip install zodify

Supports Python 3.10–3.13. The project is in alpha. These examples describe 0.8.0, published and verified September 9, 2026. See the compatibility contract for supported behavior and the path to 1.0.

Quick Start

from zodify import validate

schema = {"port": int, "debug": bool}

validate(schema, {"port": 8080, "debug": False})
# {'port': 8080, 'debug': False}

validate(schema, {"port": "8080", "debug": False})
# ValueError: port: expected int, got str

A dictionary schema returns a new dictionary. Types are strict by default: "8080" is a string, so it fails an int check. Failures raise ValueError with a path to the field. Extra keys are rejected.

Choosing a validator

Use cases for zodify Reasons to consider another approach
You already have dictionaries and want reusable checks. A few direct Python checks already solve the task.
You validate configuration, CLI input, or data in scripts. Your framework already provides the validation you need.
Zero required runtime dependencies matter. You need a broader annotation vocabulary, model features, or specialized serialization.

Pydantic supports both models and TypeAdapter for ordinary types, including dictionaries. Use a dedicated JSON Schema implementation when a JSON Schema document is your validation language. The comparison guide explains the tradeoffs.

Schemas

Use nested dictionaries, single-element lists, unions, and optional keys as needed:

from zodify import Optional, validate

schema = {
    "db": {"host": str, "port": Optional(int, 5432)},
    "tags": [str],
    "debug": Optional(bool, False),
}

validate(schema, {"db": {"host": "localhost"}, "tags": ["prod"]})
# {'db': {'host': 'localhost', 'port': 5432}, 'tags': ['prod'], 'debug': False}

Conversions are explicit. For string inputs such as configuration values:

validate({"port": int}, {"port": "8080"}, coerce=True)
# {'port': 8080}

Schema grammar and conversion rules cover the details.

Validation behavior

  • Strict types: ordinary validation does not coerce values. bool and int are distinct. Set coerce=True to opt into the documented conversions.
  • Unknown keys: rejected by default. unknown_keys="strip" drops them.
  • Missing versus null: Optional(type) permits omission; type | None permits a null value. These are separate choices.
  • Default ownership: defaults are trusted, without validation or copying. Mutable defaults can be shared between results. Successful validation does not make data deeply immutable.
  • Errors: text mode raises ValueError. With error_mode="structured", ValidationError adds legacy .issues and canonical .details.
  • Depth: max_depth=32 counts shaped dictionary traversals, including the root. It does not limit list nesting, input size, or general resource use.

See defaults and ownership and error handling.

Optional class syntax

For attribute access, declare a supported Schema:

from zodify import Schema, validate

class Config(Schema):
    port: int
    debug: bool = False

config = validate(Config, {"port": 8080})
print(config.port)  # 8080

Validate class declarations with validate(Config, data). Direct Config() instantiation is unsupported. Annotations are limited to the documented subset. See class schemas and limitations.

Guides and reference

Task Guide
Run your first validation Getting started
Validate application configuration Configuration guide
Validate command-line input CLI guide
Parse and validate a JSON object JSON input guide
Look up options, env parsing, errors, or JSON export limits Full API reference
Run complete examples Example scripts

env() reads one variable; load_env() parses an env file without changing the process environment. In schema mode, load_env() defaults to coercion and unknown-key stripping, unlike ordinary validation. Env file loading, canonical details, and conservative JSON input/export require 0.8.0; the quickstart also works with 0.6.0.

Project and contributions

Read the contributor guide for local checks and the release procedure for publication. Report problems in GitHub Issues.

Benchmark methodology documents the measured workloads and comparison limits. The roadmap distinguishes released features from plans. Compilation remains outside the public API. The implementation issue tracks direction.

License

MIT

Copyright 2026 Jun Young Sohn.

Metadata

Release files for zodify 0.8.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zodify 0.8.1
File Size Uploaded Provenance Actions
zodify-0.8.1.tar.gz 32.6 kB Without provenance Details for zodify-0.8.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for zodify 0.8.1
File Interpreter ABI Platform Actions
zodify-0.8.1-py3-none-any.whl Python 3 none any Details for zodify-0.8.1-py3-none-any.whl

Total release size: 52.1 kB

Release files / zodify-0.8.1.tar.gz

Download URL zodify-0.8.1.tar.gz
Size 32.6 kB
Tags Source
SHA-256 checksum
How to use checksums
ff05f969e4a674a650ae4259b8188b129da888109b5b55e9bbb2351edccc0778
BLAKE2b-256 checksum
How to use checksums
e20c2b11d8ce3cdd94cfa1c37b231634774b6f342571c0fcc2f9c8530b82165c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.11

Release files / zodify-0.8.1-py3-none-any.whl

Download URL zodify-0.8.1-py3-none-any.whl
Size 19.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4e118c65b2dd144b745530795853307098c4f57002c6e57dc57fa6734c3c58a6
BLAKE2b-256 checksum
How to use checksums
6dc294d37e45ba434cdab0ff8fd206325daa311cb3d4295f2835224690b0cd0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.11

Security for zodify 0.8.1

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page