Skip to content

Commit

Permalink
Enable PEP-561 support for all Python versions (PY-32283)
Browse files Browse the repository at this point in the history
  • Loading branch information
sproshev committed Oct 29, 2018
1 parent b805662 commit bd6dd00
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 125 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ private static List<RatedResolveResult> resolveInDirectory(@NotNull final String
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)));
Expand All @@ -394,7 +394,7 @@ private static List<RatedResolveResult> resolveInDirectory(@NotNull final String
}

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));
}
Expand Down
166 changes: 65 additions & 101 deletions python/testSrc/com/jetbrains/python/Py3ResolveTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -675,20 +675,16 @@ public void testUserPyInsteadStubPackage() {
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());
}
);
}

Expand All @@ -700,19 +696,15 @@ public void testStubPackageInsteadInlinePackage() {
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());
}
);
}

Expand All @@ -724,20 +716,16 @@ public void testStubPackageInsteadInlinePackageFullyQName() {
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());
}
);
}

Expand All @@ -749,17 +737,13 @@ public void testInlinePackageInsteadTypeShed() {
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());
}
);
}

Expand All @@ -776,17 +760,13 @@ public void testInlinePackageInsteadPartialStubPackage() {
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());
}
);
}

Expand All @@ -798,23 +778,19 @@ public void testPartialStubPackageInsteadInlinePackage() {
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());
}
);
}

Expand All @@ -826,13 +802,9 @@ public void testNoInlinePackageInsteadStubPackage() {
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())
);
}

Expand All @@ -844,13 +816,9 @@ public void testNoInlinePackageInsteadStubPackageAnotherImport() {
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())
);
}

Expand All @@ -865,20 +833,16 @@ public void testStubPackageInOtherRoot() {
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());
}
)
);
}
Expand Down

0 comments on commit bd6dd00

Please sign in to comment.