Enable PEP-561 support for all Python versions (PY-32283)

See https://github.com/python/peps/pull/415#issuecomment-432522008
This commit is contained in:
Semyon Proshev
2018-10-29 09:27:26 +03:00
parent b805662ad0
commit bd6dd003ec
7 changed files with 72 additions and 125 deletions
@@ -1,7 +1,6 @@
<html>
<body>
Advertises stub packages.
Supports Python 3.7 and later.
<p>
Stub package is a package that contains type information for the corresponding runtime package.
See <a href="https://www.python.org/dev/peps/pep-0561/">PEP 561</a> for more details.
@@ -1,7 +1,6 @@
<html>
<body>
Checks that a stub package supports the version of the corresponding runtime package.
Supports Python 3.7 and later.
<p>
Stub package is a package that contains type information for some runtime package.
See <a href="https://www.python.org/dev/peps/pep-0561/">PEP 561</a> for more details.
@@ -15,7 +15,6 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.util.QualifiedName
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.psi.PyFile
import com.jetbrains.python.psi.PyUtil
import com.jetbrains.python.psi.resolve.RatedResolveResult
@@ -43,23 +42,18 @@ fun convertStubToRuntimePackageName(name: QualifiedName): QualifiedName {
/**
* Returns stub package directory in the specified [dir] for the package with [referencedName] as a name.
*
* Requires language level to be at least [LanguageLevel.PYTHON37], [withoutStubs] to be False, [dir] to be lib root.
* Requires [withoutStubs] to be False and [dir] to be lib root.
*/
fun findStubPackage(containingFile: PsiFile?,
dir: PsiDirectory,
fun findStubPackage(dir: PsiDirectory,
referencedName: String,
checkForPackage: Boolean,
withoutStubs: Boolean): PsiDirectory? {
// check that stub packages are allowed and dir is lib root
if (!withoutStubs &&
containingFile != null &&
LanguageLevel.forElement(containingFile).isAtLeast(LanguageLevel.PYTHON37) &&
dir.virtualFile.let { it == getClassOrContentOrSourceRoot(containingFile.project, it) }) {
if (!withoutStubs && dir.virtualFile.let { it == getClassOrContentOrSourceRoot(dir.project, it) }) {
val stubPackageName = "$referencedName$STUBS_SUFFIX"
val stubPackage = dir.findSubdirectory(stubPackageName)
// see comment about case sensitivity in com.jetbrains.python.psi.resolve.ResolveImportUtil.resolveInDirectory
if (stubPackage?.name == stubPackageName && (!checkForPackage || PyUtil.isPackage(stubPackage, containingFile))) {
if (stubPackage?.name == stubPackageName && (!checkForPackage || PyUtil.isPackage(stubPackage, dir))) {
stubPackage.putUserData(STUB_PACKAGE_KEY, true)
return stubPackage
}
@@ -191,10 +185,7 @@ private fun isInInlinePackage(element: PsiElement, module: Module?): Boolean {
val cached = element.getUserData(INLINE_PACKAGE_KEY)
if (cached != null) return cached
val result = !pyi(element) &&
(element is PyFile || PyUtil.turnDirIntoInit(element) is PyFile) &&
PyUtil.getLanguageLevelForModule(module).isAtLeast(LanguageLevel.PYTHON37) &&
getPyTyped(element) != null
val result = !pyi(element) && (element is PyFile || PyUtil.turnDirIntoInit(element) is PyFile) && getPyTyped(element) != null
element.putUserData(INLINE_PACKAGE_KEY, result)
return result
@@ -24,7 +24,6 @@ import com.jetbrains.python.inspections.PyInspectionVisitor
import com.jetbrains.python.inspections.PyPackageRequirementsInspection.PyInstallRequirementsFix
import com.jetbrains.python.packaging.*
import com.jetbrains.python.packaging.requirement.PyRequirementRelation
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.psi.PyFile
import com.jetbrains.python.psi.impl.PyPsiUtils
import com.jetbrains.python.sdk.PythonSdkType
@@ -55,8 +54,6 @@ class PyStubPackagesAdvertiser : PyInspection() {
session: LocalInspectionToolSession) : PyInspectionVisitor(holder, session) {
override fun visitPyFile(node: PyFile) {
if (node.languageLevel.isOlderThan(LanguageLevel.PYTHON37)) return
val module = ModuleUtilCore.findModuleForFile(node) ?: return
val sdk = PythonSdkType.findPythonSdk(module) ?: return
@@ -19,7 +19,6 @@ import com.jetbrains.python.inspections.PyInterpreterInspection
import com.jetbrains.python.packaging.PyPackage
import com.jetbrains.python.packaging.PyPackageManager
import com.jetbrains.python.packaging.requirement.PyRequirementRelation
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.psi.PyFile
import com.jetbrains.python.sdk.PythonSdkType
import javax.swing.JComponent
@@ -65,8 +64,6 @@ class PyStubPackagesCompatibilityInspection : PyInspection() {
session: LocalInspectionToolSession) : PyInspectionVisitor(holder, session) {
override fun visitPyFile(node: PyFile) {
if (node.languageLevel.isOlderThan(LanguageLevel.PYTHON37)) return
val module = ModuleUtilCore.findModuleForFile(node) ?: return
val sdk = PythonSdkType.findPythonSdk(module) ?: return
@@ -382,7 +382,7 @@ public class ResolveImportUtil {
final PsiDirectory subdir = dir.findSubdirectory(referencedName);
// VFS may be case insensitive on Windows, but resolve is always case sensitive (PEP 235, PY-18958), so we check name here
if (subdir != null && subdir.getName().equals(referencedName) && (!checkForPackage || PyUtil.isPackage(subdir, containingFile))) {
final PsiDirectory stubPackage = PyStubPackages.findStubPackage(containingFile, dir, referencedName, checkForPackage, withoutStubs);
final PsiDirectory stubPackage = PyStubPackages.findStubPackage(dir, referencedName, checkForPackage, withoutStubs);
if (stubPackage == null || PyStubPackages.stubPackageIsPartial(stubPackage)) {
result.add(new RatedResolveResult(RatedResolveResult.RATE_NORMAL, PyStubPackages.transferStubPackageMarker(dir, subdir)));
@@ -394,7 +394,7 @@ public class ResolveImportUtil {
}
if (subdir == null) {
final PsiDirectory stubPackage = PyStubPackages.findStubPackage(containingFile, dir, referencedName, checkForPackage, withoutStubs);
final PsiDirectory stubPackage = PyStubPackages.findStubPackage(dir, referencedName, checkForPackage, withoutStubs);
if (stubPackage != null) {
result.add(new RatedResolveResult(RatedResolveResult.RATE_NORMAL, stubPackage));
}
@@ -675,20 +675,16 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
final PsiFile file = element.getContainingFile();
assertEquals("foo.py", file.getName());
assertEquals("src", file.getParent().getParent().getName());
}
)
final PsiFile file = element.getContainingFile();
assertEquals("foo.py", file.getName());
assertEquals("src", file.getParent().getParent().getName());
}
);
}
@@ -700,19 +696,15 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
final PsiFile file = element.getContainingFile();
assertEquals("foo.pyi", file.getName());
assertEquals("pkg-stubs", file.getParent().getName());
}
)
final PsiFile file = element.getContainingFile();
assertEquals("foo.pyi", file.getName());
assertEquals("pkg-stubs", file.getParent().getName());
}
);
}
@@ -724,20 +716,16 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
final PsiFile file = element.getContainingFile();
assertEquals("foo.pyi", file.getName());
assertEquals("pkg-stubs", file.getParent().getName());
}
)
final PsiFile file = element.getContainingFile();
assertEquals("foo.pyi", file.getName());
assertEquals("pkg-stubs", file.getParent().getName());
}
);
}
@@ -749,17 +737,13 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
assertEquals("process.py", element.getContainingFile().getName());
}
)
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
assertEquals("process.py", element.getContainingFile().getName());
}
);
}
@@ -776,17 +760,13 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
assertEquals("foo.py", element.getContainingFile().getName());
}
)
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
assertEquals("foo.py", element.getContainingFile().getName());
}
);
}
@@ -798,23 +778,19 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiReference reference = PyResolveTestCase.findReferenceByMarker(myFixture.getFile());
assertInstanceOf(reference, PsiPolyVariantReference.class);
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> {
final PsiReference reference = PyResolveTestCase.findReferenceByMarker(myFixture.getFile());
assertInstanceOf(reference, PsiPolyVariantReference.class);
final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
assertSize(1, results);
final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
assertSize(1, results);
final PsiElement element = results[0].getElement();
assertInstanceOf(element, PyFunction.class);
assertEquals("foo.pyi", element.getContainingFile().getName());
}
)
final PsiElement element = results[0].getElement();
assertInstanceOf(element, PyFunction.class);
assertEquals("foo.pyi", element.getContainingFile().getName());
}
);
}
@@ -826,13 +802,9 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> assertNull(PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve())
)
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> assertNull(PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve())
);
}
@@ -844,13 +816,9 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile libDir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib");
assertNotNull(libDir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
() ->
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> assertNull(PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve())
)
runWithAdditionalClassEntryInSdkRoots(
libDir,
() -> assertNull(PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve())
);
}
@@ -865,20 +833,16 @@ public class Py3ResolveTest extends PyResolveTestCase {
final VirtualFile lib2Dir = StandardFileSystems.local().findFileByPath(getTestDataPath() + "/" + path + "/lib2");
assertNotNull(lib2Dir);
runWithLanguageLevel(
LanguageLevel.PYTHON37,
runWithAdditionalClassEntryInSdkRoots(
lib1Dir,
() ->
runWithAdditionalClassEntryInSdkRoots(
lib1Dir,
() ->
runWithAdditionalClassEntryInSdkRoots(
lib2Dir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
assertEquals("foo.pyi", element.getContainingFile().getName());
}
)
lib2Dir,
() -> {
final PsiElement element = PyResolveTestCase.findReferenceByMarker(myFixture.getFile()).resolve();
assertInstanceOf(element, PyFunction.class);
assertEquals("foo.pyi", element.getContainingFile().getName());
}
)
);
}