From 6f9013eb6b5624fe1e5a6ddaa67746293d7cf6b1 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 19 Feb 2021 14:43:10 +0300 Subject: [PATCH] PY-47281 Exclude names from internal modules of libraries from auto-importing Namely, names such as "numpy.random._examples.numba.extending.numbacall" or "numpy.testing._private.noseclasses.NumpyDoctest" should no longer be suggested, unless they are also exported in a public package higher in the hierarchy. It doesn't not affect definitions from internal modules that belong to project sources, these are still offered in the lookup. GitOrigin-RevId: 2be393f30bd7d9905a31bdbe8db101807c136617 --- .../PyQualifiedNameCompletionMatcher.java | 5 ++++ .../python_stubs/mypackage/__init__.py | 0 .../python_stubs/mypackage/_impl.py | 6 ++++ .../site-packages/mypackage/__init__.py | 1 + .../src/main.py | 1 + .../src/mypackage_util/_impl.py | 2 ++ .../site-packages/mypackage/__init__.py | 1 + .../site-packages/mypackage/_impl.py | 6 ++++ .../mypackage/_vendor/__init__.py | 0 .../site-packages/mypackage/_vendor/lib.py | 2 ++ .../src/main.py | 1 + .../src/mypackage_util/_impl.py | 2 ++ ...otImportedQualifiedNameCompletionTest.java | 29 +++++++++++++++++++ 13 files changed, 56 insertions(+) create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/python_stubs/mypackage/__init__.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/python_stubs/mypackage/_impl.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/site-packages/mypackage/__init__.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/main.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/mypackage_util/_impl.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/__init__.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_impl.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_vendor/__init__.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_vendor/lib.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/main.py create mode 100644 python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/mypackage_util/_impl.py diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyQualifiedNameCompletionMatcher.java b/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyQualifiedNameCompletionMatcher.java index d9f999d3af74..f7cf6414d8e2 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyQualifiedNameCompletionMatcher.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/stubs/PyQualifiedNameCompletionMatcher.java @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubs.StubIndex; import com.intellij.psi.util.QualifiedName; @@ -41,6 +42,7 @@ public class PyQualifiedNameCompletionMatcher { QualifiedNameMatcher matcher = new QualifiedNameMatcher(qualifiedNamePattern); StubIndex stubIndex = StubIndex.getInstance(); Project project = Objects.requireNonNull(scope.getProject()); + PsiManager psiManager = PsiManager.getInstance(project); GlobalSearchScope moduleMatchingScope = scope.intersectWith(new ModuleQualifiedNameMatchingScope(matcher, project)); Set alreadySuggestedAttributes = new HashSet<>(); @@ -66,6 +68,9 @@ public class PyQualifiedNameCompletionMatcher { else { importPath = moduleQualifiedName; } + if (ContainerUtil.exists(importPath.getComponents(), c -> c.startsWith("_")) && !psiManager.isInProject(element)) { + return true; + } QualifiedName attributeQualifiedName = importPath.append(attributeName); if (alreadySuggestedAttributes.add(attributeQualifiedName)) { if (!processor.process(new ExportedName(attributeQualifiedName, originallyTypedAlias, element))) { diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/python_stubs/mypackage/__init__.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/python_stubs/mypackage/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/python_stubs/mypackage/_impl.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/python_stubs/mypackage/_impl.py new file mode 100644 index 000000000000..2609413403d8 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/python_stubs/mypackage/_impl.py @@ -0,0 +1,6 @@ +def func_exported(): + pass + + +def func(): + pass diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/site-packages/mypackage/__init__.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/site-packages/mypackage/__init__.py new file mode 100644 index 000000000000..3b6f5772854d --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/site-packages/mypackage/__init__.py @@ -0,0 +1 @@ +from ._impl import func_exported diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/main.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/main.py new file mode 100644 index 000000000000..295a59659c49 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/main.py @@ -0,0 +1 @@ +mypa.fu \ No newline at end of file diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/mypackage_util/_impl.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/mypackage_util/_impl.py new file mode 100644 index 000000000000..b9bfa6f12339 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalSkeletonsExcludedUnlessExported/src/mypackage_util/_impl.py @@ -0,0 +1,2 @@ +def func(): + pass diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/__init__.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/__init__.py new file mode 100644 index 000000000000..3b6f5772854d --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/__init__.py @@ -0,0 +1 @@ +from ._impl import func_exported diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_impl.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_impl.py new file mode 100644 index 000000000000..2609413403d8 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_impl.py @@ -0,0 +1,6 @@ +def func_exported(): + pass + + +def func(): + pass diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_vendor/__init__.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_vendor/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_vendor/lib.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_vendor/lib.py new file mode 100644 index 000000000000..b9bfa6f12339 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/site-packages/mypackage/_vendor/lib.py @@ -0,0 +1,2 @@ +def func(): + pass diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/main.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/main.py new file mode 100644 index 000000000000..d140b0a9b7e3 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/main.py @@ -0,0 +1 @@ +mypack.fun diff --git a/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/mypackage_util/_impl.py b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/mypackage_util/_impl.py new file mode 100644 index 000000000000..b9bfa6f12339 --- /dev/null +++ b/python/testData/completion/notImportedQualifiedName/VariantsFromInternalThirdPartyModulesExcludedUnlessExported/src/mypackage_util/_impl.py @@ -0,0 +1,2 @@ +def func(): + pass diff --git a/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java b/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java index 68d10ce71342..eba87c58750b 100644 --- a/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PyNotImportedQualifiedNameCompletionTest.java @@ -28,6 +28,35 @@ public class PyNotImportedQualifiedNameCompletionTest extends PyTestCase { assertContainsElements(variants, "bar.func", "bar.func1"); } + // PY-47281 + public void testVariantsFromInternalThirdPartyModulesExcludedUnlessExported() { + runWithAdditionalClassEntryInSdkRoots(getTestName(false) + "/site-packages", () -> { + myFixture.copyDirectoryToProject(getTestName(false) + "/src", ""); + myFixture.configureByFile("main.py"); + myFixture.completeBasic(); + List variants = myFixture.getLookupElementStrings(); + assertNotNull(variants); + assertDoesntContain(variants, "mypackage._impl.func", "mypackage._vendor.lib.func"); + assertContainsElements(variants, "mypackage.func_exported", "mypackage_util._impl.func"); + }); + } + + // PY-47281 + public void testVariantsFromInternalSkeletonsExcludedUnlessExported() { + String testName = getTestName(false); + runWithAdditionalClassEntryInSdkRoots(testName + "/site-packages", () -> { + runWithAdditionalClassEntryInSdkRoots(testName + "/python_stubs", () -> { + myFixture.copyDirectoryToProject(testName + "/src", ""); + myFixture.configureByFile("main.py"); + myFixture.completeBasic(); + List variants = myFixture.getLookupElementStrings(); + assertNotNull(variants); + assertDoesntContain(variants, "mypackage._impl.func"); + assertContainsElements(variants, "mypackage.func_exported", "mypackage_util._impl.func"); + }); + }); + } + public void testQualifiedNameMatcherTest() { QualifiedNameMatcher matcher = new QualifiedNameMatcher(QualifiedName.fromDottedString("foo.bar.baz")); assertTrue(matcher.prefixMatches("foo.bar.baz"));