diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java index b7f3b1814325..af275c2a81a4 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyImportReference.java @@ -215,6 +215,7 @@ public class PyImportReference extends PyReferenceImpl { } } } + fillFromRootsIfNotRelative(relativeLevel, insertHandler); } else { // in "import _" or "from _ import" PsiElement prevElem = PyPsiUtils.getPrevNonWhitespaceSibling(myElement); @@ -235,28 +236,43 @@ public class PyImportReference extends PyReferenceImpl { addImportedNames(importStatement.getImportElements()); } } + final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); // look at dir by level - if ((relativeLevel >= 0 || !ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile))) { - final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); - if (containingDirectory != null) { - QualifiedName thisQName = QualifiedNameFinder.findShortestImportableQName(containingDirectory); - if (thisQName == null || thisQName.getComponentCount() == relativeLevel) { - fillFromDir(ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel), insertHandler); - } - else if (thisQName.getComponentCount() > relativeLevel) { - thisQName = thisQName.removeTail(relativeLevel); - fillFromQName(thisQName, insertHandler); - } - } + if (LanguageLevel.forElement(myCurrentFile).isPy3K() && containingDirectory != null && + PyUtil.isExplicitPackage(containingDirectory)) { + fillFromRootsIfNotRelative(relativeLevel, insertHandler); + fillFromSameDirectoryOrRelative(relativeLevel, insertHandler); + } + else { + fillFromSameDirectoryOrRelative(relativeLevel, insertHandler); + fillFromRootsIfNotRelative(relativeLevel, insertHandler); } - } - if (relativeLevel == -1) { - fillFromQName(QualifiedName.fromComponents(), insertHandler); } return ArrayUtil.toObjectArray(myObjects); } + private void fillFromRootsIfNotRelative(int relativeLevel, @Nullable InsertHandler insertHandler) { + if (relativeLevel == -1) { + fillFromQName(QualifiedName.fromComponents(), insertHandler); + } + } + + private void fillFromSameDirectoryOrRelative(int relativeLevel, @Nullable InsertHandler insertHandler) { + if (relativeLevel < 0 && ResolveImportUtil.isAbsoluteImportEnabledFor(myCurrentFile)) return; + final PsiDirectory containingDirectory = myCurrentFile.getContainingDirectory(); + if (containingDirectory != null) { + QualifiedName thisQName = QualifiedNameFinder.findShortestImportableQName(containingDirectory); + if (thisQName == null || thisQName.getComponentCount() == relativeLevel) { + fillFromDir(ResolveImportUtil.stepBackFrom(myCurrentFile, relativeLevel), insertHandler); + } + else if (thisQName.getComponentCount() > relativeLevel) { + thisQName = thisQName.removeTail(relativeLevel); + fillFromQName(thisQName, insertHandler); + } + } + } + private void fillFromQName(QualifiedName thisQName, InsertHandler insertHandler) { StreamEx.of(PyResolveImportUtil.resolveQualifiedName(thisQName, PyResolveImportUtil.fromFoothold(myCurrentFile))) .select(PsiDirectory.class) diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py new file mode 100644 index 000000000000..75970a773ebb --- /dev/null +++ b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py @@ -0,0 +1 @@ +from log \ No newline at end of file diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py new file mode 100644 index 000000000000..75970a773ebb --- /dev/null +++ b/python/testData/completion/fromImportCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py @@ -0,0 +1 @@ +from log \ No newline at end of file diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py new file mode 100644 index 000000000000..d722805d37f3 --- /dev/null +++ b/python/testData/completion/importCompletionHintForSameDirectoryModuleInOrdinaryPackage/ordinaryPackage/sample.py @@ -0,0 +1 @@ +import log \ No newline at end of file diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/logging1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py new file mode 100644 index 000000000000..d722805d37f3 --- /dev/null +++ b/python/testData/completion/importCompletionHintForSameDirectoryModuleInPlainDirectory/plainDirectory/sample.py @@ -0,0 +1 @@ +import log \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index f044730c75c0..360dea053df3 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -7,6 +7,7 @@ import com.intellij.openapi.module.Module; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.TestDataPath; +import com.intellij.testFramework.fixtures.TestLookupElementPresentation; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.codeInsight.completion.PyModuleNameCompletionContributor; import com.jetbrains.python.fixtures.PyTestCase; @@ -491,6 +492,38 @@ public class Py3CompletionTest extends PyTestCase { }); } + // PY-46056 + public void testImportCompletionHintForSameDirectoryModuleInOrdinaryPackage() { + doTestVariantTailText("ordinaryPackage/sample.py", "logging", null); + } + + // PY-46056 + public void testImportCompletionHintForSameDirectoryModuleInPlainDirectory() { + doTestVariantTailText("plainDirectory/sample.py", "logging", " (plainDirectory)"); + } + + // PY-46056 + public void testFromImportCompletionHintForSameDirectoryModuleInOrdinaryPackage() { + doTestVariantTailText("ordinaryPackage/sample.py", "logging", null); + } + + // PY-46056 + public void testFromImportCompletionHintForSameDirectoryModuleInPlainDirectory() { + doTestVariantTailText("plainDirectory/sample.py", "logging", " (plainDirectory)"); + } + + private void doTestVariantTailText(@NotNull String entryFilePath, @NotNull String variantName, @Nullable String tailText) { + runWithLanguageLevel(LanguageLevel.getLatest(), () -> { + myFixture.copyDirectoryToProject(getTestName(true), ""); + myFixture.configureByFile(entryFilePath); + LookupElement[] variants = myFixture.completeBasic(); + assertNotNull(variants); + LookupElement lookupElement = ContainerUtil.find(variants, v -> v.getLookupString().equals(variantName)); + assertNotNull(lookupElement); + assertEquals(tailText, TestLookupElementPresentation.renderElement(lookupElement).getTailText()); + }); + } + // PY-46054 public void testFromImportFromSameDirectoryModule() { runWithLanguageLevel(LanguageLevel.getLatest(), () -> {