From c8ad8ac8b59d85531b6019128613b9f6e415e506 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Mon, 17 Jul 2023 15:02:57 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Do=20not=20convert=20`cons?= =?UTF-8?q?tr`=20to=20`Annotated`=20(#97)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bump_pydantic/codemods/con_func.py | 9 +++++++-- tests/integration/cases/con_func.py | 4 ++-- tests/unit/test_con_func.py | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/bump_pydantic/codemods/con_func.py b/bump_pydantic/codemods/con_func.py index a9899b8..5e42033 100644 --- a/bump_pydantic/codemods/con_func.py +++ b/bump_pydantic/codemods/con_func.py @@ -57,6 +57,10 @@ def leave_ann_assign_constr_call(self, original_node: cst.AnnAssign, updated_nod func_name = cast(str, annotation.func.attr.value) # type: ignore type_name = MAP_FUNC_TO_TYPE[func_name] + # TODO: When FastAPI supports Pydantic 2.0.4+, remove the conditional below. + if func_name == "constr": + return updated_node + needed_import = MAP_TYPE_TO_NEEDED_IMPORT.get(type_name) if needed_import is not None: AddImportsVisitor.add_needed_import(context=self.context, **needed_import) # type: ignore[arg-type] @@ -82,12 +86,13 @@ def leave_ann_assign_constr_call(self, original_node: cst.AnnAssign, updated_nod annotation = cst.Annotation(annotation=annotated) # type: ignore[assignment] return updated_node.with_changes(annotation=annotation) + # TODO: When FastAPI supports Pydantic 2.0.4+, remove the comments below. @m.leave(CONSTR_CALL) def leave_constr_call(self, original_node: cst.Call, updated_node: cst.Call) -> cst.Call: self._remove_import(original_node.func) - AddImportsVisitor.add_needed_import(context=self.context, module="pydantic", obj="StringConstraints") + # AddImportsVisitor.add_needed_import(context=self.context, module="pydantic", obj="StringConstraints") return updated_node.with_changes( - func=cst.Name("StringConstraints"), + # func=cst.Name("StringConstraints"), args=[ arg if arg.keyword and arg.keyword.value != "regex" else arg.with_changes(keyword=cst.Name("pattern")) for arg in updated_node.args diff --git a/tests/integration/cases/con_func.py b/tests/integration/cases/con_func.py index eecf276..1bab613 100644 --- a/tests/integration/cases/con_func.py +++ b/tests/integration/cases/con_func.py @@ -23,14 +23,14 @@ expected=File( "con_func.py", content=[ - "from pydantic import Field, StringConstraints, BaseModel", + "from pydantic import Field, BaseModel, constr", "from decimal import Decimal", "from typing import List, Set", "from typing_extensions import Annotated", "", "", "class Potato(BaseModel):", - " a: Annotated[str, StringConstraints(pattern='[a-z]+')]", + " a: constr(pattern='[a-z]+')", " b: Annotated[List[int], Field(min_length=1, max_length=10)]", " c: Annotated[int, Field(gt=0, lt=10)]", " d: Annotated[bytes, Field(min_length=1, max_length=10)]", diff --git a/tests/unit/test_con_func.py b/tests/unit/test_con_func.py index 37647dc..831f20b 100644 --- a/tests/unit/test_con_func.py +++ b/tests/unit/test_con_func.py @@ -1,3 +1,4 @@ +import pytest from libcst.codemod import CodemodTest from bump_pydantic.codemods.con_func import ConFuncCallCommand @@ -8,6 +9,7 @@ class TestFieldCommand(CodemodTest): maxDiff = None + @pytest.mark.xfail(reason="Annotated is not supported yet!") def test_constr_to_annotated(self) -> None: before = """ from pydantic import BaseModel, constr @@ -24,6 +26,7 @@ class Potato(BaseModel): """ self.assertCodemod(before, after) + @pytest.mark.xfail(reason="Annotated is not supported yet!") def test_pydantic_constr_to_annotated(self) -> None: before = """ import pydantic