Search code examples
pydantic

Pydantic type validate with type known only during runtime + assignment


Is it possible to have a pydantic model where I would pass the data type for one of the variables during runtime somehow? I have tried to read, but I cannot wrap my head around Pydantic on how would it work. I need data type enforcement essentially, also during assigment. I hope for something that would do things like that:

class State(BaseModel):
    datatype: type,
    value: self.datatype,
    getter: Callable
    setter: Callable

state1 = State(bool, True, get_state1, set_state1)
state2 = State(int, 0, get_state2, set_state2)

state1.value = 7 # this should throw error, expected datatype of state1 is bool

Solution

  • In think there are two independent questions here:

    • (1) Validating assignment
    • (2) Defining a type a runtime

    To enable validating assignments you can use a specific config option. See https://docs.pydantic.dev/latest/api/config/#pydantic.config.ConfigDict.validate_assignment

    Regarding (2) I would argue that Pydantic is not really made to handle type definitions at runtime. The whole point of Pydantic is to define the types beforehand, then Pydantic builds a model schema once and uses it to validate at runtime. However there are options to achieve this, if you have very good reasons to do so.

    First you could mimic that behavior by defining a custom field_validator. In the field validator you then use a TypeValidator to trigger the type validation. However it is important to say, that this only works well for small models, because the TypeValidator will build a schema on creation and rebuild every time the validation is called.

    Combined with the validate_assignment=True option you get something along the lines of:

    from pydantic import BaseModel, field_validator, TypeAdapter, ConfigDict
    from typing import Any
    
    
    class State(BaseModel):
        model_config  = ConfigDict(validate_assignment=True)
        value_type: type
        value: Any
    
        @field_validator("value", mode="before")
        @classmethod
        def validate_value(cls, value, info):
            adapter = TypeAdapter(info.data["value_type"])
            return adapter.validate_python(value)
    
    
    state1 = State(value=True, value_type=bool)
    state2 = State(value=7, value_type=int)
    
    state1.value = 7 # this should throw error, exp
    

    Which exactly raises:

    ValidationError: 1 validation error for State
    value
      Input should be a valid boolean, unable to interpret input [type=bool_parsing, input_value=7, input_type=int]
        For further information visit https://errors.pydantic.dev/2.5/v/bool_parsing
    

    Alternatively you could look into creating the whole model on runtime. For this Pydantic provides dynamic model creation, see for example https://docs.pydantic.dev/latest/concepts/models/#dynamic-model-creation

    I hope this helps!