Search code examples
pythoninitializationgetter-setterpydantic

pydantic How to set hex string to int using pydantic?


Sometimes, any data return a hex string like "bbb". I wanna use to int value by "bbb". So I wrote code case1.. but it is an error.

How to convert hex string to int value using BaseModel? Does pydantic also have a setter getter function? I know a method like case2, but I wanna use a json data directly, because of some key is empty...!

case 1

from pydantic import BaseModel
from typing import Optional

data = {
    "aaa" : 4,
    "bbb" : "0x3",
}

class DataTemp(BaseModel):
    aaa : int
    bbb : Optional[int]
    
def main():
    _data = DataTemp(**data)
    print(_data)
    

if __name__ == "__main__":
    main()

case2

_data2 = DataTemp(aaa= data["aaa"], bbb=int(data["bbb"],16))

Solution

  • This answer has been updated for Pydantic V2 (specifically 2.5.x) as per the this section of their migration guide while maintaining the original intent of this prior revision.


    Pydantic does allow the attachment of additional validators to a given field by via field validators. When creating one you will need to take care to deal with the incoming data and process it based on your requirements. In your example, it should allow None, standard ints and also any str that represent a hexadecimal string. So the following implementation can satisfy the mentioned constraints:

    from typing import Optional
    from pydantic import BaseModel, ValidationInfo, field_validator
    
    class DataTemp(BaseModel):
        aaa: int
        # to allow the assignment of str along with int, even though the
        # value will always be casted back to an int via the field validator,
        # and set the default value to None to permit omitted key in V2
        bbb: Optional[int | str] = None
    
        @field_validator('bbb')
        @classmethod
        def validate_bbb(cls, v: Optional[int | str], info: ValidationInfo):
            return int(v, 16) if isinstance(v, str) else v
    

    Usage:

    >>> DataTemp(aaa=4, bbb=33)
    DataTemp(aaa=4, bbb=33)
    >>> DataTemp(aaa=4, bbb=None)
    DataTemp(aaa=4, bbb=None)
    >>> DataTemp(aaa=4)  # bbb omitted, defaults to None as specified
    DataTemp(aaa=4, bbb=None)
    >>> DataTemp(aaa=4, bbb='0x333')
    DataTemp(aaa=4, bbb=819)
    >>> DataTemp(aaa=4, bbb='32')
    DataTemp(aaa=4, bbb=50)
    >>> DataTemp(aaa=4, bbb='asdf')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "pydantic/main.py", line 164, in __init__
        __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
    pydantic_core._pydantic_core.ValidationError: 1 validation error for DataTemp
    bbb
      Value error, invalid literal for int() with base 16: 'asdf' [type=value_error, input_value='asdf', input_type=str]
        For further information visit https://errors.pydantic.dev/2.5/v/value_error