ryche
ryche

Reputation: 2094

How to validate complex list types in pydantic?

Why does pydantic not validate an argument that is the list of Foo objects but throws ValidationError when the argument is a list of primitive types?

Can I enforce the validation of complex types?

Validation doesn't work:

from typing import List
from pydantic import BaseModel


class Foo(BaseModel):
    kind: str = "foo"

class Bar(BaseModel):
    kind: str = "bar"

class Spam(BaseModel):
    foos: List[Foo]

spam = Spam(foos=[Bar()])
print(spam.dict())

>>> {'foos': [{'kind': 'bar'}]}

Validation works:

class Spam(BaseModel):
    foos: List[int]


spam = Spam(foos=[Bar()])
print(spam.dict())

pydantic.error_wrappers.ValidationError: 1 validation error for Spam
foos -> 0
  value is not a valid integer (type=type_error.integer)

Upvotes: 2

Views: 11433

Answers (2)

alex_noname
alex_noname

Reputation: 32163

When working with pydantic, it should be remembered that:

pydantic is primarily a parsing library, not a validation library. Validation is a means to an end: building a model which conforms to the types and constraints provided.

In other words, pydantic guarantees the types and constraints of the output model, not the input data.

For additional validation of incoming data, a tool is provided - validators. For example:

class Spam(BaseModel):
    foos: List[Foo]

    @validator('foos', pre=True, each_item=True)
    def check_squares(cls, v):
        assert isinstance(v, Foo), "Foo is only allowed"
        return v

Upvotes: 5

pjk
pjk

Reputation: 556

You can't validate the value like kind: str = "foo". You have to use Field in order to validate values of a variable.

Try:

from typing import List

import pydantic
from pydantic import BaseModel, Field


class Foo(BaseModel):
   kind: str = Field(const="foo", default="foo")

class Bar(BaseModel):
    kind: str = Field(const="bar", default="bar")

class Spam(BaseModel):
    foos: List[Foo]

try:
    Spam.parse_obj({'foos': [{'kind': 'bar'}]})
except pydantic.ValidationError as e:
    print(e)

Upvotes: 0

Related Questions