Search code examples
pythonpython-3.xpydanticcustom-type

In Pydantic, how do I apply the flags that I have set in my base model to my custom type?


In my model, I have fields that are mandatory. Users try to avoid filling in these fields by using a dash character (-) as input. To avoid this from happening, I wrote a custom string type in Pydantic. The custom type checks if the input should change to None and checks if it is allowed to be None. The problem that I have is that my custom type does not use the Flags of my BaseModel. Such as anystr_strip_whitespace, to remove the whitespace from the beginning and end of the string. I would like to have the Config from the BaseModel also applied in my custom types. Therefore I hope that anybody can help me with my question about applying the flags of the BaseModel in a custom type.

All help is appreciated

Some example code:

class MyBaseModel(BaseModel):
    class Config:
        anystr_strip_whitespace = True


class EmptyStrToNone(str):
    @classmethod
    def __get_validators__(cls):
        yield cls.change_empty_string_to_none

    @classmethod
    def change_empty_string_to_none(cls, value: str, field: ModelField) -> Optional[str]:
        """If the field is Optional, the input which represents an empty string is set to None. 
        If the field is required, instead of returning None it raises an Exception."""
        is_required = field.required
        lowercase_value = str(value).lower()
        if is_required:
            # Faulty cases that raise an exception
            # E.g. check in a dictionary if it has a string such as "not specified" that represents an empty string.
        elif # Optional condition
            return None

        return str_validator(value)

Solution

  • You can receive the config and use it to decide if the str should be stripped. From Validators - pydantic:

    A few things to note on validators:

    [...]

    • you can also add any subset of the following arguments to the signature (the names must match):

      • [...]
      • config: the model config

    Full example:

    from pydantic import BaseConfig, BaseModel
    from pydantic.validators import str_validator
    
    
    class MyStr(str):
        @classmethod
        def __get_validators__(cls):
            yield str_validator
            yield cls._strip_whitespace
            # Yield more custom validators if needed
    
        @classmethod
        def _strip_whitespace(cls, value: str, config: BaseConfig) -> str:
            if config.anystr_strip_whitespace:
                return value.strip()
            return value
    
    
    class MyBaseModel(BaseModel):
        my_str: MyStr
    
        class Config:
            anystr_strip_whitespace = True
    
    
    print(MyBaseModel(my_str=" a "))
    

    Output:

    my_str='a'