Bump Pydantic is a tool to help you migrate your code from Pydantic V1 to V2.
[!NOTE]\ If you find bugs, please report them on the issue tracker.
The installation is as simple as:
pip install bump-pydantic
bump-pydantic
is a CLI tool, hence you can use it from your terminal.
It's easy to use. If your project structure is:
repository/
└── my_package/
└── <python source files>
Then you'll want to do:
cd /path/to/repository
bump-pydantic my_package
To check the diff before applying the changes, you can run:
bump-pydantic --diff <path>
To apply the changes, you can run:
bump-pydantic <path>
You can find below the list of rules that are applied by bump-pydantic
.
It's also possible to disable rules by using the --disable
option.
None
to Optional[T]
, Union[T, None]
and Any
fieldsNone
to Optional[T]
fields.The following code will be transformed:
class User(BaseModel):
name: Optional[str]
Into:
class User(BaseModel):
name: Optional[str] = None
Config
class by model_config
attributeConfig
class by model_config = ConfigDict()
.Config
attributes to new model_config
attributes.Extra
enum by string values.The following code will be transformed:
from pydantic import BaseModel, Extra
class User(BaseModel):
name: str
class Config:
extra = Extra.forbid
Into:
from pydantic import ConfigDict, BaseModel
class User(BaseModel):
name: str
model_config = ConfigDict(extra="forbid")
Field
old parameters to new onesField
old parameters to new ones.field: Enum = Field(Enum.VALUE, const=True)
by field: Literal[Enum.VALUE] = Enum.VALUE
.The following code will be transformed:
from typing import List
from pydantic import BaseModel, Field
class User(BaseModel):
name: List[str] = Field(..., min_items=1)
Into:
from typing import List
from pydantic import BaseModel, Field
class User(BaseModel):
name: List[str] = Field(..., min_length=1)
BaseSettings
from pydantic
to pydantic_settings
.Color
and PaymentCardNumber
from pydantic
to pydantic_extra_types
.GenericModel
by BaseModel
GenericModel
by BaseModel
.The following code will be transformed:
from typing import Generic, TypeVar
from pydantic.generics import GenericModel
T = TypeVar('T')
class User(GenericModel, Generic[T]):
name: str
Into:
from typing import Generic, TypeVar
from pydantic import BaseModel
T = TypeVar('T')
class User(BaseModel, Generic[T]):
name: str
__root__
by RootModel
__root__
by RootModel
.The following code will be transformed:
from typing import List
from pydantic import BaseModel
class User(BaseModel):
age: int
name: str
class Users(BaseModel):
__root__ = List[User]
Into:
from typing import List
from pydantic import RootModel, BaseModel
class User(BaseModel):
age: int
name: str
class Users(RootModel[List[User]]):
pass
@validator
by @field_validator
.@root_validator
by @model_validator
.The following code will be transformed:
from pydantic import BaseModel, validator, root_validator
class User(BaseModel):
name: str
@validator('name', pre=True)
def validate_name(cls, v):
return v
@root_validator(pre=True)
def validate_root(cls, values):
return values
Into:
from pydantic import BaseModel, field_validator, model_validator
class User(BaseModel):
name: str
@field_validator('name', mode='before')
def validate_name(cls, v):
return v
@model_validator(mode='before')
def validate_root(cls, values):
return values
con*
functions by Annotated
versionsconstr(*args)
by Annotated[str, StringConstraints(*args)]
.conint(*args)
by Annotated[int, Field(*args)]
.confloat(*args)
by Annotated[float, Field(*args)]
.conbytes(*args)
by Annotated[bytes, Field(*args)]
.condecimal(*args)
by Annotated[Decimal, Field(*args)]
.conset(T, *args)
by Annotated[Set[T], Field(*args)]
.confrozenset(T, *args)
by Annotated[Set[T], Field(*args)]
.conlist(T, *args)
by Annotated[List[T], Field(*args)]
.The following code will be transformed:
from pydantic import BaseModel, constr
class User(BaseModel):
name: constr(min_length=1)
Into:
from pydantic import BaseModel, StringConstraints
from typing_extensions import Annotated
class User(BaseModel):
name: Annotated[str, StringConstraints(min_length=1)]
__get_validators__
as to be replaced by __get_pydantic_core_schema__
.__modify_schema__
as to be replaced by __get_pydantic_json_schema__
.The following code will be transformed:
class SomeThing:
@classmethod
def __get_validators__(cls):
yield from []
@classmethod
def __modify_schema__(cls, field_schema, field):
if field:
field_schema['example'] = "Weird example"
Into:
class SomeThing:
@classmethod
# TODO[pydantic]: We couldn't refactor `__get_validators__`, please create the `__get_pydantic_core_schema__` manually.
# Check https://docs.pydantic.dev/latest/migration/#defining-custom-types for more information.
def __get_validators__(cls):
yield from []
@classmethod
# TODO[pydantic]: We couldn't refactor `__modify_schema__`, please create the `__get_pydantic_json_schema__` manually.
# Check https://docs.pydantic.dev/latest/migration/#defining-custom-types for more information.
def __modify_schema__(cls, field_schema, field):
if field:
field_schema['example'] = "Weird example"
bool
, str
, int
, float
.# TODO[pydantic]: add type annotation
comments to fields that can't be inferred.The following code will be transformed:
from pydantic import BaseModel, Field
class Potato(BaseModel):
name: str
is_sale = True
tags = ["tag1", "tag2"]
price = 10.5
description = "Some item"
active = Field(default=True)
ready = Field(True)
age = Field(10, title="Age")
Into:
from pydantic import BaseModel, Field
class Potato(BaseModel):
name: str
is_sale: bool = True
# TODO[pydantic]: add type annotation
tags = ["tag1", "tag2"]
price: float = 10.5
description: str = "Some item"
active: bool = Field(default=True)
ready: bool = Field(True)
age: int = Field(10, title="Age")
This project is licensed under the terms of the MIT license.