JSON Schema Draft-07 as a Python object. Structure maps to attributes, logic maps to methods.
pip install schema2objectA JS object has state and behavior together. JSON serialization stripped the behavior.
schema2object restores it: the schema defines the class, the data is the instance.
from schema2object import ObjectTree
schema = {
"type": "object",
"properties": {
"email": {"type": "string", "format": "email"},
"age": {"type": "integer", "minimum": 0},
"roles": {"type": "array", "items": {"enum": ["admin", "user", "guest"]}}
},
"required": ["email", "roles"]
}
data = {"email": "alice@example.com", "age": 30, "roles": ["admin"]}
user = ObjectTree(data, schema=schema)
# Dot-access (structure → attributes)
user.email # "alice@example.com"
user.age # 30Each Draft-07 logical operator maps to a method on ObjectTree:
| Draft-07 keyword | Method | Semantics |
|---|---|---|
oneOf |
one_of() |
XOR — exactly one branch matches |
anyOf |
any_of() |
OR — all matching branches |
allOf |
all_of() |
AND — merge all sub-schemas |
not |
not_of() |
NOT — data must not match |
if/then/else |
if_then() |
CASE WHEN — conditional branch |
properties |
project() |
SELECT — keep only schema-defined fields |
contains |
contains() |
EXISTS — array element check |
event_schema = {
"oneOf": [
{"properties": {"type": {"const": "text"}, "content": {"type": "string"}}},
{"properties": {"type": {"const": "image"}, "url": {"type": "string"}}},
{"properties": {"type": {"const": "stream"}, "delta": {"type": "string"}}}
]
}
event = ObjectTree({"type": "text", "content": "hello"}, schema=event_schema)
branch = event.one_of() # ObjectTree bound to matching sub-schema
branch.content # "hello"user_schema = {
"if": {"properties": {"role": {"const": "admin"}}},
"then": {"properties": {"level": {"minimum": 5}}},
"else": {"properties": {"level": {"maximum": 4}}}
}
user = ObjectTree({"role": "admin", "level": 10}, schema=user_schema)
branch = user.if_then() # bound to "then" branch
branch.schema.level # {"minimum": 5}schema = {
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
}
}
raw = ObjectTree({"name": "Alice", "age": 30, "extra": "noise"}, schema=schema)
clean = raw.project() # {"name": "Alice", "age": 30}When your schema defines x-methods, use the method name to look up and evaluate:
schema = {
"properties": {"age": {"type": "integer", "minimum": 0}},
"x-methods": {
"is_adult": {
"properties": {"age": {"minimum": 18}}
}
}
}
user = ObjectTree({"age": 20}, schema=schema)
# x-methods — read definition, runtime logic is yours
user.get_extensions() # {'x-methods': {'is_adult': {...}}, 'x-docs': {...}}from schema2object import ObjectTree
schema = {
"properties": {
"email": {"type": "string", "format": "email"},
"age": {"type": "integer", "minimum": 0}
},
"required": ["email"]
}
# Valid
user = ObjectTree({"email": "alice@example.com", "age": 30}, schema=schema)
# Invalid — raises TypeError
try:
bad = ObjectTree({"email": "not-an-email"}, schema=schema)
bad.validate()
except TypeError as e:
print(e) # 'email': does not match format 'email'ObjectTree treats the schema as a class definition:
# Schema = class spec
schema = {
"properties": {
"name": {"type": "string", "minLength": 1},
"score": {"type": "number", "minimum": 0, "maximum": 100}
},
"required": ["name"],
"x-methods": {
"passed": {"properties": {"score": {"minimum": 60}}}
},
"x-docs": {
"intent": "Student result entity. Score 60+ means passed."
}
}
# Instance = ObjectTree
student = ObjectTree({"name": "Alice", "score": 85}, schema=schema)
# Access state
student.name # "Alice"
student.score # 85
# x-methods — read definition, runtime logic is yours
student.get_extensions() # {'x-methods': {'passed': {...}}, 'x-docs': {...}}ObjectTree(data, *, schema=None) # construct
obj.key # dot-access field (attribute)
obj["key"] # bracket-access field
obj.get("key") # safe access → ObjectTree or None
obj.to_dict() # batch output — serialization, API response, writing to disk
obj.validate() # validate against schema, raises TypeError on fail
# Draft-07 logic methods
obj.one_of() # → ObjectTree (XOR branch)
obj.any_of() # → list[ObjectTree] (OR branches)
obj.all_of() # → ObjectTree (AND merged schema)
obj.not_of() # → bool
obj.if_then() # → ObjectTree (conditional branch)
obj.project() # → ObjectTree (schema-defined fields only)
obj.contains(schema)# → bool- Source:
projects/schema2object/ - Philosophy:
methodology/sdd-philosophy.md - x- extensions:
methodology/x-extensions.md - Rust equivalent:
references/rust/schema-value.md