Search code examples
pythonpydantic

Condense Pydantic Validators into Class Annotations


Looking to create a datastructure in Python that condenses Pydantic's validators into oneline arguments:

ie. from this

from pydantic import BaseModel, validator


class MyClass(BaseModel):
    a: str
    b: str
    c: str
    
    @validator('b')
    def calculate_b(cls, v, values):
        return values['a'] + v
      
    @validator('c')
    def calculate_c(cls, v, values):
        return values['a'] + values['b'] + v

to (something like) this

class MyClass:
    a: str
    b: str = calculate_b(...)
    c: str = calculate_c(...)

Solution

  • My Pydantic version is: 2.5.0


    Note: The @validator you used is deprecated in V2 and will be removed in V3. You should use field_validator instead if you want.

    You can use Annotated + AfterValidator(actually the default mode for field_validator is "after"):

    from typing import Annotated
    
    from pydantic import AfterValidator, BaseModel
    
    
    class MyClass(BaseModel):
        a: str
        b: Annotated[str, AfterValidator(lambda v, values: values.data["a"] + v)]
        c: Annotated[str, AfterValidator(lambda v, values: values.data["a"] + values.data["b"] + v)]
    
    
    obj = MyClass(a="a", b="b", c="c")
    print(obj)
    # a='a' b='ab' c='aabc'
    

    If the annotation became long, you can make alias out of them outside the class. But I think it's ok.

    The values are of type ValidationInfo and in order to access to the data you can use the .data attribute.