diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 19548e869c1e..800170146b4c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -1066,6 +1066,12 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } } } + else if (psiElement instanceof PyTypeDeclarationStatement) { + final PyExpression target = ((PyTypeDeclarationStatement)psiElement).getTarget(); + if (target instanceof PyTargetExpression) { + result.add((PyTargetExpression)target); + } + } } return result; } diff --git a/python/testData/inspections/PyTypeCheckerInspection/DefinitionAgainstStructural.py b/python/testData/inspections/PyTypeCheckerInspection/DefinitionAgainstStructural.py new file mode 100644 index 000000000000..5d018b9196c0 --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/DefinitionAgainstStructural.py @@ -0,0 +1,16 @@ +from typing import ClassVar + + +def dist(p1): + print(p1.x) + print(p1.y) + return p1 + + +class A: + x: ClassVar[int] + y: ClassVar[str] + + +dist(A) +dist(A()) \ No newline at end of file diff --git a/python/testData/inspections/PyTypeCheckerInspection/TypingNTAgainstStructural.py b/python/testData/inspections/PyTypeCheckerInspection/TypingNTAgainstStructural.py new file mode 100644 index 000000000000..a29fcd5ee11d --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/TypingNTAgainstStructural.py @@ -0,0 +1,16 @@ +import typing + + +def dist(p1): + print(p1.x) + print(p1.y) + return p1 + + +class TP(typing.NamedTuple): + x: int + y: int + + +dist(TP) +dist(TP(1, 2)) \ No newline at end of file diff --git a/python/testData/stubs/ClassAttributeTypeDeclaration.py b/python/testData/stubs/ClassAttributeTypeDeclaration.py new file mode 100644 index 000000000000..4ad74381bbe3 --- /dev/null +++ b/python/testData/stubs/ClassAttributeTypeDeclaration.py @@ -0,0 +1,2 @@ +class MyClass: + foo: int \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyStubsTest.java b/python/testSrc/com/jetbrains/python/PyStubsTest.java index a7c799671412..adfc004e6f1c 100644 --- a/python/testSrc/com/jetbrains/python/PyStubsTest.java +++ b/python/testSrc/com/jetbrains/python/PyStubsTest.java @@ -908,4 +908,20 @@ public class PyStubsTest extends PyTestCase { assertNull(funcStub.findChildStubByType(PyElementTypes.ANNOTATION)); }); } + + // PY-26163 + public void testClassAttributeTypeDeclaration() { + runWithLanguageLevel(LanguageLevel.PYTHON36, () -> { + final PyFile file = getTestFile(); + final PyClass pyClass = file.findTopLevelClass("MyClass"); + final TypeEvalContext context = TypeEvalContext.codeAnalysis(file.getProject(), file); + + assertNotNull(pyClass.findClassAttribute("foo", false, context)); + assertNotParsed(file); + + //noinspection ResultOfMethodCallIgnored + pyClass.getText(); + assertNotNull(pyClass.findClassAttribute("foo", false, context)); + }); + } } diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index 0f8ef889d30c..992f846afafb 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -455,4 +455,14 @@ public class PyTypeCheckerInspectionTest extends PyInspectionTestCase { public void testCallableInstanceAgainstCallable() { runWithLanguageLevel(LanguageLevel.PYTHON35, this::doTest); } + + // PY-26163 + public void testTypingNTAgainstStructural() { + runWithLanguageLevel(LanguageLevel.PYTHON36, this::doTest); + } + + // PY-26163 + public void testDefinitionAgainstStructural() { + runWithLanguageLevel(LanguageLevel.PYTHON36, this::doTest); + } }