From a8650dfd2302e16223f369919f698e066b6cf48f Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 16 Mar 2018 15:07:47 +0300 Subject: [PATCH] PY-28461 Fixed completion for implicit package members imported via relative imports from the same level --- .../jetbrains/python/psi/types/PyModuleType.java | 8 +++++--- .../completion/implicitImportsInsidePackage/a.py | 2 +- .../implicitImportsInsidePackage/pkg1/m1.py | 2 +- .../pkg1/pkg2/__init__.py | 2 +- .../pkg1/pkg3/__init__.py | 2 +- .../implicitImportsInsidePackagePy2/a.py | 2 ++ .../pkg1/__init__.py | 3 +++ .../implicitImportsInsidePackagePy2/pkg1/m1.py | 1 + .../pkg1/pkg2/__init__.py | 1 + .../pkg1/pkg3/__init__.py | 1 + .../jetbrains/python/PythonCompletionTest.java | 15 +++++++++++++-- 11 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 python/testData/completion/implicitImportsInsidePackagePy2/a.py create mode 100644 python/testData/completion/implicitImportsInsidePackagePy2/pkg1/__init__.py create mode 100644 python/testData/completion/implicitImportsInsidePackagePy2/pkg1/m1.py create mode 100644 python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg2/__init__.py create mode 100644 python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg3/__init__.py diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index ba81c1a5fb20..5e8e178ef89e 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -16,6 +16,7 @@ import com.intellij.psi.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; +import com.intellij.util.ObjectUtils; import com.intellij.util.ProcessingContext; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; @@ -285,8 +286,8 @@ public class PyModuleType implements PyType { // Modules don't descend from obje private static List getImportedQNames(@NotNull PyImportElement element) { final List importedQNames = new ArrayList<>(); final PyStatement stmt = element.getContainingImportStatement(); - if (stmt instanceof PyFromImportStatement) { - final PyFromImportStatement fromImportStatement = (PyFromImportStatement)stmt; + final PyFromImportStatement fromImportStatement = ObjectUtils.tryCast(stmt, PyFromImportStatement.class); + if (fromImportStatement != null) { final QualifiedName importedQName = fromImportStatement.getImportSourceQName(); final String visibleName = element.getVisibleName(); if (importedQName != null) { @@ -316,7 +317,8 @@ public class PyModuleType implements PyType { // Modules don't descend from obje importedQNames.add(importedQName); } } - if (!ResolveImportUtil.isAbsoluteImportEnabledFor(element)) { + if (!ResolveImportUtil.isAbsoluteImportEnabledFor(element) || + (fromImportStatement != null && fromImportStatement.getRelativeLevel() == 1)) { PsiFile file = element.getContainingFile(); if (file != null) { file = file.getOriginalFile(); diff --git a/python/testData/completion/implicitImportsInsidePackage/a.py b/python/testData/completion/implicitImportsInsidePackage/a.py index b83d7b38ed86..c3da0a9258fa 100644 --- a/python/testData/completion/implicitImportsInsidePackage/a.py +++ b/python/testData/completion/implicitImportsInsidePackage/a.py @@ -1,2 +1,2 @@ import pkg1 -pkg1. \ No newline at end of file +pkg1. diff --git a/python/testData/completion/implicitImportsInsidePackage/pkg1/m1.py b/python/testData/completion/implicitImportsInsidePackage/pkg1/m1.py index 98383be197e4..c4e5bcc8001f 100644 --- a/python/testData/completion/implicitImportsInsidePackage/pkg1/m1.py +++ b/python/testData/completion/implicitImportsInsidePackage/pkg1/m1.py @@ -1 +1 @@ -foo=1 \ No newline at end of file +foo = 1 diff --git a/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg2/__init__.py b/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg2/__init__.py index 31c1eef29203..fbd64a6abc75 100644 --- a/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg2/__init__.py +++ b/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg2/__init__.py @@ -1 +1 @@ -bar = 1 \ No newline at end of file +bar = 1 diff --git a/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg3/__init__.py b/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg3/__init__.py index 05a514738efd..4f0d6fe821dd 100644 --- a/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg3/__init__.py +++ b/python/testData/completion/implicitImportsInsidePackage/pkg1/pkg3/__init__.py @@ -1 +1 @@ -foo2 \ No newline at end of file +foo2 = 0 diff --git a/python/testData/completion/implicitImportsInsidePackagePy2/a.py b/python/testData/completion/implicitImportsInsidePackagePy2/a.py new file mode 100644 index 000000000000..c3da0a9258fa --- /dev/null +++ b/python/testData/completion/implicitImportsInsidePackagePy2/a.py @@ -0,0 +1,2 @@ +import pkg1 +pkg1. diff --git a/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/__init__.py b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/__init__.py new file mode 100644 index 000000000000..669bde9bf079 --- /dev/null +++ b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/__init__.py @@ -0,0 +1,3 @@ +from .m1 import foo +from pkg1.pkg2 import bar +from .pkg3 import foo2 \ No newline at end of file diff --git a/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/m1.py b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/m1.py new file mode 100644 index 000000000000..c4e5bcc8001f --- /dev/null +++ b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/m1.py @@ -0,0 +1 @@ +foo = 1 diff --git a/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg2/__init__.py b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg2/__init__.py new file mode 100644 index 000000000000..fbd64a6abc75 --- /dev/null +++ b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg2/__init__.py @@ -0,0 +1 @@ +bar = 1 diff --git a/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg3/__init__.py b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg3/__init__.py new file mode 100644 index 000000000000..4f0d6fe821dd --- /dev/null +++ b/python/testData/completion/implicitImportsInsidePackagePy2/pkg1/pkg3/__init__.py @@ -0,0 +1 @@ +foo2 = 0 diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index 6e00964aa9e4..b9532337aa16 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -1255,14 +1255,25 @@ public class PythonCompletionTest extends PyTestCase { assertContainsElements(suggested, "__init__(self)"); } - //PY-28461 + // PY-28461 public void testImplicitImportsInsidePackage() { + runWithLanguageLevel(LanguageLevel.PYTHON37, + () -> doMultiFileAssertSameElements("m1", "pkg2", "pkg3", "bar", "foo", "foo2")); + } + + // PY-28461 + public void testImplicitImportsInsidePackagePy2() { + runWithLanguageLevel(LanguageLevel.PYTHON27, + () -> doMultiFileAssertSameElements("m1", "pkg2", "pkg3", "bar", "foo", "foo2")); + } + + private void doMultiFileAssertSameElements(String... variants) { myFixture.copyDirectoryToProject(getTestName(true), ""); myFixture.configureByFile("a.py"); myFixture.completeBasic(); final List suggested = myFixture.getLookupElementStrings(); assertNotNull(suggested); - assertSameElements(suggested, "m1", "pkg2", "pkg3", "bar", "foo", "foo2"); + assertSameElements(suggested, variants); } @Override