diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index 19f247d4a4bf..0aaa054c8b6c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -15,16 +15,17 @@ */ package com.jetbrains.python.psi.types; +import com.google.common.collect.Sets; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileSystemItem; import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; -import com.jetbrains.python.psi.AccessDirection; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.psi.PyUtil; +import com.intellij.util.containers.ContainerUtil; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.resolve.PointInImport; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -36,6 +37,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; /** * @author yole @@ -57,6 +59,20 @@ public class PyImportedModuleType implements PyType { if (resolved != null) { final PsiFile containingFile = location != null ? location.getContainingFile() : null; List elements = Collections.singletonList(ResolveImportUtil.resolveChild(resolved, name, containingFile, false, true)); + final PyImportElement importElement = myImportedModule.getImportElement(); + if (location != null && importElement != null && PyUtil.inSameFile(location, importElement) && + ResolveImportUtil.getPointInImport(location) == PointInImport.NONE && resolved instanceof PsiFileSystemItem) { + final List importedSubmodules = PyModuleType.collectImportedSubmodules((PsiFileSystemItem)resolved, location); + if (importedSubmodules != null) { + final Set imported = Sets.newHashSet(importedSubmodules); + elements = ContainerUtil.filter(elements, new Condition() { + @Override + public boolean value(PsiElement element) { + return imported.contains(element); + } + }); + } + } return ResolveImportUtil.rateResults(elements); } return null; diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index cd642a6910cf..d057b70c6ed3 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -388,7 +388,8 @@ public class PyModuleType implements PyType { // Modules don't descend from obje @NotNull PsiElement location, @Nullable final Set existingNames) { - return ContainerUtil.mapNotNull(collectImportedSubmodules(pyPackage, location), + final List elements = collectImportedSubmodules(pyPackage, location); + return elements != null ? ContainerUtil.mapNotNull(elements, new Function() { @Override public LookupElement fun(PsiElement element) { @@ -400,10 +401,10 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } return null; } - }); + }) : Collections.emptyList(); } - @NotNull + @Nullable public static List collectImportedSubmodules(@NotNull PsiFileSystemItem pyPackage, @NotNull PsiElement location) { final PsiElement parentAnchor; if (pyPackage instanceof PyFile && PyUtil.isPackage(((PyFile)pyPackage))) { @@ -413,7 +414,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje parentAnchor = pyPackage; } else { - throw new IllegalArgumentException("Package argument should be either standard Python package or namespace package"); + return null; } final ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(location); diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/a.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/a.py deleted file mode 100644 index 6de874dee44a..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/a.py +++ /dev/null @@ -1,5 +0,0 @@ -import pkg1.m1 - -print(pkg1.m2) -print(pkg1.nonexistent) - diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/__init__.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/__init__.py deleted file mode 100644 index 8b137891791f..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m1.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m1.py deleted file mode 100644 index 123f7cbbfd9d..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m1.py +++ /dev/null @@ -1 +0,0 @@ -import pkg1.m2 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m2.py b/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m2.py deleted file mode 100644 index 8b137891791f..000000000000 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/ImplicitlyImportedSubModule/pkg1/m2.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/main.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/main.py new file mode 100644 index 000000000000..54e2273f4550 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/main.py @@ -0,0 +1,5 @@ +import nspkg1.m2 + +print(nspkg1.m2) +print(nspkg1.m3) +print(nspkg1.nssubpkg1) diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m2.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m2.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m3.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/m3.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/nssubpkg1/m1.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/NotImportedSubmodulesOfNamespacePackage/nspkg1/nssubpkg1/m1.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/p1/__init__.py b/python/testData/inspections/unusedImport/unusedSubmodule/p1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/p1/m1.py b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m1.py new file mode 100644 index 000000000000..a43e3eb876c1 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m1.py @@ -0,0 +1 @@ +a1 = 42 \ No newline at end of file diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/p1/m2.py b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m2.py new file mode 100644 index 000000000000..97f0eb4ade34 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedSubmodule/p1/m2.py @@ -0,0 +1 @@ +a2 = -1 \ No newline at end of file diff --git a/python/testData/inspections/unusedImport/unusedSubmodule/test1.py b/python/testData/inspections/unusedImport/unusedSubmodule/test1.py new file mode 100644 index 000000000000..40e9e79d3ac1 --- /dev/null +++ b/python/testData/inspections/unusedImport/unusedSubmodule/test1.py @@ -0,0 +1,3 @@ +import p1.m1 + +print(p1.m2.a2) diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java index 9cdac1dd034b..1a29300f947d 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java @@ -112,6 +112,11 @@ public class Py3UnresolvedReferencesInspectionTest extends PyTestCase { doTest(); } + // PY-14385 + public void testNotImportedSubmodulesOfNamespacePackage() { + doMultiFileTest("main.py"); + } + // PY-15017 public void testClassLevelReferenceInMethodAnnotation() { doTest(); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 6e0c1b333f7a..59a93465d995 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -510,10 +510,7 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doTest(); } - // PY-14615 - public void testImplicitlyImportedSubModule() { - doMultiFileTest(); - } + @NotNull @Override diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java index 1ce20f386adf..018d75e8fbde 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnusedImportTest.java @@ -38,6 +38,11 @@ public class PyUnusedImportTest extends PyTestCase { doTest("test1.py"); } + // PY-5621 + public void testUnusedSubmodule() { + doTest("test1.py"); + } + // PY-6380 public void testUnusedAfterStarImport() { doTest("test1.py");