Skip to content
Cascading Labs QScrape VoidCrawl Yosoi

Validators

Yosoi offers two layers of field-level validation: built-in type coercions that handle the common cases, and a Validators inner class for custom transforms.

Built-in Coercions

Field types like ys.Price(), ys.Title(), and ys.Author() coerce raw strings automatically — no @field_validator needed.

import yosoi as ys
class Product(ys.Contract):
title: str = ys.Title()
price: float = ys.Price(description='Book price, always includes £ symbol')
rating: str = ys.Rating(description="Star rating written as a word e.g. 'Three'")
raw = {'title': ' A Light in the Attic ', 'price': '£12.99', 'rating': ' Three '}
result = Product.model_validate(raw)
# result.title == 'A Light in the Attic' (whitespace stripped)
# result.price == 12.99 (float, £ stripped)
# result.rating == 'Three' (whitespace stripped)

Validators Inner Class

For custom per-field transforms, define static methods inside a Validators class. They run before Pydantic’s△ own validation. No decorator ceremony required.

class BookStore(ys.Contract):
title: str = ys.Title()
price: float = ys.Price(description='Book price including currency symbol')
category: str = ys.Field(description='Genre or category label')
class Validators:
@staticmethod
def title(v: str) -> str:
"""Truncate very long titles to 60 characters."""
return v[:60].rstrip() + ('...' if len(v) > 60 else '')
@staticmethod
def category(v: str) -> str:
"""Normalise category to title case."""
return v.strip().title()
raw = {
'title': 'The Very Long Title That Goes On and On and Eventually Exceeds Sixty Characters',
'price': '$1,234.56',
'category': ' science fiction ',
}
result = BookStore.model_validate(raw)
# result.title == 'The Very Long Title That Goes On and On and Eventually...'
# result.price == 1234.56 ($ and , stripped by ys.Price)
# result.category == 'Science Fiction'

Each method name must match the field name it transforms. Methods that don’t match any field are silently ignored.

FAQs

Can I raise an error inside a Validators method?

Yes. Raise a standard ValueError and Pydantic will wrap it into a ValidationError as usual.

Do validators run on list[T] fields element-by-element?

No. The validator receives the full list as its argument. If you need per-element processing, iterate inside the method.

Can I use async validators?

No. Validators methods must be synchronous static methods. For async post-processing, handle it after model_validate() returns.

What is the execution order?

Validators methods run first, then built-in type coercions, then Pydantic’s own validation. This means your custom transforms see the raw extracted string before any coercion has been applied.

References

△ Pydantic. Pydantic Services Inc. Data validation library for Python. https://docs.pydantic.dev/