Type Adapter
You may have types that are not BaseModel
s that you want to validate data against.
Or you may want to validate a List[SomeModel]
, or dump it to JSON.
API Documentation
For use cases like this, Pydantic provides TypeAdapter
,
which can be used for type validation, serialization, and JSON schema generation without needing to create a
BaseModel
.
A TypeAdapter
instance exposes some of the functionality from
BaseModel
instance methods for types that do not have such methods
(such as dataclasses, primitive types, and more):
from typing import List
from typing_extensions import TypedDict
from pydantic import TypeAdapter, ValidationError
class User(TypedDict):
name: str
id: int
user_list_adapter = TypeAdapter(List[User])
user_list = user_list_adapter.validate_python([{'name': 'Fred', 'id': '3'}])
print(repr(user_list))
#> [{'name': 'Fred', 'id': 3}]
try:
user_list_adapter.validate_python(
[{'name': 'Fred', 'id': 'wrong', 'other': 'no'}]
)
except ValidationError as e:
print(e)
"""
1 validation error for list[typed-dict]
0.id
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='wrong', input_type=str]
"""
print(repr(user_list_adapter.dump_json(user_list)))
#> b'[{"name":"Fred","id":3}]'
dump_json
returns bytes
TypeAdapter
's dump_json
methods returns a bytes
object, unlike the corresponding method for BaseModel
, model_dump_json
, which returns a str
.
The reason for this discrepancy is that in V1, model dumping returned a str type, so this behavior is retained in V2 for backwards compatibility.
For the BaseModel
case, bytes
are coerced to str
types, but bytes
are often the desired end type.
Hence, for the new TypeAdapter
class in V2, the return type is simply bytes
, which can easily be coerced to a str
type if desired.
Note
Despite some overlap in use cases with RootModel
,
TypeAdapter
should not be used as a type annotation for
specifying fields of a BaseModel
, etc.
Parsing data into a specified type¶
TypeAdapter
can be used to apply the parsing logic to populate Pydantic models
in a more ad-hoc way. This function behaves similarly to
BaseModel.model_validate
,
but works with arbitrary Pydantic-compatible types.
This is especially useful when you want to parse results into a type that is not a direct subclass of
BaseModel
. For example:
from typing import List
from pydantic import BaseModel, TypeAdapter
class Item(BaseModel):
id: int
name: str
# `item_data` could come from an API call, eg., via something like:
# item_data = requests.get('https://my-api.com/items').json()
item_data = [{'id': 1, 'name': 'My Item'}]
items = TypeAdapter(List[Item]).validate_python(item_data)
print(items)
#> [Item(id=1, name='My Item')]
TypeAdapter
is capable of parsing data into any of the types Pydantic can
handle as fields of a BaseModel
.
Performance considerations
When creating an instance of TypeAdapter
, the provided type must be analyzed and converted into a pydantic-core
schema. This comes with some non-trivial overhead, so it is recommended to create a TypeAdapter
for a given type
just once and reuse it in loops or other performance-critical code.