mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
PY-77940 Allow resolving underscored names in .pyi stubs
This reverts the changes made in eb733982acf0992fbae822d0feb582fb07ad010f for PY-40233. The original problem was PyShadowingBuiltinsInspection erroneously reporting redefining private names declared in builtins.pyi, such as _T, however, resolving underscored names from all .pyi stubs was prohibited to fix that. These are considered "stub-only objects" according to the typing spec (https://typing.readthedocs.io/en/latest/guides/writing_stubs.html#stub-only-objects), but it doesn't prohibit reusing them in other stubs and in .py files under an `if typing.TYPE_CHECKING:` guard. Besides, both Mypy and Pyright resolve such names imported from .pyi stubs without warnings, so it doesn't make sense to enforce additional visibility restrictions from our side. Also, I enabled completing such names in other .pyi stubs (but not in .py files). Previously, in PY-38172 their completion was disabled everywhere. GitOrigin-RevId: 8340d4dcaf732d18d481bbee824ffdddd2719d3d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
300099d359
commit
820da7c49c
@@ -2007,9 +2007,11 @@ public abstract class PythonCommonCompletionTest extends PythonCommonTestCase {
|
||||
}
|
||||
|
||||
// PY-38172
|
||||
public void testNoPrivateStubElementsInModuleCompletion() {
|
||||
PsiFile file = myFixture.configureByText(PythonFileType.INSTANCE, "import collections\n" +
|
||||
"collections.<caret>");
|
||||
public void testNoPrivateStubElementsInCompletionForCollectionsModule() {
|
||||
PsiFile file = myFixture.configureByText(PythonFileType.INSTANCE, """
|
||||
import collections
|
||||
collections.<caret>
|
||||
""");
|
||||
myFixture.completeBasic();
|
||||
List<String> suggested = myFixture.getLookupElementStrings();
|
||||
assertNotEmpty(suggested);
|
||||
@@ -2018,6 +2020,19 @@ public abstract class PythonCommonCompletionTest extends PythonCommonTestCase {
|
||||
assertSdkRootsNotParsed(file);
|
||||
}
|
||||
|
||||
// PY-38172
|
||||
public void testPrivateStubElementsNotSuggestedInPyFiles() {
|
||||
doMultiFileTest();
|
||||
}
|
||||
|
||||
// PY-38172
|
||||
public void testPrivateStubElementsSuggestedInOtherPyiStubs() {
|
||||
myFixture.copyDirectoryToProject(getTestName(true), "");
|
||||
myFixture.configureByFile("a.pyi");
|
||||
myFixture.complete(CompletionType.BASIC, 1);
|
||||
myFixture.checkResultByFile(getTestName(true) + "/a.after.pyi");
|
||||
}
|
||||
|
||||
// PY-42520
|
||||
public void testNoRepeatingNamedArgs() {
|
||||
runWithLanguageLevel(
|
||||
|
||||
@@ -152,7 +152,7 @@ public final class PyShadowingBuiltinsInspection extends PyInspection {
|
||||
return;
|
||||
}
|
||||
final String name = element.getName();
|
||||
if (name != null && !myIgnoredNames.contains(name)) {
|
||||
if (name != null && PyUtil.getInitialUnderscores(name) != 1 && !myIgnoredNames.contains(name)) {
|
||||
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element);
|
||||
final PsiElement builtin = builtinCache.getByName(name);
|
||||
if (builtin != null && !PyUtil.inSameFile(builtin, element)) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.AccessDirection;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyQualifiedExpression;
|
||||
import com.jetbrains.python.psi.PyUtil;
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
@@ -57,7 +58,7 @@ public final class PythonBuiltinReferenceResolveProvider implements PyReferenceR
|
||||
|
||||
// ...as a builtin symbol
|
||||
final PyFile builtinsFile = builtinCache.getBuiltinsFile();
|
||||
if (builtinsFile != null) {
|
||||
if (builtinsFile != null && !PyUtil.isClassPrivateName(referencedName) && PyUtil.getInitialUnderscores(referencedName) != 1) {
|
||||
for (RatedResolveResult resolveResult : builtinsFile.multiResolveName(referencedName)) {
|
||||
result.add(new ImportedResolveResult(resolveResult.getElement(), resolveResult.getRate(), null));
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ class PyiFile(viewProvider: FileViewProvider) : PyFileImpl(viewProvider, PyiLang
|
||||
|
||||
override fun multiResolveName(name: String, exported: Boolean): List<RatedResolveResult> {
|
||||
if (name == "function" && PyBuiltinCache.getInstance(this).builtinsFile == this) return emptyList()
|
||||
if (exported && isPrivateName(name)) return emptyList()
|
||||
|
||||
val baseResults = super.multiResolveName(name, exported)
|
||||
val dunderAll = dunderAll ?: emptyList()
|
||||
@@ -55,10 +54,17 @@ class PyiFile(viewProvider: FileViewProvider) : PyFileImpl(viewProvider, PyiLang
|
||||
lastParent: PsiElement?,
|
||||
place: PsiElement): Boolean {
|
||||
val dunderAll = dunderAll ?: emptyList()
|
||||
val completingInPyiStub = PyiUtil.isInsideStub(place)
|
||||
val wrapper = object : DelegatingScopeProcessor(processor) {
|
||||
override fun execute(element: PsiElement, state: ResolveState): Boolean = when {
|
||||
// According to the typing spec, underscored names in .pyi stubs should be considered
|
||||
// "stub-only" objects (https://typing.readthedocs.io/en/latest/guides/writing_stubs.html#stub-only-objects).
|
||||
// However, they can still be re-used between .pyi stubs and imported in .py files under typing.TYPE_CHECKING.
|
||||
// Also, they can point to some inadvertently exposed de-facto API of some .py module.
|
||||
// Therefore, we do allow resolving such names, but don't suggest them among completion variants
|
||||
// to avoid polluting the lookup with internal names like "_T", "_Ts", etc.
|
||||
!completingInPyiStub && element is PsiNamedElement && isPrivateName(element.name) -> true
|
||||
isPrivateImport(element, dunderAll) -> true
|
||||
element is PsiNamedElement && isPrivateName(element.name) -> true
|
||||
else -> super.execute(element, state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from _common import _Place<caret>
|
||||
@@ -0,0 +1,4 @@
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from _common import _Place<caret>
|
||||
@@ -0,0 +1,3 @@
|
||||
from typing import TypeAlias
|
||||
|
||||
_Placeholder: TypeAlias = int
|
||||
@@ -0,0 +1 @@
|
||||
from common import _Placeholder
|
||||
@@ -0,0 +1 @@
|
||||
from common import _Place<caret>
|
||||
@@ -0,0 +1,3 @@
|
||||
from typing import TypeAlias
|
||||
|
||||
_Placeholder: TypeAlias = int
|
||||
@@ -0,0 +1,4 @@
|
||||
from common import _Placeholder
|
||||
|
||||
x: _Placeholder
|
||||
# <ref>
|
||||
4
python/testData/pyi/resolve/underscoredName/common.pyi
Normal file
4
python/testData/pyi/resolve/underscoredName/common.pyi
Normal file
@@ -0,0 +1,4 @@
|
||||
from typing import TypeAlias
|
||||
|
||||
|
||||
_Placeholder: TypeAlias = int
|
||||
@@ -0,0 +1,4 @@
|
||||
from typing import TypeAlias
|
||||
|
||||
|
||||
_Placeholder: TypeAlias = int
|
||||
4
python/testData/types/UnderscoredNameInPyiStub/lib.pyi
Normal file
4
python/testData/types/UnderscoredNameInPyiStub/lib.pyi
Normal file
@@ -0,0 +1,4 @@
|
||||
from common import _Placeholder
|
||||
|
||||
|
||||
def f() -> _Placeholder: ...
|
||||
@@ -6214,6 +6214,15 @@ public class PyTypingTest extends PyTestCase {
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-77940
|
||||
public void testUnderscoredNameInPyiStub() {
|
||||
doMultiFileStubAwareTest("int", """
|
||||
from lib import f
|
||||
|
||||
expr = f()
|
||||
""");
|
||||
}
|
||||
|
||||
private void doTestNoInjectedText(@NotNull String text) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());
|
||||
|
||||
@@ -81,4 +81,9 @@ public class PyiResolveTest extends PyMultiFileResolveTestCase {
|
||||
QualifiedName internalCanonicalImportPath = QualifiedNameFinder.findCanonicalImportPath(internalClass, null);
|
||||
assertEquals(QualifiedName.fromDottedString("pkg.mod"), internalCanonicalImportPath);
|
||||
}
|
||||
|
||||
// PY-77940
|
||||
public void testUnderscoredName() {
|
||||
assertResolvesTo(PyTargetExpression.class, "_Placeholder");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user