Cerberus schemas: coercion, defaults and custom rules: working versions (tested 2026-10-16)
A Cerberus signup schema that coerces types, fills default and default_setter fields, and enforces subclass plus check_with rules, tested offline.
passed5 passed · 0 failed2026-10-16 09:57 UTC- Status
- passed
- Last passed
- 2026-10-16 09:57 UTC
- Tests
- 5 / 5
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions2
cerberus@1.3.8pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
test environment
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38883899161
The code
Exactly the files that passed. Your agent can pull them with get_recipe("cerberus-schema-normalization") (install), or see them on GitHub.
requirements.txt
cerberus==1.3.8 pytest==9.1.1
schema.py
from cerberus import Validator
def default_nickname(doc):
return doc["username"].split("@")[0].strip()
def strong_password(field, value, error):
if not any(c.isdigit() for c in value):
error(field, "must contain a digit")
SIGNUP = {
"username": {
"type": "string",
"coerce": str.strip,
"required": True,
"empty": False,
"is_lower": True,
},
"email": {
"type": "string",
"required": True,
"regex": r"^[^@\s]+@[^@\s]+\.[^@\s]+$",
},
"age": {"type": "integer", "coerce": int, "min": 13},
"password": {"type": "string", "required": True, "check_with": strong_password},
"role": {"type": "string", "default": "viewer", "allowed": ["viewer", "editor"]},
"tags": {
"type": "list",
"default": [],
"schema": {"type": "string", "coerce": str.lower},
},
"nickname": {"type": "string", "default_setter": default_nickname},
}
class SignupValidator(Validator):
def _validate_is_lower(self, is_lower, field, value):
"""{'type': 'boolean'}"""
if is_lower and value != value.lower():
self._error(field, "must be lowercase")
tests/test_schema.py
from schema import SIGNUP, SignupValidator
BASE = {
"username": "ada",
"email": "[email protected]",
"age": "36",
"password": "s3cret",
}
def test_validated_coerces_and_applies_defaults():
v = SignupValidator(SIGNUP)
doc = v.validated({**BASE, "tags": ["Math", "LOGIC"]})
assert v.errors == {}
assert doc["age"] == 36
assert doc["role"] == "viewer"
assert doc["tags"] == ["math", "logic"]
assert doc["nickname"] == "ada"
def test_normalized_skips_validation_rules():
v = SignupValidator(SIGNUP)
out = v.normalized({**BASE, "username": "Ada"})
assert out["username"] == "Ada" and v.errors == {}
assert v.validated({**BASE, "username": "Ada"}) is None
assert v.errors["username"] == ["must be lowercase"]
def test_default_overrides_none_unless_nullable():
plain = SignupValidator({"role": {"type": "string", "default": "viewer"}})
assert plain.normalized({})["role"] == "viewer"
assert plain.normalized({"role": None})["role"] == "viewer"
nullable = SignupValidator(
{"role": {"type": "string", "default": "viewer", "nullable": True}}
)
assert nullable.normalized({"role": None})["role"] is None
def test_purge_unknown_vs_unknown_rejected():
loose = SignupValidator(SIGNUP, purge_unknown=True)
assert "admin" not in loose.normalized({**BASE, "admin": True})
strict = SignupValidator(SIGNUP)
assert strict.validate({**BASE, "age": 36, "admin": True}) is False
assert strict.errors["admin"] == ["unknown field"]
def test_check_with_password_rule():
v = SignupValidator(SIGNUP)
assert v.validate({**BASE, "age": 36, "password": "nodigits"}) is False
assert v.errors["password"] == ["must contain a digit"]
pytest.ini
[pytest] pythonpath = .
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.