Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use values from list as pydantic validator?

I would like to create pydantic model to validate users form. one of my model values should be validated from a list of names. I succeed to create the model using enum as follow:

from enum import Enum
class Fruit(str, Enum):
    APPLE = 'apple'
    BANANA = 'banana'
    MELON = 'melon'

from pydantic import BaseModel
class UserForm(BaseModel):
    fruit: Fruit
    name: str

Now I would like to switch the enum to a list of values in my code:

fruit = ['apple','banana','melon']

How can I manage to do so?

tnx

like image 882
OrFeldman Avatar asked Dec 27 '20 12:12

OrFeldman


People also ask

How do you validate a Pydantic model?

Add the fields to validate to the @validator decorator directly above the validation function. @validator("name") uses the field value of "name" (e.g. "Peter" ) as input to the validation function. All fields of the class and its parent classes can be added to the @validator decorator.

What is __ root __ In Pydantic?

Pydantic models can be defined with a custom root type by declaring the __root__ field. The root type can be any type supported by pydantic, and is specified by the type hint on the __root__ field.

What is Pydantic validator?

Pydantic is a useful library for validating your data model at runtime period. This would make sure you put the input data with the correct type which prevents you get an unexpected error while in production. Pydantic provides a series of field types that you can use for validating input fields.

What is Pydantic Constr?

constr is a specific type that give validation rules regarding this specific type. You have equivalent for all classic python types.

How can I use a pydantic model for input validation?

We might consider using a pydantic model for the input validation. We can start out with the simplest form of a pydantic model, with field types: Pydantic models are simply classes inheriting from the BaseModel class. We can create an instance of the new class as:

How to use Python dataclasses with pydantic?

Python dataclasses however do not support type or data validation unlike Pydantic. In other to get started with pydantic you would need to install it into your virtual machine. To use pydantic you have to import BaseModel then pass it as an argument in your class. Pydantic checks whether the data given matches the schema described, if it does.

Is the input for ID a valid integer in pydantic?

It will print out the following JSON, which indicates that the input for id is not a valid integer. pydantic provides support for most of the common types from the Python standard library. The full list is as follows:

How to pass values from one model to another in pydantic?

Besides passing values via the constructor, we can also pass values via copy & update or with setters (Pydantic’s models are mutable by default). These, however, have a surprising behavior. Copy & update won’t perform any type of validation. We can see that in the following example: Create a regular model that coerces input types.


Video Answer


4 Answers

You could do this also by means of a list of Literal type. Like so:

import pydantic
from typing import Literal, List

class M(pydantic.BaseModel):
    fruits: List[Literal["apple", "orange"]]

print(M.parse_obj({"fruits":["apple", "orange"]}))  # OK fruits=['apple', 'orange']
print(M.parse_obj({"fruits":["apple", "orange", "potato"]}))  # Error unexpected value potato
like image 109
alex_noname Avatar answered Sep 29 '22 16:09

alex_noname


I am proposing an elegant solution.

from pydantic import BaseModel
from typing import List
from enum import Enum


class Fruit(str, Enum):
    APPLE = 'apple'
    BANANA = 'banana'
    MELON = 'melon'


class UserForm(BaseModel):
    fruits: List[Fruit]
    name: str

And that's it.

  • you don't need to write your own validator
  • just tell pydantic you need a list of Fruit object, and it will do it for you

Check the above code:

put the above code in a file main.py.

Run

python -i main.py
>>> uf = UserForm(fruits=['apple','banana'],name='hello')
>>> uf
UserForm(fruits=[<Fruit.APPLE: 'apple'>, <Fruit.BANANA: 'banana'>], name='hello')


>>> af = UserForm(fruits=['monkey','apple'],name='hello')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 400, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for UserForm
fruits -> 0
  value is not a valid enumeration member; permitted: 'apple', 'banana', 'melon' (type=type_error.enum; enum_values=[<Fruit.APPLE: 'apple'>, <Fruit.BANANA: 'banana'>, <Fruit.MELON: 'melon'>])
>>> 

pydantic will raise an error, as monkey is not in fruits.

like image 32
aahnik Avatar answered Sep 29 '22 16:09

aahnik


You can use validator in the following way:

 from pydantic import BaseModel, ValidationError, validator
 class UserForm(BaseModel):
    fruit: str
    name: str
    @validator('fruit')
    def fruit_must_be_in_fruits(cls,fruit):
      fruits=['apple','banana','melon']
      if fruit not in fruits:
        raise ValueError(f'must be in {fruits}')
      return fruit
 try:
    UserForm(fruit="apple",name="apple")
 except ValidationError as e:
    print(e)

It will raise a validation error if it doesn't match the criteria.

like image 33
Walid Avatar answered Sep 30 '22 16:09

Walid


You can get informations about the enum by its .__members__ dictionary - here you can simply iterate it keys though:

from enum import Enum
class Fruit(str, Enum):
    APPLE = 'apple'
    BANANA = 'banana'
    MELON = 'melon'

# only need __members__ if you need more infos about it

print(Fruit.__members__)

# you do not need the __members__ if you just want the keys
print([name.lower() for name in Fruit])

Output:

# enums __members__ dictionary
{'APPLE': <Fruit.APPLE: 'apple'>, 
 'BANANA': <Fruit.BANANA: 'banana'>, 
 'MELON': <Fruit.MELON: 'melon'>} 

# lower keys
['apple', 'banana', 'melon']
like image 43
Patrick Artner Avatar answered Oct 03 '22 16:10

Patrick Artner