diff --git a/src/com/koxudaxi/pydantic/PydanticInspection.kt b/src/com/koxudaxi/pydantic/PydanticInspection.kt index 177ba35c..6384120d 100644 --- a/src/com/koxudaxi/pydantic/PydanticInspection.kt +++ b/src/com/koxudaxi/pydantic/PydanticInspection.kt @@ -94,6 +94,31 @@ class PydanticInspection : PyInspection() { inspectDefaultFactory(node) } + override fun visitPyReferenceExpression(node: PyReferenceExpression) { + if(!pydanticCacheService.isV2) return + val pyFunction = node.reference.resolve() as? PyFunction ?: return + + val qualifiedName = (pyFunction as? PyQualifiedNameOwner)?.qualifiedName ?: return + if (!qualifiedName.startsWith("pydantic.")) return + if (!isPydanticDeprecatedSince20(pyFunction)) return + registerProblem( + node.nameElement?.psi ?: node, + "" + + "Pydantic V2 Migration Guide: " + + "" + + "https://docs.pydantic.dev/dev-v2/migration/" + + "" + + "", + ProblemHighlightType.LIKE_DEPRECATED + ) + + } + private fun isPydanticDeprecatedSince20(pyFunction: PyFunction): Boolean = + pyFunction.statementList.statements.filterIsInstance() + .mapNotNull { (it.expression as? PyCallExpression)?.getArgument(1, PyReferenceExpression::class.java) } + .any { (it.reference.resolve() as? PyTargetExpression)?.findAssignedValue()?.name == "PydanticDeprecatedSince20" } + + private fun inspectCustomRootFieldV2(pyClass: PyClass) { if (getRootField(pyClass) == null) return if (!isPydanticModel(pyClass, false, myTypeEvalContext)) return diff --git a/testData/inspectionv2/validators.py b/testData/inspectionv2/validators.py new file mode 100644 index 00000000..41e01619 --- /dev/null +++ b/testData/inspectionv2/validators.py @@ -0,0 +1,26 @@ +from pydantic import BaseModel, validator, root_validator + +def check(func): + def inner(): + func() + return inner + +class A(BaseModel): + a: str + + + @validator('a') + def validate_a(cls): + pass + + @root_validator() + def validate_root(cls): + pass + + + def dummy(self): + pass + + @check + def task(self): + pass \ No newline at end of file diff --git a/testData/mock/pydanticv2/__init__.py b/testData/mock/pydanticv2/__init__.py index 27cd21f2..5d87cbbc 100644 --- a/testData/mock/pydanticv2/__init__.py +++ b/testData/mock/pydanticv2/__init__.py @@ -21,5 +21,6 @@ from .types import * from .config import ConfigDict from .version import VERSION +from .deprecated import validator, root_validator __version__ = VERSION diff --git a/testData/mock/pydanticv2/deprecated/__init__.py b/testData/mock/pydanticv2/deprecated/__init__.py new file mode 100644 index 00000000..b40d593b --- /dev/null +++ b/testData/mock/pydanticv2/deprecated/__init__.py @@ -0,0 +1 @@ +from class_validators import validator, root_validator \ No newline at end of file diff --git a/testData/mock/pydanticv2/deprecated/class_validators.py b/testData/mock/pydanticv2/deprecated/class_validators.py new file mode 100644 index 00000000..946b8341 --- /dev/null +++ b/testData/mock/pydanticv2/deprecated/class_validators.py @@ -0,0 +1,39 @@ +from warnings import warn + +from ..warnings import PydanticDeprecatedSince20 + +DeprecationWarning = PydanticDeprecatedSince20 + + +def validator( + __field: str, + *fields: str, + pre: bool = False, + each_item: bool = False, + always: bool = False, + check_fields: bool | None = None, + allow_reuse: bool = False, +) -> Callable[[_V1ValidatorType], _V1ValidatorType]: + + warn( + 'Pydantic V1 style `@validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@field_validator` validators,' + ' see the migration guide for more details', + DeprecationWarning, + stacklevel=2, + ) + + +def root_validator( + *__args, + pre: bool = False, + skip_on_failure: bool = False, + allow_reuse: bool = False, +) -> Any: + warn( + 'Pydantic V1 style `@root_validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@model_validator` validators,' + ' see the migration guide for more details', + DeprecationWarning, + stacklevel=2, + ) diff --git a/testSrc/com/koxudaxi/pydantic/PydanticInspectionV2Test.kt b/testSrc/com/koxudaxi/pydantic/PydanticInspectionV2Test.kt index a5b286ac..4db438dc 100644 --- a/testSrc/com/koxudaxi/pydantic/PydanticInspectionV2Test.kt +++ b/testSrc/com/koxudaxi/pydantic/PydanticInspectionV2Test.kt @@ -25,4 +25,8 @@ open class PydanticInspectionV2Test : PydanticInspectionBase(version = "v2") { fun testReadOnlyPropertyFrozenConfigDict() { doTest() } + + fun testValidators() { + doTest() + } }