From 92e2aadcc1a0fc2d2405b94997a9356f810b9376 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Sun, 2 Oct 2016 19:21:27 +0300 Subject: [PATCH] Move PyPropertyAccessInspection functionality which relates to __slots__ to PyDunderSlotsInspection --- .../inspections/PyDunderSlotsInspection.kt | 63 +++++ .../PyPropertyAccessInspection.java | 59 ----- .../classAttrAssignmentAndInheritedSlots.py | 0 ...ssAttrAssignmentAndOwnAndInheritedSlots.py | 0 ...tAndOwnAndInheritedWithAttrAndDictSlots.py | 0 ...signmentAndOwnAndInheritedWithAttrSlots.py | 0 ...signmentAndOwnAndInheritedWithDictSlots.py | 0 ...AttrAssignmentAndOwnSlotsAndEmptyParent.py | 0 ...nmentAndOwnWithAttrAndInheritedSlotsPy2.py | 0 ...nmentAndOwnWithAttrAndInheritedSlotsPy3.py | 13 ++ ...signmentAndOwnWithDictAndInheritedSlots.py | 0 ...AndOwnWithDictAndInheritedWithAttrSlots.py | 0 .../classAttrAssignmentAndSlots.py | 0 .../classAttrAssignmentAndSlotsWithAttrPy2.py | 0 .../classAttrAssignmentAndSlotsWithAttrPy3.py | 10 + .../classAttrAssignmentAndSlotsWithDict.py | 0 ...tedClassAttrAssignmentAndInheritedSlots.py | 0 ...ssAttrAssignmentAndOwnAndInheritedSlots.py | 0 ...OwnAndInheritedWithAttrAndDictSlotsPy2.py} | 4 - ...dOwnAndInheritedWithAttrAndDictSlotsPy3.py | 13 ++ ...nmentAndOwnAndInheritedWithAttrSlotsPy2.py | 0 ...nmentAndOwnAndInheritedWithAttrSlotsPy3.py | 4 +- ...signmentAndOwnAndInheritedWithDictSlots.py | 0 ...inheritedClassAttrAssignmentAndOwnSlots.py | 0 ...tAndOwnWithAttrAndDictAndInheritedSlots.py | 0 ...signmentAndOwnWithAttrAndInheritedSlots.py | 0 ...AndOwnWithAttrAndInheritedWithDictSlots.py | 0 ...signmentAndOwnWithDictAndInheritedSlots.py | 0 ...wnWithDictAndInheritedWithAttrSlotsPy2.py} | 4 - ...OwnWithDictAndInheritedWithAttrSlotsPy3.py | 13 ++ .../writeToAttrInSlots.py | 0 ...nmentAndOwnWithAttrAndInheritedSlotsPy3.py | 15 -- .../classAttrAssignmentAndSlotsWithAttrPy3.py | 12 - .../PyDunderSlotsInspectionTest.java | 217 ++++++++++++++++++ .../PyPropertyAccessInspectionTest.java | 190 +-------------- 35 files changed, 335 insertions(+), 282 deletions(-) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnAndInheritedWithAttrSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnAndInheritedWithDictSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnSlotsAndEmptyParent.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy2.py (100%) create mode 100644 python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnWithDictAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndSlotsWithAttrPy2.py (100%) create mode 100644 python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithAttrPy3.py rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/classAttrAssignmentAndSlotsWithDict.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py => PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy2.py} (58%) create mode 100644 python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy3.py rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy2.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3.py (50%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnAndInheritedWithDictSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnWithAttrAndDictAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedWithDictSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedSlots.py (100%) rename python/testData/inspections/{PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py => PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy2.py} (58%) create mode 100644 python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy3.py rename python/testData/inspections/{PyPropertyAccessInspection => PyDunderSlotsInspectionTest}/writeToAttrInSlots.py (100%) delete mode 100644 python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py delete mode 100644 python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithAttrPy3.py create mode 100644 python/testSrc/com/jetbrains/python/inspections/PyDunderSlotsInspectionTest.java diff --git a/python/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt b/python/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt index 3eaad119ed3b..0bffce77a8d2 100644 --- a/python/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt +++ b/python/src/com/jetbrains/python/inspections/PyDunderSlotsInspection.kt @@ -21,6 +21,8 @@ import com.intellij.psi.PsiElementVisitor import com.jetbrains.python.PyNames import com.jetbrains.python.psi.* import com.jetbrains.python.psi.impl.PyPsiUtils +import com.jetbrains.python.psi.resolve.PyResolveContext +import com.jetbrains.python.psi.types.PyClassType class PyDunderSlotsInspection : PyInspection() { @@ -31,6 +33,8 @@ class PyDunderSlotsInspection : PyInspection() { private class Visitor(holder: ProblemsHolder, session: LocalInspectionToolSession) : PyInspectionVisitor(holder, session) { override fun visitPyClass(node: PyClass?) { + super.visitPyClass(node) + if (node != null && LanguageLevel.forElement(node).isAtLeast(LanguageLevel.PYTHON30)) { val slots = findSlotsValue(node) @@ -47,6 +51,14 @@ class PyDunderSlotsInspection : PyInspection() { } } + override fun visitPyTargetExpression(node: PyTargetExpression?) { + super.visitPyTargetExpression(node) + + if (node != null) { + checkAttributeExpression(node) + } + } + private fun findSlotsValue(pyClass: PyClass): PyExpression? { val target = pyClass.findClassAttribute(PyNames.SLOTS, false, myTypeEvalContext) as? PyTargetExpression val value = target?.findAssignedValue() @@ -61,6 +73,57 @@ class PyDunderSlotsInspection : PyInspection() { registerProblem(slot, "'$name' in __slots__ conflicts with class variable") } } + + private fun checkAttributeExpression(target: PyTargetExpression) { + val targetName = target.name + val qualifier = target.qualifier + + if (targetName == null || qualifier == null) { + return + } + + val qualifierType = myTypeEvalContext.getType(qualifier) + if (qualifierType is PyClassType && !qualifierType.isDefinition) { + val reference = target.getReference(PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext)) + val qualifierClass = qualifierType.pyClass + + val classWithReadOnlyAttr = PyUtil + .multiResolveTopPriority(reference) + .asSequence() + .filterIsInstance() + .map { declaration -> declaration.containingClass } + .filterNotNull() + .find { declaringClass -> !attributeIsWritable(qualifierClass, declaringClass, targetName) } + + if (classWithReadOnlyAttr != null) { + registerProblem(target, "'${qualifierClass.name}' object attribute '$targetName' is read-only") + } + } + } + + private fun attributeIsWritable(qualifierClass: PyClass, declaringClass: PyClass, targetName: String): Boolean { + return attributeIsWritableInClass(qualifierClass, declaringClass, targetName) || + qualifierClass + .getAncestorClasses(myTypeEvalContext) + .asSequence() + .filter { ancestorClass -> !PyUtil.isObjectClass(ancestorClass) } + .any { ancestorClass -> attributeIsWritableInClass(ancestorClass, declaringClass, targetName) } + } + + private fun attributeIsWritableInClass(cls: PyClass, declaringClass: PyClass, targetName: String): Boolean { + val ownSlots = cls.ownSlots + + if (ownSlots == null || ownSlots.contains(PyNames.DICT)) { + return true + } + + if (!cls.equals(declaringClass) || !ownSlots.contains(targetName)) { + return false + } + + return LanguageLevel.forElement(declaringClass).isAtLeast(LanguageLevel.PYTHON30) || + declaringClass.findClassAttribute(targetName, false, myTypeEvalContext) == null + } } } diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java index cde7b2df7d6a..32df780cae0a 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyAccessInspection.java @@ -22,18 +22,14 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.util.containers.HashMap; import com.jetbrains.python.PyBundle; -import com.jetbrains.python.PyNames; import com.jetbrains.python.inspections.quickfix.PyCreatePropertyQuickFix; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.types.PyClassType; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.toolbox.Maybe; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; -import java.util.List; - /** * Checks that properties are accessed correctly. * User: dcheryasov @@ -75,7 +71,6 @@ public class PyPropertyAccessInspection extends PyInspection { public void visitPyTargetExpression(PyTargetExpression node) { super.visitPyTargetExpression(node); checkPropertyExpression(node); - checkAttributeExpression(node); } private void checkPropertyExpression(PyQualifiedExpression node) { @@ -126,59 +121,5 @@ public class PyPropertyAccessInspection extends PyInspection { registerProblem(node, message, new PyCreatePropertyQuickFix(dir)); } } - - private void checkAttributeExpression(@NotNull PyTargetExpression target) { - final String targetName = target.getName(); - final PyExpression qualifier = target.getQualifier(); - - if (targetName == null || qualifier == null) { - return; - } - - final PyType qualifierType = myTypeEvalContext.getType(qualifier); - - if (qualifierType instanceof PyClassType) { - final PyClassType qualifierClassType = (PyClassType)qualifierType; - - if (!qualifierClassType.isDefinition()) { - final PyClass qualifierClass = qualifierClassType.getPyClass(); - - PyUtil - .multiResolveTopPriority(target.getReference(PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext))) - .stream() - .filter(PyTargetExpression.class::isInstance) - .map(declaration -> ((PyTargetExpression)declaration).getContainingClass()) - .filter(declaringClass -> declaringClass != null && !attributeIsWritable(qualifierClass, declaringClass, targetName)) - .findFirst() - .ifPresent( - cls -> registerProblem(target, String.format("'%s' object attribute '%s' is read-only", qualifierClass.getName(), targetName)) - ); - } - } - } - - private boolean attributeIsWritable(@NotNull PyClass qualifierClass, @NotNull PyClass declaringClass, @NotNull String targetName) { - return attributeIsWritableInClass(qualifierClass, declaringClass, targetName) || - qualifierClass - .getAncestorClasses(myTypeEvalContext) - .stream() - .filter(ancestorClass -> !PyUtil.isObjectClass(ancestorClass)) - .anyMatch(ancestorClass -> attributeIsWritableInClass(ancestorClass, declaringClass, targetName)); - } - - private boolean attributeIsWritableInClass(@NotNull PyClass cls, @NotNull PyClass declaringClass, @NotNull String targetName) { - final List ownSlots = cls.getOwnSlots(); - - if (ownSlots == null || ownSlots.contains(PyNames.DICT)) { - return true; - } - - if (!cls.equals(declaringClass) || !ownSlots.contains(targetName)) { - return false; - } - - return LanguageLevel.forElement(declaringClass).isAtLeast(LanguageLevel.PYTHON30) || - declaringClass.findClassAttribute(targetName, false, myTypeEvalContext) == null; - } } } diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedWithAttrSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedWithAttrSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedWithAttrSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedWithAttrSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedWithDictSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedWithDictSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnAndInheritedWithDictSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnAndInheritedWithDictSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnSlotsAndEmptyParent.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnSlotsAndEmptyParent.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnSlotsAndEmptyParent.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnSlotsAndEmptyParent.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy2.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy2.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy2.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy2.py diff --git a/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py new file mode 100644 index 000000000000..9bf8cbb3654c --- /dev/null +++ b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py @@ -0,0 +1,13 @@ +class B(object): + __slots__ = ['f', 'b'] + +class C(B): + attr = 'baz' + __slots__ = ['attr', 'bar'] + +C.attr = 'spam' +print(C.attr) + +c = C() +c.attr = 'spam' +print(c.attr) \ No newline at end of file diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithDictAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithDictAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithDictAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithDictAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithAttrPy2.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithAttrPy2.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithAttrPy2.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithAttrPy2.py diff --git a/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithAttrPy3.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithAttrPy3.py new file mode 100644 index 000000000000..3db9a4206fe4 --- /dev/null +++ b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithAttrPy3.py @@ -0,0 +1,10 @@ +class Foo(object): + attr = 'baz' + __slots__ = ['attr', 'bar'] + +Foo.attr = 'spam' +print(Foo.attr) + +foo = Foo() +foo.attr = 'spam' +print(foo.attr) \ No newline at end of file diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithDict.py b/python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithDict.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithDict.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/classAttrAssignmentAndSlotsWithDict.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy2.py similarity index 58% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy2.py index ecc7cafebcb4..3fe78eefccbf 100644 --- a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots.py +++ b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy2.py @@ -1,7 +1,3 @@ -# Py3: OK -# Py2: -# ValueError: 'attr' in __slots__ conflicts with class variable -# This is not responsibility of current inspection class B(object): attr = 'baz' __slots__ = ['f', 'attr', '__dict__'] diff --git a/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy3.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy3.py new file mode 100644 index 000000000000..6b95f8270dca --- /dev/null +++ b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy3.py @@ -0,0 +1,13 @@ +class B(object): + attr = 'baz' + __slots__ = ['f', 'attr', '__dict__'] + +class C(B): + __slots__ = ['foo', 'bar'] + +C.attr = 'spam' +print(C.attr) + +c = C() +c.attr = 'spam' +print(c.attr) \ No newline at end of file diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy2.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy2.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy2.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy2.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3.py similarity index 50% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3.py index 4ae21acb1d24..301371fbf75e 100644 --- a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3.py +++ b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3.py @@ -1,8 +1,6 @@ -# ValueError: 'attr' in __slots__ conflicts with class variable -# This is not responsibility of current inspection class B(object): attr = 'baz' - __slots__ = ['attr', 'b'] + __slots__ = ['attr', 'b'] class C(B): __slots__ = ['foo', 'bar'] diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithDictSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithDictSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnAndInheritedWithDictSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnAndInheritedWithDictSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithAttrAndDictAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithAttrAndDictAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithAttrAndDictAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithAttrAndDictAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedWithDictSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedWithDictSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedWithDictSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithAttrAndInheritedWithDictSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy2.py similarity index 58% rename from python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy2.py index b8ed2806bc6a..2b3123af86f4 100644 --- a/python/testData/inspections/PyPropertyAccessInspection/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots.py +++ b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy2.py @@ -1,7 +1,3 @@ -# Py2: OK -# Py3: -# ValueError: 'attr' in __slots__ conflicts with class variable -# This is not responsibility of current inspection class B(object): attr = 'baz' __slots__ = ['f', 'attr'] diff --git a/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy3.py b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy3.py new file mode 100644 index 000000000000..bea42dcf3e5e --- /dev/null +++ b/python/testData/inspections/PyDunderSlotsInspectionTest/inheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy3.py @@ -0,0 +1,13 @@ +class B(object): + attr = 'baz' + __slots__ = ['f', 'attr'] + +class C(B): + __slots__ = ['foo', 'bar', '__dict__'] + +C.attr = 'spam' +print(C.attr) + +c = C() +c.attr = 'spam' +print(c.attr) \ No newline at end of file diff --git a/python/testData/inspections/PyPropertyAccessInspection/writeToAttrInSlots.py b/python/testData/inspections/PyDunderSlotsInspectionTest/writeToAttrInSlots.py similarity index 100% rename from python/testData/inspections/PyPropertyAccessInspection/writeToAttrInSlots.py rename to python/testData/inspections/PyDunderSlotsInspectionTest/writeToAttrInSlots.py diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py b/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py deleted file mode 100644 index 8642e35ade02..000000000000 --- a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3.py +++ /dev/null @@ -1,15 +0,0 @@ -class B(object): - __slots__ = ['f', 'b'] - -# ValueError: 'attr' in __slots__ conflicts with class variable -# This is not responsibility of current inspection -class C(B): - attr = 'baz' - __slots__ = ['attr', 'bar'] - -C.attr = 'spam' -print(C.attr) - -c = C() -c.attr = 'spam' -print(c.attr) \ No newline at end of file diff --git a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithAttrPy3.py b/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithAttrPy3.py deleted file mode 100644 index d8f34b6bc76b..000000000000 --- a/python/testData/inspections/PyPropertyAccessInspection/classAttrAssignmentAndSlotsWithAttrPy3.py +++ /dev/null @@ -1,12 +0,0 @@ -# ValueError: 'attr' in __slots__ conflicts with class variable -# This is not responsibility of current inspection -class Foo(object): - attr = 'baz' - __slots__ = ['attr', 'bar'] - -Foo.attr = 'spam' -print(Foo.attr) - -foo = Foo() -foo.attr = 'spam' -print(foo.attr) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyDunderSlotsInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyDunderSlotsInspectionTest.java new file mode 100644 index 000000000000..e3926bf83a42 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/inspections/PyDunderSlotsInspectionTest.java @@ -0,0 +1,217 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.inspections; + +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; + +import java.io.IOException; +import java.io.UncheckedIOException; + +public class PyDunderSlotsInspectionTest extends PyTestCase { + + // PY-12773 + public void testClassAttrAssignmentAndSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndSlotsWithDict() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndSlotsWithAttrPy2() { + doTestPy2(); + } + + // PY-12773 + public void testClassAttrAssignmentAndSlotsWithAttrPy3() { + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnSlotsAndEmptyParent() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnWithDictAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnAndInheritedWithDictSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy2() { + doTestPy2(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3() { + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnAndInheritedWithAttrSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnWithAttrAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnWithDictAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnWithAttrAndDictAndInheritedSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy2() { + doTestPy2(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3() { + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithDictSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy2() { + doTestPy2(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlotsPy3() { + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnWithAttrAndInheritedWithDictSlots() { + doTestPy2(); + doTestPy3(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy2() { + doTestPy2(); + } + + // PY-12773 + public void testInheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlotsPy3() { + doTestPy3(); + } + + // PY-19956 + public void testWriteToAttrInSlots() { + doTestPy2(); + doTestPy3(); + } + + private void doTestPy2() { + runWithLanguageLevel(LanguageLevel.PYTHON26, this::doTestPy); + } + + private void doTestPy3() { + runWithLanguageLevel(LanguageLevel.PYTHON30, this::doTestPy); + } + + private void doTestPy() { + final String path = "inspections/PyDunderSlotsInspectionTest/" + getTestName(true) + ".py"; + + final VirtualFile file = myFixture.getTempDirFixture().getFile(path); + if (file != null) { + try { + WriteAction.run(() -> file.delete(this)); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + myFixture.configureByFile(path); + myFixture.enableInspections(PyDunderSlotsInspection.class); + myFixture.checkHighlighting(true, false, false); + } +} diff --git a/python/testSrc/com/jetbrains/python/inspections/PyPropertyAccessInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyPropertyAccessInspectionTest.java index ae9a4a6b81c9..67848c045703 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyPropertyAccessInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyPropertyAccessInspectionTest.java @@ -15,205 +15,25 @@ */ package com.jetbrains.python.inspections; -import com.intellij.openapi.application.WriteAction; -import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.psi.LanguageLevel; -import java.io.IOException; -import java.io.UncheckedIOException; - /** * @author yole */ public class PyPropertyAccessInspectionTest extends PyTestCase { public void testTest() { - doTestPy2(); + doTest(); } // PY-2313 public void testOverrideAssignment() { - doTestPy2(); + doTest(); } - // PY-12773 - public void testClassAttrAssignmentAndSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndSlotsWithDict() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndSlotsWithAttrPy2() { - doTestPy2(); - } - - // PY-12773 - public void testClassAttrAssignmentAndSlotsWithAttrPy3() { - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnSlotsAndEmptyParent() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnWithDictAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnAndInheritedWithDictSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy2() { - doTestPy2(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnWithAttrAndInheritedSlotsPy3() { - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnAndInheritedWithAttrSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnWithAttrAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnWithDictAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnWithAttrAndDictAndInheritedSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy2() { - doTestPy2(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithAttrSlotsPy3() { - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithDictSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnAndInheritedWithAttrAndDictSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnWithAttrAndInheritedWithDictSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-12773 - public void testInheritedClassAttrAssignmentAndOwnWithDictAndInheritedWithAttrSlots() { - doTestPy2(); - doTestPy3(); - } - - // PY-19956 - public void testWriteToAttrInSlots() { - doTestPy2(); - doTestPy3(); - } - - private void doTestPy2() { - runWithLanguageLevel(LanguageLevel.PYTHON26, this::doTestPy); - } - - private void doTestPy3() { - runWithLanguageLevel(LanguageLevel.PYTHON30, this::doTestPy); - } - - private void doTestPy() { - final String path = "inspections/PyPropertyAccessInspection/" + getTestName(true) + ".py"; - - final VirtualFile file = myFixture.getTempDirFixture().getFile(path); - if (file != null) { - try { - WriteAction.run(() -> file.delete(this)); - } - catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - myFixture.configureByFile(path); + private void doTest() { + setLanguageLevel(LanguageLevel.PYTHON26); + myFixture.configureByFile("inspections/PyPropertyAccessInspection/" + getTestName(true) + ".py"); myFixture.enableInspections(PyPropertyAccessInspection.class); myFixture.checkHighlighting(true, false, false); }