PLAIN PYTHON · ZERO RUNTIME DEPS
Exact types, coercion, and unions
Understand bool versus int, string conversion, and union order in zodify 0.6.0.
Exact Python types by default
The int schema accepts an actual int. It rejects bool, float, and string values, even when they look numerically equivalent. Coercion is an explicit option.
With coerce=True, string input can convert to int or float. Boolean strings are case-insensitive true/1/yes and false/0/no. Strings are not trimmed by the boolean rule. Conversion to str uses str(value); numeric schemas do not accept arbitrary constructor casting from non-string input.
import json
from zodify import validate
accepted = []
for token in ["1", "1.0", "true", '"1"']:
value = json.loads(token)
try:
validate({"count": int}, {"count": value})
except ValueError:
accepted.append(False)
else:
accepted.append(True)
assert accepted == [True, False, False, False]
assert validate({"port": int}, {"port": "8080"}, coerce=True) == {"port": 8080}
assert validate({"value": int | str}, {"value": "1"}, coerce=True)["value"] == 1
assert validate({"value": str | int}, {"value": "1"}, coerce=True)["value"] == "1"
print("exact-types: passed")
Expected output: exact-types: passed
Union order can change string results
In coercing unions, exact non-string matches win first. String input then tries union members in their declared order: int | str can turn '1' into 1, while str | int preserves '1'. Without coercion, exact membership determines acceptance. Do not reorder a union casually.