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
This commit is contained in:
Mikhail Golubev
2021-08-23 10:14:13 +00:00
committed by intellij-monorepo-bot
parent 7fc1f80e2e
commit 6726f799ad
11 changed files with 32 additions and 5 deletions
@@ -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<PsiDirectory>()
.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<PyFile>()
.map { PyModuleType(it) }
.flatMap { it.getCompletionVariantsAsLookupElements(parameters.position, context, false, false, typeContext) }
@@ -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<String> doBasicCompletion() {
myFixture.copyDirectoryToProject(getTestName(false), "");