diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java index 5bdb664b51cb..b836e7d63724 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -182,21 +182,25 @@ public class PyImportReference extends PyReferenceImpl { if (fromImport != null && myElement.getParent() != fromImport) { // in "from foo import _" PyReferenceExpression src = fromImport.getImportSource(); if (src != null) { - PsiElement modCandidate = src.getReference().resolve(); - if (modCandidate instanceof PyExpression) { - addImportedNames(fromImport.getImportElements()); // don't propose already imported items - // try to collect submodules - PyExpression module = (PyExpression)modCandidate; - PyType qualifierType = myContext.getType(module); - if (qualifierType != null) { - ProcessingContext ctx = new ProcessingContext(); - ctx.put(PyType.CTX_NAMES, myNamesAlready); - Collections.addAll(myObjects, qualifierType.getCompletionVariants(myElement.getName(), myElement, ctx)); + ResolveResult[] resolved = src.getReference().multiResolve(false); + for (ResolveResult result : resolved) { + PsiElement modCandidate = result.getElement(); + if (modCandidate instanceof PyExpression) { + addImportedNames(fromImport.getImportElements()); // don't propose already imported items + // try to collect submodules + PyExpression module = (PyExpression)modCandidate; + PyType qualifierType = myContext.getType(module); + if (qualifierType != null) { + ProcessingContext ctx = new ProcessingContext(); + ctx.put(PyType.CTX_NAMES, myNamesAlready); + Collections.addAll(myObjects, qualifierType.getCompletionVariants(myElement.getName(), myElement, ctx)); + } + } + else if (modCandidate instanceof PsiDirectory) { + fillFromDir((PsiDirectory)modCandidate, ImportKeywordHandler.INSTANCE); } - return myObjects.toArray(); } - else if (modCandidate instanceof PsiDirectory) { - fillFromDir((PsiDirectory)modCandidate, ImportKeywordHandler.INSTANCE); + if (!myObjects.isEmpty()) { return myObjects.toArray(); } } diff --git a/python/testData/completion/fromLocalNamespacePackageInFromImport/root1/pkg/bar.py b/python/testData/completion/fromLocalNamespacePackageInFromImport/root1/pkg/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromLocalNamespacePackageInFromImport/root1/pkg/foo.py b/python/testData/completion/fromLocalNamespacePackageInFromImport/root1/pkg/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromLocalNamespacePackageInFromImport/root1/pkg/test.py b/python/testData/completion/fromLocalNamespacePackageInFromImport/root1/pkg/test.py new file mode 100644 index 000000000000..284501bd6125 --- /dev/null +++ b/python/testData/completion/fromLocalNamespacePackageInFromImport/root1/pkg/test.py @@ -0,0 +1 @@ +from pkg import \ No newline at end of file diff --git a/python/testData/completion/fromLocalNamespacePackageInFromImport/root2/pkg/baz.py b/python/testData/completion/fromLocalNamespacePackageInFromImport/root2/pkg/baz.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromLocalNamespacePackageInImportStatement/root1/pkg/bar.py b/python/testData/completion/fromLocalNamespacePackageInImportStatement/root1/pkg/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromLocalNamespacePackageInImportStatement/root1/pkg/foo.py b/python/testData/completion/fromLocalNamespacePackageInImportStatement/root1/pkg/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromLocalNamespacePackageInImportStatement/root1/pkg/test.py b/python/testData/completion/fromLocalNamespacePackageInImportStatement/root1/pkg/test.py new file mode 100644 index 000000000000..3f729c32a29d --- /dev/null +++ b/python/testData/completion/fromLocalNamespacePackageInImportStatement/root1/pkg/test.py @@ -0,0 +1 @@ +import pkg. \ No newline at end of file diff --git a/python/testData/completion/fromLocalNamespacePackageInImportStatement/root2/pkg/baz.py b/python/testData/completion/fromLocalNamespacePackageInImportStatement/root2/pkg/baz.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index 90af39ef4b33..8b47addb0e75 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -14,6 +14,7 @@ import com.intellij.testFramework.TestDataPath; import com.jetbrains.python.documentation.docstrings.DocStringFormat; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.psi.LanguageLevel; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -619,6 +620,16 @@ public class PythonCompletionTest extends PyTestCase { doMultiFileTest(); } + // PY-32268 + public void testFromLocalNamespacePackageInFromImport() { + doTestImportFromLocalPython3NamespacePackage(); + } + + // PY-32268 + public void testFromLocalNamespacePackageInImportStatement() { + doTestImportFromLocalPython3NamespacePackage(); + } + // PY-6829 public void testFakeNameInQualifiedReference() { doTest(); @@ -1555,6 +1566,19 @@ public class PythonCompletionTest extends PyTestCase { }); } + private void doTestImportFromLocalPython3NamespacePackage() { + runWithLanguageLevel(LanguageLevel.PYTHON35, () -> { + myFixture.copyDirectoryToProject(getTestName(true), ""); + runWithSourceRoots(Lists.newArrayList(myFixture.findFileInTempDir("root1"), myFixture.findFileInTempDir("root2")), () -> { + myFixture.configureByFile("root1/pkg/test.py"); + List lookupStrings = StreamEx.of(myFixture.completeBasic()) + .map(LookupElement::getLookupString) + .toList(); + assertContainsElements(lookupStrings, "foo", "bar", "baz"); + }); + }); + } + @Override protected String getTestDataPath() { return PythonTestUtil.getTestDataPath() + "/completion";