Search code examples
pythonpydantic-v2

Pydantic V2 @field_validator is not executed


I try to parse and validate a CSV file using the following Pydantic (V2) model.

from typing import Optional
from pydantic import BaseModel, field_validator
    
class PydanticProduct(BaseModel):
    fid: Optional[float]
    water: Optional[float]

    class ConfigDict:
        from_attributes = True

    @field_validator('fid', 'water',  mode='before')
    def check_empty_fields(cls, value) -> float:
        if value == '':
            return None
        try:
            float_value = float(value)
        except ValueError:
            raise ValueError("Unable to parse string as a number. Please provide a valid number.")
        return float_value

If the CSV file contents look like this

fid,water
1.0,81.3
1.25,26.3
3.0,31.5

the fields will get converted from strings to float correctly.

On the other hand if the CSV file contents have empty strings

fid,water
1.0,
,26.3
3.0,31.5

then I will get the following error

Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='', input_type=str]

I tried to use the @field_validator with the mode="before" but the problem is that the validation is not executed.

In addition, I noticed that the validation is not executed even if there are no errors (aka. the case without empty strings)


Solution

  • From the field validator documentation

    A few things to note on validators:

    • @field_validators are "class methods", so the first argument value they receive is the UserModel class, not an instance of UserModel. We recommend you use the @classmethod decorator on them below the @field_validator decorator to get proper type checking.

    So you will need to add the missing @classmethod decorator.

    from typing import Optional
    from pydantic import BaseModel, field_validator
        
    class PydanticProduct(BaseModel):
        fid: Optional[float]
        water: Optional[float]
    
        class ConfigDict:
            from_attributes = True
    
        @field_validator('fid', 'water',  mode='before')
        @classmethod
        def check_empty_fields(cls, value) -> float:
            if value == '':
                return None
            try:
                float_value = float(value)
            except ValueError:
                raise ValueError("Unable to parse string as a number. Please provide a valid number.")
            return float_value