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), "");