From 6e515ed9b89faa7da4c6af0a7ce6f05f6c6fe1de Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 9 Dec 2024 14:51:06 +0200 Subject: [PATCH] PY-77433 Don't report mutable field defaults in dataclass_transform-based dataclasses Some dataclass implementations, such as Pydantic, allow declaring fields with mutable defaults, deep-copying them under the hood. See https://docs.pydantic.dev/latest/concepts/models/#fields-with-non-hashable-default-values (cherry picked from commit e495621858950976226731dddbb01af4012704fa) IJ-CR-151192 GitOrigin-RevId: 7412272584a4c26e404d3d84e6150f974027eca7 --- .../python/inspections/PyDataclassInspection.kt | 13 +++++++++++-- .../a.py | 14 +++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDataclassInspection.kt b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDataclassInspection.kt index 1072fe8457a2..e6b7f3cd48b5 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDataclassInspection.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/PyDataclassInspection.kt @@ -60,8 +60,17 @@ class PyDataclassInspection : PyInspection() { val dataclassParameters = parseDataclassParameters(node, myTypeEvalContext) if (dataclassParameters != null) { - if (dataclassParameters.type.asPredefinedType == PyDataclassParameters.PredefinedType.STD || - dataclassParameters.type.asPredefinedType == PyDataclassParameters.PredefinedType.DATACLASS_TRANSFORM) { + if (dataclassParameters.type.asPredefinedType == PyDataclassParameters.PredefinedType.DATACLASS_TRANSFORM) { + processDataclassParameters(node, dataclassParameters) + + node.processClassLevelDeclarations { element, _ -> + if (element is PyTargetExpression) { + processFieldFunctionCall(node, dataclassParameters, element) + } + true + } + } + else if (dataclassParameters.type.asPredefinedType == PyDataclassParameters.PredefinedType.STD) { processDataclassParameters(node, dataclassParameters) val postInit = node.findMethodByName(Dataclasses.DUNDER_POST_INIT, false, myTypeEvalContext) diff --git a/python/testData/inspections/PyDataclassInspection/MutableDefaultFieldValueDataclassTransform/a.py b/python/testData/inspections/PyDataclassInspection/MutableDefaultFieldValueDataclassTransform/a.py index 1eb85248a92f..61790553b71f 100644 --- a/python/testData/inspections/PyDataclassInspection/MutableDefaultFieldValueDataclassTransform/a.py +++ b/python/testData/inspections/PyDataclassInspection/MutableDefaultFieldValueDataclassTransform/a.py @@ -6,19 +6,19 @@ from decorator import my_dataclass, field @my_dataclass() class A: - a: list[int] = [] - b: list[int] = list() - c: set[int] = {1} - d: set[int] = set() + a: list[int] = [] + b: list[int] = list() + c: set[int] = {1} + d: set[int] = set() e: tuple[int, ...] = () f: tuple[int, ...] = tuple() g: ClassVar[list[int]] = [] h: ClassVar = [] - i: dict[int, int] = {1: 2} - j: dict[int, int] = dict() + i: dict[int, int] = {1: 2} + j: dict[int, int] = dict() k = [] l = list() - m: dict[int, int] = OrderedDict() + m: dict[int, int] = OrderedDict() n: frozenset[int] = frozenset() o: list = field(default_factory=list) a2: type[list[int]] = list