Lightweight validation for Python mappings and JSON-like documents.
dictify is a lightweight validation library for standalone fields and mapping-shaped models.
It is designed for small schema layers, partial validation, and annotation-first models with explicit dict-like behavior.
- Python
3.12+ - Use
Field(...)for defaults, required fields, and extra validators - Use Python annotations to declare
Modelfield types - Access model data with either attributes or mapping syntax
- Validate a single value with
Field(...)without defining a full model - Define annotation-first
Modelclasses for dict-shaped documents - Keep mapping access and attribute access together
- Handle unknown keys and public attributes explicitly with
strict - Convert back to plain Python data with
dict(model)andmodel.dict()
pip install dictifyfrom datetime import UTC, datetime
from typing import Annotated
from dictify import Field, Model
class Note(Model):
title: str = Field(required=True).verify(
lambda value: len(value) <= 300,
"Title must be 300 characters or fewer",
)
content: str = Field()
timestamp: Annotated[datetime, "creation time"] = Field(
default=lambda: datetime.now(UTC)
)
note = Note({"title": "Dictify", "content": "dictify is easy"})
note.content = "Updated content"
note["content"] = "Updated again"
# These raise Model.Error.
note.title = 0
note["title"] = 0Model is strict by default.
strict=Truerejects undeclared keys and undeclared public attributesstrict=Falsestores undeclared keys and attributes as extra model data
note = Note({"title": "Dictify"}, strict=False)
note.category = "docs"
assert note["category"] == "docs"
assert dict(note)["category"] == "docs"Use explicit conversion when you need plain Python data.
import json
note_dict = dict(note) # shallow dict conversion
note_native = note.dict() # recursive dict/list conversion
note_json = json.dumps(note.dict())Field.instance(...) still works well for standalone validation.
email = Field(required=True).instance(str).match(r".+@.+")
email.value = "user@example.com"dictify ships with an installed CLI for the packaged AI skill.
dictify ai-skill-installThe installer prompts for the exact destination folder and defaults to:
./.agents/skills/dictify-usage
If the destination already exists, dictify asks before overwriting it.
Repository-local maintenance commands live under dev/cli.
Run them from the repo root with:
uv run python -m dev.cli --helpExamples:
uv run python -m dev.cli docs build
uv run python -m dev.cli docs dev
uv run python -m dev.cli ai skill-ref
uv run python -m dev.cli build
uv run python -m dev.cli release-checkSee dev/README.md for the command summary.
The annotation-first model API is fully supported at runtime.
Static type checker support for declarations like email: str = Field(...) is still limited and may require cast(Any, Field(...)) depending on the checker and editor.
- Docs: https://keenlycode.github.io/dictify/
- Usage: https://keenlycode.github.io/dictify/guide/usage/
- AI Skill: https://keenlycode.github.io/dictify/guide/ai-skill/
- Field API: https://keenlycode.github.io/dictify/guide/field-api/
- Validation Recipes: https://keenlycode.github.io/dictify/guide/validation-recipes/
- Changelog: https://github.com/keenlycode/dictify/blob/main/CHANGELOG.md