From 6726f799adb6274d7458da407eeb9183ea84893e Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 28 Jul 2021 16:43:50 +0300 Subject: [PATCH] PY-48198 PY-48220 Use PyResolveImportUtil to find not imported modules for completion It allows to properly take into account .pyi stubs for module and packages and find namespace packages in addition to ordinary Python packages as both of them don't get into PyModuleNameIndex. GitOrigin-RevId: 4afdf6d61e1f2e426ce65b0d04c6727caaeada2b --- ...esolvedModuleAttributeCompletionContributor.kt | 12 +++++++----- .../AttributesFromModuleStubSuggested/main.py | 1 + .../AttributesFromModuleStubSuggested/mod.py | 1 + .../AttributesFromModuleStubSuggested/mod.pyi | 2 ++ .../AttributesFromPackageStubSuggested/main.py | 1 + .../pkg/__init__.py | 1 + .../pkg/__init__.pyi | 3 +++ .../main.py | 1 + .../nspkg/submod.py | 0 .../nspkg/subpkg/.empty | 0 .../PyNotImportedQualifiedNameCompletionTest.java | 15 +++++++++++++++ 11 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/main.py create mode 100644 python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.py create mode 100644 python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.pyi create mode 100644 python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/main.py create mode 100644 python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.py create mode 100644 python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.pyi create mode 100644 python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/main.py create mode 100644 python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/nspkg/submod.py create mode 100644 python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/nspkg/subpkg/.empty diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyUnresolvedModuleAttributeCompletionContributor.kt b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyUnresolvedModuleAttributeCompletionContributor.kt index c6291d97a843..948c3ca1546f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyUnresolvedModuleAttributeCompletionContributor.kt +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/completion/PyUnresolvedModuleAttributeCompletionContributor.kt @@ -20,8 +20,9 @@ import com.jetbrains.python.codeInsight.imports.AddImportHelper import com.jetbrains.python.inspections.unresolvedReference.PyPackageAliasesProvider import com.jetbrains.python.psi.* import com.jetbrains.python.psi.resolve.PyResolveUtil +import com.jetbrains.python.psi.resolve.fromFoothold +import com.jetbrains.python.psi.resolve.resolveQualifiedName import com.jetbrains.python.psi.search.PySearchUtilBase -import com.jetbrains.python.psi.stubs.PyModuleNameIndex import com.jetbrains.python.psi.stubs.PyQualifiedNameCompletionMatcher import com.jetbrains.python.psi.stubs.PyQualifiedNameCompletionMatcher.QualifiedNameMatcher import com.jetbrains.python.psi.types.PyModuleType @@ -117,12 +118,12 @@ class PyUnresolvedModuleAttributeCompletionContributor : CompletionContributor() val scope = PySearchUtilBase.defaultSuggestionScope(parameters.originalFile) val typeContext = TypeEvalContext.userInitiated(project, originalFile) - val availableModules = PyModuleNameIndex.findByQualifiedName(packageName, project, scope) - .asSequence() + val availableModules = resolveQualifiedName(packageName, fromFoothold(originalFile)) if (packageNameForAlias == null) { - availableModules.filter { PyUtil.isPackage(it) } - .flatMap { PyModuleType.getSubModuleVariants(it.containingDirectory, it, null) } + availableModules.asSequence() + .filterIsInstance() + .flatMap { PyModuleType.getSubModuleVariants(it, originalFile, null) } .filterNot { it.lookupString.startsWith('_') } .mapNotNull { val qualifiedNameToSuggest = "$qualifier.${it.lookupString}" @@ -138,6 +139,7 @@ class PyUnresolvedModuleAttributeCompletionContributor : CompletionContributor() } availableModules.asSequence() + .mapNotNull { if (it is PsiDirectory) PyUtil.getPackageElement(it, originalFile) else it } .filterIsInstance() .map { PyModuleType(it) } .flatMap { it.getCompletionVariantsAsLookupElements(parameters.position, context, false, false, typeContext) } diff --git a/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/main.py b/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/main.py new file mode 100644 index 000000000000..e52e3abd2f30 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/main.py @@ -0,0 +1 @@ +mod. \ No newline at end of file diff --git a/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.py b/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.py new file mode 100644 index 000000000000..31c1eef29203 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.py @@ -0,0 +1 @@ +bar = 1 \ No newline at end of file diff --git a/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.pyi b/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.pyi new file mode 100644 index 000000000000..4c4c329b459b --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/AttributesFromModuleStubSuggested/mod.pyi @@ -0,0 +1,2 @@ +foo: Any +bar: int diff --git a/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/main.py b/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/main.py new file mode 100644 index 000000000000..eabe811548ff --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/main.py @@ -0,0 +1 @@ +pkg. diff --git a/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.py b/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.py new file mode 100644 index 000000000000..fbd64a6abc75 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.py @@ -0,0 +1 @@ +bar = 1 diff --git a/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.pyi b/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.pyi new file mode 100644 index 000000000000..c8c84de6bbe6 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/AttributesFromPackageStubSuggested/pkg/__init__.pyi @@ -0,0 +1,3 @@ +foo: Any +bar: int + diff --git a/python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/main.py b/python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/main.py new file mode 100644 index 000000000000..3749492afa16 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/main.py @@ -0,0 +1 @@ +nspkg. diff --git a/python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/nspkg/submod.py b/python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/nspkg/submod.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/nspkg/subpkg/.empty b/python/testData/completion/notImportedQualifiedName/SubpackagesAndSubmodulesOfNamespacePackages/nspkg/subpkg/.empty new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java b/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java index 4d7250ea11ee..fa7974a4be4e 100644 --- a/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java @@ -136,6 +136,16 @@ public class PyNotImportedQualifiedNameCompletionTest extends PyTestCase { doTestBasicCompletion(); } + // PY-48220 + public void testAttributesFromPackageStubSuggested() { + assertContainsElements(doBasicCompletion(), "pkg.foo"); + } + + // PY-48220 + public void testAttributesFromModuleStubSuggested() { + assertContainsElements(doBasicCompletion(), "mod.foo"); + } + // PY-48219 public void testAttributesNotLimitedByDunderAll() { assertContainsElements(doBasicCompletion(), "mod.foo"); @@ -146,6 +156,11 @@ public class PyNotImportedQualifiedNameCompletionTest extends PyTestCase { doTestBasicCompletion(); } + // PY-48198 + public void testSubpackagesAndSubmodulesOfNamespacePackages() { + assertContainsElements(doBasicCompletion(), "nspkg.submod", "nspkg.subpkg"); + } + @Nullable private List doBasicCompletion() { myFixture.copyDirectoryToProject(getTestName(false), "");