pythontypespydantic

Is it possible to have a "dependently typed" field in a pydantic class?


I wonder if, and then how, in Pydantic, one could have a field whose type is determined by the value of another field, e.g., as follows:

from pydantic import BaseModel

class Example(BaseModel):
    type: str
    value: MyType[type] # not possible and wrong syntax, but ...

Let's say I want to have instances with int or complex:

ex1 = Example(type="int", value = 5) # or maybe MyType("int",5)
ex2 = Example(type="complex", value=1+2j) # or maybe MyType("complex", 1+2j)

Then I want ex1.value to be validated as an integer, and ex2.value as a complex. Ultimately I want multidimensional lists (T, List[T], List[List[T]], etc.) carrying (where T is) int, float, complex, or str.

Is there a nice way of doing something in that direction? (preferably in Python 3.8)


Solution

  • Would something like this work for you?

    from pydantic.generics import GenericModel
    from typing import Generic, TypeVar, TYPE_CHECKING
    
    T = TypeVar('T')
    
    class Example(GenericModel, Generic[T]):
        value: T
    
    ex1 = Example[int](value=5)
    ex2 = Example[complex](value=1+2j)
    
    if TYPE_CHECKING:
        reveal_type(ex1.value)
        reveal_type(ex2.value)
    

    Output:

    $ mypy program.py
    program.py:13: note: Revealed type is "builtins.int"
    program.py:14: note: Revealed type is "builtins.complex"
    Success: no issues found in 1 source file
    

    If you want to have a type attribute you can add it like this:

    from pydantic.generics import GenericModel
    from typing import Generic, Type, TypeVar, TYPE_CHECKING
    
    T = TypeVar('T')
    
    class Example(GenericModel, Generic[T]):
        type: Type[T]
        value: T
    
    ex1 = Example[int](type=int, value=5)