From ed160cbeebe45b5dc85c545e5d9f05ac078e395b Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Wed, 10 Jun 2020 23:27:22 +0300 Subject: [PATCH] Provide type for `pathlib._PurePathBase` until PY-34617 is fixed (PY-30747) GitOrigin-RevId: 25a707348036715ebb67280ea650a298cf882f4e --- .../stdlib/PyStdlibTypeProvider.java | 30 +++++++++++++++++++ .../Py3TypeCheckerInspectionTest.java | 16 ++++++++++ 2 files changed, 46 insertions(+) diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 61dbc8a4c6f4..7190d65876c8 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -50,6 +51,10 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { if (type != null) { return Ref.create(type); } + type = getPathlibPurePathBaseType(referenceTarget); + if (type != null) { + return Ref.create(type); + } return null; } @@ -129,6 +134,31 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { return null; } + @Nullable + private static PyType getPathlibPurePathBaseType(@NotNull PsiElement referenceTarget) { + if (referenceTarget instanceof PyTargetExpression && + "pathlib._PurePathBase".equals(((PyTargetExpression)referenceTarget).getQualifiedName())) { + final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(referenceTarget); + + if (LanguageLevel.forElement(referenceTarget).isOlderThan(LanguageLevel.PYTHON36)) { + final PyClassType objectType = builtinCache.getObjectType(); + if (objectType != null) { + return objectType.toClass(); + } + } + + final PyClassType pathLikeType = builtinCache.getObjectType(PyNames.BUILTIN_PATH_LIKE); + final PyClassType strType = builtinCache.getStrType(); + if (pathLikeType != null) { + return strType == null + ? pathLikeType.toClass() + : new PyCollectionTypeImpl(pathLikeType.getPyClass(), true, Collections.singletonList(strType)); + } + } + + return null; + } + @Nullable @Override public Ref getCallType(@NotNull PyFunction function, @NotNull PyCallSiteExpression callSite, @NotNull TypeEvalContext context) { diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java index 37aeef4071de..4a20b27630ef 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java @@ -418,4 +418,20 @@ public class Py3TypeCheckerInspectionTest extends PyInspectionTestCase { public void testParametrizedBuiltinTypeAndTypingTypeAreEquivalent() { doTest(); } + + // PY-30747 + public void testPathlibPathMatchingOsPathLike() { + doTestByText( + "import pathlib\n" + + "import os\n" + + "\n" + + "def foo(p: pathlib.Path):\n" + + " with open(p) as file:\n" + + " pass\n" + + "\n" + + "p1: pathlib.Path\n" + + "p2: os.PathLike[bytes] = p1 # false negative, see PyTypeChecker.matchGenerics\n" + + "p3: os.PathLike[str] = p1" + ); + } }