Pydantic V1 has long been EOL, and most users have migrated to Pydatnic V2.
We're therefore archiving this repo. Please get in touch if you haven any questions.
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.
- Bump Pydantic ♻️
-
- BP001: Add default
NonetoOptional[T],Union[T, None]andAnyfields - BP002: Replace
Configclass bymodel_configattribute - BP003: Replace
Fieldold parameters to new ones - BP004: Replace imports
- BP005: Replace
GenericModelbyBaseModel - BP006: Replace
__root__byRootModel - BP007: Replace decorators
- BP008: Replace
con*functions byAnnotatedversions - BP009: Mark pydantic "protocol" functions in custom types with proper TODOs
- BP001: Add default
The installation is as simple as:
pip install bump-pydanticbump-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_packageTo 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.
- ✅ Add default
NonetoOptional[T]fields.
The following code will be transformed:
class User(BaseModel):
name: Optional[str]Into:
class User(BaseModel):
name: Optional[str] = None- ✅ Replace
Configclass bymodel_config = ConfigDict(). - ✅ Rename old
Configattributes to newmodel_configattributes. - ✅ Add a TODO comment in case the transformation can't be done automatically.
- ✅ Replace
Extraenum by string values.
The following code will be transformed:
from pydantic import BaseModel, Extra
class User(BaseModel):
name: str
class Config:
extra = Extra.forbidInto:
from pydantic import ConfigDict, BaseModel
class User(BaseModel):
name: str
model_config = ConfigDict(extra="forbid")- ✅ Replace
Fieldold parameters to new ones. - ✅ Replace
field: Enum = Field(Enum.VALUE, const=True)byfield: 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)- ✅ Replace
BaseSettingsfrompydantictopydantic_settings. - ✅ Replace
ColorandPaymentCardNumberfrompydantictopydantic_extra_types.
- ✅ Replace
GenericModelbyBaseModel.
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: strInto:
from typing import Generic, TypeVar
from pydantic import BaseModel
T = TypeVar('T')
class User(BaseModel, Generic[T]):
name: str- ✅ Replace
__root__byRootModel.
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- ✅ Replace
@validatorby@field_validator. - ✅ Replace
@root_validatorby@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 valuesInto:
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- ✅ Replace
constr(*args)byAnnotated[str, StringConstraints(*args)]. - ✅ Replace
conint(*args)byAnnotated[int, Field(*args)]. - ✅ Replace
confloat(*args)byAnnotated[float, Field(*args)]. - ✅ Replace
conbytes(*args)byAnnotated[bytes, Field(*args)]. - ✅ Replace
condecimal(*args)byAnnotated[Decimal, Field(*args)]. - ✅ Replace
conset(T, *args)byAnnotated[Set[T], Field(*args)]. - ✅ Replace
confrozenset(T, *args)byAnnotated[Set[T], Field(*args)]. - ✅ Replace
conlist(T, *args)byAnnotated[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)]- ✅ Mark
__get_validators__as to be replaced by__get_pydantic_core_schema__. - ✅ Mark
__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"- ✅ Add type annotations based on the default value for a few types that can be inferred, like
bool,str,int,float. - ✅ Add
# TODO[pydantic]: add type annotationcomments 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.