Implementation:Anthropics Anthropic sdk python Pydantic Compat
| Knowledge Sources | |
|---|---|
| Domains | SDK_Architecture, Compatibility |
| Last Updated | 2026-02-15 12:00 GMT |
Overview
The _compat.py module provides a compatibility layer that abstracts the differences between Pydantic v1 and Pydantic v2/v3, allowing the Anthropic SDK to work seamlessly with either version.
Description
Pydantic underwent a major rewrite between v1 and v2, renaming and restructuring many core APIs. This module detects the installed Pydantic version at import time using the PYDANTIC_V1 flag (set by checking pydantic.VERSION.startswith("1.")) and provides unified wrapper functions that delegate to the correct version-specific API.
The module covers several categories of compatibility: type introspection functions (get_args, get_origin, is_union, is_literal_type, is_typeddict), parsing functions (parse_date, parse_datetime), model operations (model_dump, model_json, model_parse, model_parse_json, model_copy, parse_obj), field inspection (field_is_required, field_get_default, field_outer_type), model metadata (get_model_config, get_model_fields), generic model base classes, and cached property types. For v1, functions delegate to Pydantic's legacy APIs (e.g., model.parse_obj(), model.dict()); for v2+, they use the modern equivalents (e.g., model.model_validate(), model.model_dump()).
The module also provides a GenericModel base class that inherits from pydantic.generics.GenericModel in v1 and directly from pydantic.BaseModel in v2 (where the distinction is no longer required), along with a ConfigDict re-export and typed_cached_property for settable cached properties.
Usage
This module is used internally throughout the SDK whenever Pydantic model operations are needed. SDK developers should import compat wrappers from this module instead of calling Pydantic APIs directly to maintain cross-version support.
Code Reference
Source Location
- Repository: Anthropic SDK Python
- File:
src/anthropic/_compat.py
Signature
PYDANTIC_V1: bool # True if pydantic.VERSION starts with "1."
def parse_obj(model: type[_ModelT], value: object) -> _ModelT: ...
def field_is_required(field: FieldInfo) -> bool: ...
def field_get_default(field: FieldInfo) -> Any: ...
def field_outer_type(field: FieldInfo) -> Any: ...
def get_model_config(model: type[pydantic.BaseModel]) -> Any: ...
def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: ...
def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: ...
def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: ...
def model_parse_json(model: type[_ModelT], data: str | bytes) -> _ModelT: ...
def model_dump(
model: pydantic.BaseModel,
*,
exclude: IncEx | None = None,
exclude_unset: bool = False,
exclude_defaults: bool = False,
warnings: bool = True,
mode: Literal["json", "python"] = "python",
by_alias: bool | None = None,
) -> dict[str, Any]: ...
def model_parse(model: type[_ModelT], data: Any) -> _ModelT: ...
class GenericModel(pydantic.BaseModel): ...
# Re-exported type introspection (sourced from pydantic v1 or _utils for v2):
def get_args(t: type[Any]) -> tuple[Any, ...]: ...
def is_union(tp: type[Any] | None) -> bool: ...
def get_origin(t: type[Any]) -> type[Any] | None: ...
def is_literal_type(type_: type[Any]) -> bool: ...
def is_typeddict(type_: type[Any]) -> bool: ...
def parse_date(value: date | StrBytesIntFloat) -> date: ...
def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: ...
Import
# Internal SDK usage only
from anthropic._compat import (
PYDANTIC_V1,
model_dump,
model_json,
model_parse,
model_copy,
parse_obj,
get_model_fields,
field_is_required,
GenericModel,
ConfigDict,
)
I/O Contract
Version Detection
| Flag | Type | Value |
|---|---|---|
PYDANTIC_V1 |
bool |
True when pydantic.VERSION starts with "1.", False otherwise
|
Model Operation Mapping
| Compat Function | Pydantic v1 Delegation | Pydantic v2+ Delegation |
|---|---|---|
parse_obj(model, value) |
model.parse_obj(value) |
model.model_validate(value)
|
model_dump(model, ...) |
model.dict(...) |
model.model_dump(...)
|
model_json(model, indent) |
model.json(indent=indent) |
model.model_dump_json(indent=indent)
|
model_parse_json(model, data) |
model.parse_raw(data) |
model.model_validate_json(data)
|
model_parse(model, data) |
model.parse_obj(data) |
model.model_validate(data)
|
model_copy(model, deep) |
model.copy(deep=deep) |
model.model_copy(deep=deep)
|
get_model_fields(model) |
model.__fields__ |
model.model_fields
|
get_model_config(model) |
model.__config__ |
model.model_config
|
field_is_required(field) |
field.required |
field.is_required()
|
field_get_default(field) |
field.get_default() |
field.get_default() (maps PydanticUndefined to None)
|
field_outer_type(field) |
field.outer_type_ |
field.annotation
|
GenericModel Base Class
| Pydantic Version | GenericModel Inherits From |
|---|---|
| v1 | pydantic.generics.GenericModel + pydantic.BaseModel
|
| v2+ | pydantic.BaseModel (generic distinction no longer needed)
|
Usage Examples
from anthropic._compat import model_dump, model_parse, PYDANTIC_V1
import pydantic
class MyModel(pydantic.BaseModel):
name: str
value: int
# Parse data into a model (works with both v1 and v2)
instance = model_parse(MyModel, {"name": "test", "value": 42})
# Dump model to dict (works with both v1 and v2)
data = model_dump(instance, exclude_unset=True)
# -> {"name": "test", "value": 42}
# Check which version is in use
if PYDANTIC_V1:
print("Using Pydantic v1 compatibility layer")
else:
print("Using Pydantic v2+ native APIs")
Related Pages
Related Implementations
- Implementation:Anthropics_Anthropic_sdk_python_Core_Types -- Type aliases used by compat functions (
IncEx,StrBytesIntFloat) - Implementation:Anthropics_Anthropic_sdk_python_Package_Init -- Top-level package that depends on compat layer