From af64e90b62acf5afce58b3540727c3d2369ce584 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 31 Jan 2018 19:47:30 +0300 Subject: [PATCH] PY-16412 Properly import named tuples for their use in type hints For that I introduced a new method -- getElement() in PyType that allows to find out the element that can be used to reference this type according to PEP 484 perspective, e.g. a target assignment for TypeVar's and NamedTuples and PSI class themselves for class types. Also, class object types for named tuples are wrapped in typing.Type[] as expected. --- .../jetbrains/python/psi/types/PyType.java | 6 +++ .../intentions/PyTypeHintGenerationUtil.java | 43 +++++++++++-------- .../codeInsight/stdlib/PyNamedTupleType.java | 30 +++++++++---- .../stdlib/PyStdlibTypeProvider.java | 3 +- .../documentation/PyTypeModelBuilder.java | 22 +++++----- .../python/psi/types/PyClassTypeImpl.java | 7 +++ .../python/psi/types/PyGenericType.java | 13 ++++++ .../lib.py | 7 +++ .../main.py | 3 ++ .../main_after.py | 5 +++ .../lib.py | 7 +++ .../main.py | 3 ++ .../main_after.py | 3 ++ .../lib.py | 7 +++ .../main.py | 3 ++ .../main_after.py | 5 +++ .../lib.py | 9 ++++ .../main.py | 3 ++ .../main_after.py | 3 ++ .../lib.py | 7 +++ .../main.py | 3 ++ .../main_after.py | 3 ++ .../PyAnnotateVariableTypeIntentionTest.java | 20 +++++++++ 23 files changed, 177 insertions(+), 38 deletions(-) create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/lib.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main_after.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/lib.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main_after.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/lib.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main_after.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/lib.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main_after.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/lib.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main.py create mode 100644 python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main_after.py diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java index 437d998b5fb6..60c284ff7931 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.ProcessingContext; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.PyQualifiedNameOwner; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import org.jetbrains.annotations.NotNull; @@ -35,6 +36,11 @@ import java.util.Set; */ public interface PyType { + @Nullable + default PyQualifiedNameOwner getDeclarationElement() { + return null; + } + /** * Resolves an attribute of type. * diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyTypeHintGenerationUtil.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyTypeHintGenerationUtil.java index 05b7efba8d53..15592d3af782 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyTypeHintGenerationUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyTypeHintGenerationUtil.java @@ -21,6 +21,7 @@ import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.codeInsight.imports.AddImportHelper; import com.jetbrains.python.codeInsight.imports.AddImportHelper.ImportPriority; +import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType; import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; @@ -280,11 +281,11 @@ public class PyTypeHintGenerationUtil { private static void addImportsForTypeAnnotations(@NotNull List types, @NotNull TypeEvalContext context, @NotNull PsiFile file) { - final Set classes = new HashSet<>(); + final Set symbols = new HashSet<>(); final Set namesFromTyping = new HashSet<>(); for (PyType type : types) { - collectImportTargetsFromType(type, context, classes, namesFromTyping); + collectImportTargetsFromType(type, context, symbols, namesFromTyping); } final boolean builtinTyping = LanguageLevel.forElement(file).isAtLeast(LanguageLevel.PYTHON35); @@ -293,24 +294,30 @@ public class PyTypeHintGenerationUtil { AddImportHelper.addOrUpdateFromImportStatement(file, "typing", name, null, priority, null); } - for (PyClass pyClass : classes) { - PyClassRefactoringUtil.insertImport(file, pyClass, null, true); + for (PsiNamedElement symbol : symbols) { + PyClassRefactoringUtil.insertImport(file, symbol, null, true); } } private static void collectImportTargetsFromType(@Nullable PyType type, @NotNull TypeEvalContext context, - @NotNull Set classes, - @NotNull Set names) { + @NotNull Set symbols, + @NotNull Set typingTypes) { if (type == null) { - names.add("Any"); + typingTypes.add("Any"); } else if (type instanceof PyUnionType) { final Collection members = ((PyUnionType)type).getMembers(); final boolean isOptional = members.size() == 2 && members.contains(PyNoneType.INSTANCE); - names.add(isOptional ? "Optional" : "Union"); + typingTypes.add(isOptional ? "Optional" : "Union"); for (PyType pyType : members) { - collectImportTargetsFromType(pyType, context, classes, names); + collectImportTargetsFromType(pyType, context, symbols, typingTypes); + } + } + else if (type instanceof PyNamedTupleType) { + final PyQualifiedNameOwner element = type.getDeclarationElement(); + if (element instanceof PsiNamedElement) { + symbols.add((PsiNamedElement)element); } } else if (type instanceof PyCollectionType) { @@ -318,32 +325,32 @@ public class PyTypeHintGenerationUtil { final PyClass pyClass = ((PyCollectionTypeImpl)type).getPyClass(); final String typingCollectionName = PyTypingTypeProvider.TYPING_COLLECTION_CLASSES.get(pyClass.getQualifiedName()); if (typingCollectionName != null && type.isBuiltin()) { - names.add(typingCollectionName); + typingTypes.add(typingCollectionName); } else { - classes.add(pyClass); + symbols.add(pyClass); } } else if (type instanceof PyTupleType) { - names.add("Tuple"); + typingTypes.add("Tuple"); } for (PyType pyType : ((PyCollectionType)type).getElementTypes()) { - collectImportTargetsFromType(pyType, context, classes, names); + collectImportTargetsFromType(pyType, context, symbols, typingTypes); } } else if (type instanceof PyClassType) { - classes.add(((PyClassType)type).getPyClass()); + symbols.add(((PyClassType)type).getPyClass()); } else if (type instanceof PyCallableType) { - names.add("Callable"); + typingTypes.add("Callable"); final PyCallableType callableType = (PyCallableType)type; for (PyCallableParameter parameter : ContainerUtil.notNullize(callableType.getParameters(context))) { - collectImportTargetsFromType(parameter.getType(context), context, classes, names); + collectImportTargetsFromType(parameter.getType(context), context, symbols, typingTypes); } - collectImportTargetsFromType(callableType.getReturnType(context), context, classes, names); + collectImportTargetsFromType(callableType.getReturnType(context), context, symbols, typingTypes); } if (type instanceof PyInstantiableType && ((PyInstantiableType)type).isDefinition()) { - names.add("Type"); + typingTypes.add("Type"); } } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 955f82fa289b..186f513fdcdf 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -6,10 +6,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; import com.intellij.util.containers.ContainerUtil; -import java.util.HashMap; -import com.jetbrains.python.psi.PyCallSiteExpression; -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.types.*; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; @@ -32,12 +29,22 @@ public class PyNamedTupleType extends PyTupleType implements PyCallableType { private final DefinitionLevel myDefinitionLevel; private final boolean myTyped; + private final PyTargetExpression myTargetExpression; public PyNamedTupleType(@NotNull PyClass tupleClass, @NotNull String name, @NotNull LinkedHashMap fields, @NotNull DefinitionLevel definitionLevel, boolean typed) { + this(tupleClass, name, fields, definitionLevel, typed, null); + } + + public PyNamedTupleType(@NotNull PyClass tupleClass, + @NotNull String name, + @NotNull LinkedHashMap fields, + @NotNull DefinitionLevel definitionLevel, + boolean typed, + @Nullable PyTargetExpression target) { super(tupleClass, Collections.unmodifiableList(ContainerUtil.map(fields.values(), typeAndValue -> typeAndValue.getType())), false, @@ -47,6 +54,13 @@ public class PyNamedTupleType extends PyTupleType implements PyCallableType { myName = name; myDefinitionLevel = definitionLevel; myTyped = typed; + myTargetExpression = target; + } + + @NotNull + @Override + public PyQualifiedNameOwner getDeclarationElement() { + return myTargetExpression; } @Override @@ -74,7 +88,7 @@ public class PyNamedTupleType extends PyTupleType implements PyCallableType { @Override public PyNamedTupleType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { if (myDefinitionLevel == DefinitionLevel.NT_FUNCTION) { - return new PyNamedTupleType(myClass, myName, myFields, DefinitionLevel.NEW_TYPE, myTyped); + return new PyNamedTupleType(myClass, myName, myFields, DefinitionLevel.NEW_TYPE, myTyped, myTargetExpression); } else if (myDefinitionLevel == DefinitionLevel.NEW_TYPE) { return getCallDefinitionType(callSite, context); @@ -87,7 +101,7 @@ public class PyNamedTupleType extends PyTupleType implements PyCallableType { @Override public PyNamedTupleType toInstance() { return myDefinitionLevel == DefinitionLevel.NEW_TYPE - ? new PyNamedTupleType(myClass, myName, myFields, DefinitionLevel.INSTANCE, myTyped) + ? new PyNamedTupleType(myClass, myName, myFields, DefinitionLevel.INSTANCE, myTyped, myTargetExpression) : this; } @@ -96,7 +110,7 @@ public class PyNamedTupleType extends PyTupleType implements PyCallableType { public PyNamedTupleType toClass() { return myDefinitionLevel == DefinitionLevel.INSTANCE ? this - : new PyNamedTupleType(myClass, myName, myFields, DefinitionLevel.NEW_TYPE, myTyped); + : new PyNamedTupleType(myClass, myName, myFields, DefinitionLevel.NEW_TYPE, myTyped, myTargetExpression); } @Override @@ -165,7 +179,7 @@ public class PyNamedTupleType extends PyTupleType implements PyCallableType { } } - return new PyNamedTupleType(myClass, myName, newFields, myDefinitionLevel, false); + return new PyNamedTupleType(myClass, myName, newFields, myDefinitionLevel, false, myTargetExpression); } return this; diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 339e46ccf14a..1ba8101bf21a 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -539,7 +539,8 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { stub.getName(), parseNamedTupleFields(referenceTarget, fields, context), definitionLevel, - ContainerUtil.find(fields.values(), Optional::isPresent) != null); + ContainerUtil.find(fields.values(), Optional::isPresent) != null, + as(referenceTarget, PyTargetExpression.class)); } @Nullable diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index 8b1658237aef..e93aa285ddae 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -227,7 +227,17 @@ public class PyTypeModelBuilder { myVisited.put(type, null); //mark as evaluating TypeModel result = null; - if (type instanceof PyNamedTupleType) { + if (type instanceof PyInstantiableType && ((PyInstantiableType)type).isDefinition()) { + final PyInstantiableType instanceType = ((PyInstantiableType)type).toInstance(); + // Special case: render Type[type] as just type + if (type instanceof PyClassType && instanceType.equals(PyBuiltinCache.getInstance(((PyClassType)type).getPyClass()).getTypeType())) { + result = NamedType.nameOrAny(type); + } + else { + result = new ClassObjectType(build(instanceType, allowUnions)); + } + } + else if (type instanceof PyNamedTupleType) { result = NamedType.nameOrAny(type); } else if (type instanceof PyTupleType) { @@ -281,16 +291,6 @@ public class PyTypeModelBuilder { else if (type instanceof PyCallableType && !(type instanceof PyClassLikeType)) { result = buildCallable((PyCallableType)type); } - else if (type instanceof PyInstantiableType && ((PyInstantiableType)type).isDefinition()) { - final PyInstantiableType instanceType = ((PyInstantiableType)type).toInstance(); - // Special case: render Type[type] as just type - if (type instanceof PyClassType && instanceType.equals(PyBuiltinCache.getInstance(((PyClassType)type).getPyClass()).getTypeType())) { - result = NamedType.nameOrAny(type); - } - else { - result = new ClassObjectType(build(instanceType, allowUnions)); - } - } else if (type instanceof PyGenericType) { result = new GenericType(type.getName()); } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 6cf348331798..784edb59b2e6 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -85,6 +85,13 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { return myClass; } + + @NotNull + @Override + public PyQualifiedNameOwner getDeclarationElement() { + return getPyClass(); + } + /** * @return whether this type refers to an instance or a definition of the class. */ diff --git a/python/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/src/com/jetbrains/python/psi/types/PyGenericType.java index f1c6cda9e29a..4db2801039c5 100644 --- a/python/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -20,6 +20,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.PyTargetExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import org.jetbrains.annotations.NotNull; @@ -34,15 +35,27 @@ public class PyGenericType implements PyType, PyInstantiableType @NotNull private final String myName; @Nullable private final PyType myBound; private boolean myIsDefinition = false; + private PyTargetExpression myTargetExpression; public PyGenericType(@NotNull String name, @Nullable PyType bound) { this(name, bound, false); } public PyGenericType(@NotNull String name, @Nullable PyType bound, boolean isDefinition) { + this(name, bound, isDefinition, null); + } + + public PyGenericType(@NotNull String name, @Nullable PyType bound, boolean isDefinition, @Nullable PyTargetExpression target) { myName = name; myBound = bound; myIsDefinition = isDefinition; + myTargetExpression = target; + } + + @Nullable + @Override + public PyTargetExpression getDeclarationElement() { + return myTargetExpression; } @Nullable diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/lib.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/lib.py new file mode 100644 index 000000000000..d6e48b35355d --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/lib.py @@ -0,0 +1,7 @@ +from collections import namedtuple + +MyTuple = namedtuple('MyTuple', ['foo']) + + +def func(): + return MyTuple diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main.py new file mode 100644 index 000000000000..e5ef8a7cf290 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main.py @@ -0,0 +1,3 @@ +from lib import func + +var = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main_after.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main_after.py new file mode 100644 index 000000000000..29ad886c603e --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleClassInOtherFile/main_after.py @@ -0,0 +1,5 @@ +from typing import Type + +from lib import func, MyTuple + +var: [Type[MyTuple]] = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/lib.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/lib.py new file mode 100644 index 000000000000..e5a5bd866fdb --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/lib.py @@ -0,0 +1,7 @@ +from collections import namedtuple + +MyTuple = namedtuple('MyTuple', ['foo']) + + +def func(): + return MyTuple(foo=42) diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main.py new file mode 100644 index 000000000000..e5ef8a7cf290 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main.py @@ -0,0 +1,3 @@ +from lib import func + +var = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main_after.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main_after.py new file mode 100644 index 000000000000..4bc5bad6b0b3 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationCollectionsNamedTupleInOtherFile/main_after.py @@ -0,0 +1,3 @@ +from lib import func, MyTuple + +var: [MyTuple] = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/lib.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/lib.py new file mode 100644 index 000000000000..ea25ea34916c --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/lib.py @@ -0,0 +1,7 @@ +from typing import NamedTuple + +MyTuple = NamedTuple('MyTuple', [('foo', int)]) + + +def func(): + return MyTuple diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main.py new file mode 100644 index 000000000000..e5ef8a7cf290 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main.py @@ -0,0 +1,3 @@ +from lib import func + +var = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main_after.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main_after.py new file mode 100644 index 000000000000..29ad886c603e --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleClassInOtherFile/main_after.py @@ -0,0 +1,5 @@ +from typing import Type + +from lib import func, MyTuple + +var: [Type[MyTuple]] = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/lib.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/lib.py new file mode 100644 index 000000000000..95a5a655aba7 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/lib.py @@ -0,0 +1,9 @@ +from typing import NamedTuple + + +class MyTuple(NamedTuple): + foo: int + + +def func(): + return MyTuple(foo=42) diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main.py new file mode 100644 index 000000000000..e5ef8a7cf290 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main.py @@ -0,0 +1,3 @@ +from lib import func + +var = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main_after.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main_after.py new file mode 100644 index 000000000000..4bc5bad6b0b3 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleDirectInheritorInOtherFile/main_after.py @@ -0,0 +1,3 @@ +from lib import func, MyTuple + +var: [MyTuple] = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/lib.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/lib.py new file mode 100644 index 000000000000..92d97504bfb6 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/lib.py @@ -0,0 +1,7 @@ +from typing import NamedTuple + +MyTuple = NamedTuple('MyTuple', [('foo', int)]) + + +def func(): + return MyTuple(foo=42) diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main.py new file mode 100644 index 000000000000..e5ef8a7cf290 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main.py @@ -0,0 +1,3 @@ +from lib import func + +var = func() \ No newline at end of file diff --git a/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main_after.py b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main_after.py new file mode 100644 index 000000000000..4bc5bad6b0b3 --- /dev/null +++ b/python/testData/intentions/PyAnnotateVariableTypeIntentionTest/AnnotationTypingNamedTupleInOtherFile/main_after.py @@ -0,0 +1,3 @@ +from lib import func, MyTuple + +var: [MyTuple] = func() \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/intentions/PyAnnotateVariableTypeIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyAnnotateVariableTypeIntentionTest.java index f8f32eefab5b..9a79ec6e5e27 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyAnnotateVariableTypeIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyAnnotateVariableTypeIntentionTest.java @@ -231,6 +231,26 @@ public class PyAnnotateVariableTypeIntentionTest extends PyIntentionTestCase { doAnnotationTest(); } + public void testAnnotationTypingNamedTupleInOtherFile() { + doMultiFileAnnotationTest(); + } + + public void testAnnotationTypingNamedTupleClassInOtherFile() { + doMultiFileAnnotationTest(); + } + + public void testAnnotationTypingNamedTupleDirectInheritorInOtherFile() { + doMultiFileAnnotationTest(); + } + + public void testAnnotationCollectionsNamedTupleInOtherFile() { + doMultiFileAnnotationTest(); + } + + public void testAnnotationCollectionsNamedTupleClassInOtherFile() { + doMultiFileAnnotationTest(); + } + public void testConflictWithAnnotationFunctionTypeIntention() { doTest(LanguageLevel.PYTHON36); }