Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pydantic/bump-pydantic
Convert Pydantic from V1 to V2 ♻
https://github.com/pydantic/bump-pydantic
codemod pydantic python
Last synced: 6 days ago
JSON representation
Convert Pydantic from V1 to V2 ♻
- Host: GitHub
- URL: https://github.com/pydantic/bump-pydantic
- Owner: pydantic
- License: mit
- Created: 2023-04-17T14:01:26.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-07-25T12:21:59.000Z (4 months ago)
- Last Synced: 2024-09-26T19:18:01.761Z (about 2 months ago)
- Topics: codemod, pydantic, python
- Language: Python
- Homepage:
- Size: 151 KB
- Stars: 305
- Watchers: 7
- Forks: 24
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Bump Pydantic ♻️
[![PyPI - Version](https://img.shields.io/pypi/v/bump-pydantic.svg)](https://pypi.org/project/bump-pydantic)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/bump-pydantic.svg)](https://pypi.org/project/bump-pydantic)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](https://github.com/pydantic/bump-pydantic/issues/new).## Table of contents
- [Bump Pydantic ♻️](#bump-pydantic-️)
- [Table of contents](#table-of-contents)
- [Installation](#installation)
- [Usage](#usage)
- [Check diff before applying changes](#check-diff-before-applying-changes)
- [Apply changes](#apply-changes)
- [Rules](#rules)
- [BP001: Add default `None` to `Optional[T]`, `Union[T, None]` and `Any` fields](#bp001-add-default-none-to-optionalt-uniont-none-and-any-fields)
- [BP002: Replace `Config` class by `model_config` attribute](#bp002-replace-config-class-by-model_config-attribute)
- [BP003: Replace `Field` old parameters to new ones](#bp003-replace-field-old-parameters-to-new-ones)
- [BP004: Replace imports](#bp004-replace-imports)
- [BP005: Replace `GenericModel` by `BaseModel`](#bp005-replace-genericmodel-by-basemodel)
- [BP006: Replace `__root__` by `RootModel`](#bp006-replace-__root__-by-rootmodel)
- [BP007: Replace decorators](#bp007-replace-decorators)
- [BP008: Replace `con*` functions by `Annotated` versions](#bp008-replace-con-functions-by-annotated-versions)
- [BP009: Mark pydantic "protocol" functions in custom types with proper TODOs](bp009-mark-pydantic-protocol-functions-in-custom-types-with-proper-todos)- [License](#license)
---
## Installation
The installation is as simple as:
```bash
pip install bump-pydantic
```---
## Usage
`bump-pydantic` is a CLI tool, hence you can use it from your terminal.
It's easy to use. If your project structure is:
```bash
repository/
└── my_package/
└──
```Then you'll want to do:
```bash
cd /path/to/repository
bump-pydantic my_package
```### Check diff before applying changes
To check the diff before applying the changes, you can run:
```bash
bump-pydantic --diff
```### Apply changes
To apply the changes, you can run:
```bash
bump-pydantic
```## Rules
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.
### BP001: Add default `None` to `Optional[T]`, `Union[T, None]` and `Any` fields
- ✅ Add default `None` to `Optional[T]` fields.
The following code will be transformed:
```py
class User(BaseModel):
name: Optional[str]
```Into:
```py
class User(BaseModel):
name: Optional[str] = None
```### BP002: Replace `Config` class by `model_config` attribute
- ✅ Replace `Config` class by `model_config = ConfigDict()`.
- ✅ Rename old `Config` attributes to new `model_config` attributes.
- ✅ Add a TODO comment in case the transformation can't be done automatically.
- ✅ Replace `Extra` enum by string values.The following code will be transformed:
```py
from pydantic import BaseModel, Extraclass User(BaseModel):
name: strclass Config:
extra = Extra.forbid
```Into:
```py
from pydantic import ConfigDict, BaseModelclass User(BaseModel):
name: strmodel_config = ConfigDict(extra="forbid")
```### BP003: Replace `Field` old parameters to new ones
- ✅ Replace `Field` old parameters to new ones.
- ✅ Replace `field: Enum = Field(Enum.VALUE, const=True)` by `field: Literal[Enum.VALUE] = Enum.VALUE`.The following code will be transformed:
```py
from typing import Listfrom pydantic import BaseModel, Field
class User(BaseModel):
name: List[str] = Field(..., min_items=1)
```Into:
```py
from typing import Listfrom pydantic import BaseModel, Field
class User(BaseModel):
name: List[str] = Field(..., min_length=1)
```### BP004: Replace imports
- ✅ Replace `BaseSettings` from `pydantic` to `pydantic_settings`.
- ✅ Replace `Color` and `PaymentCardNumber` from `pydantic` to `pydantic_extra_types`.### BP005: Replace `GenericModel` by `BaseModel`
- ✅ Replace `GenericModel` by `BaseModel`.
The following code will be transformed:
```py
from typing import Generic, TypeVar
from pydantic.generics import GenericModelT = TypeVar('T')
class User(GenericModel, Generic[T]):
name: str
```Into:
```py
from typing import Generic, TypeVar
from pydantic import BaseModelT = TypeVar('T')
class User(BaseModel, Generic[T]):
name: str
```### BP006: Replace `__root__` by `RootModel`
- ✅ Replace `__root__` by `RootModel`.
The following code will be transformed:
```py
from typing import Listfrom pydantic import BaseModel
class User(BaseModel):
age: int
name: strclass Users(BaseModel):
__root__ = List[User]
```Into:
```py
from typing import Listfrom pydantic import RootModel, BaseModel
class User(BaseModel):
age: int
name: strclass Users(RootModel[List[User]]):
pass
```### BP007: Replace decorators
- ✅ Replace `@validator` by `@field_validator`.
- ✅ Replace `@root_validator` by `@model_validator`.The following code will be transformed:
```py
from pydantic import BaseModel, validator, root_validatorclass 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:
```py
from pydantic import BaseModel, field_validator, model_validatorclass 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
```### BP008: Replace `con*` functions by `Annotated` versions
- ✅ Replace `constr(*args)` by `Annotated[str, StringConstraints(*args)]`.
- ✅ Replace `conint(*args)` by `Annotated[int, Field(*args)]`.
- ✅ Replace `confloat(*args)` by `Annotated[float, Field(*args)]`.
- ✅ Replace `conbytes(*args)` by `Annotated[bytes, Field(*args)]`.
- ✅ Replace `condecimal(*args)` by `Annotated[Decimal, Field(*args)]`.
- ✅ Replace `conset(T, *args)` by `Annotated[Set[T], Field(*args)]`.
- ✅ Replace `confrozenset(T, *args)` by `Annotated[Set[T], Field(*args)]`.
- ✅ Replace `conlist(T, *args)` by `Annotated[List[T], Field(*args)]`.The following code will be transformed:
```py
from pydantic import BaseModel, constrclass User(BaseModel):
name: constr(min_length=1)
```Into:
```py
from pydantic import BaseModel, StringConstraints
from typing_extensions import Annotatedclass User(BaseModel):
name: Annotated[str, StringConstraints(min_length=1)]
```### BP009: Mark Pydantic "protocol" functions in custom types with proper TODOs
- ✅ 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:
```py
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:
```py
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"
```### BP010: Add type annotations or TODO comments to fields without them
- ✅ 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 annotation` comments to fields that can't be inferred.The following code will be transformed:
```py
from pydantic import BaseModel, Fieldclass 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:
```py
from pydantic import BaseModel, Fieldclass 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")
```---
## License
This project is licensed under the terms of the MIT license.