From 559ae9730ba3dab1305cdbaf2c29786ff38d740d Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 17 Oct 2024 16:51:50 -0400 Subject: [PATCH] Restore os.path methods overload workaround (#12837) Revert "Remove obsolete mypy bug workaround in `abspath()` (#12208)" This reverts commit 271df8ef040500e3dc4d3ca6be50eea7bd07bc62. --- stdlib/@tests/test_cases/check_os_path.py | 57 +++++++++++++++++++++++ stdlib/posixpath.pyi | 16 +++++-- 2 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 stdlib/@tests/test_cases/check_os_path.py diff --git a/stdlib/@tests/test_cases/check_os_path.py b/stdlib/@tests/test_cases/check_os_path.py new file mode 100644 index 000000000..aeec873fb --- /dev/null +++ b/stdlib/@tests/test_cases/check_os_path.py @@ -0,0 +1,57 @@ +from __future__ import annotations +from _typeshed import StrOrBytesPath +from os import PathLike +from os.path import abspath, expanduser, expandvars +from typing_extensions import assert_type +from typing import AnyStr, Union + + +def test_str_path(str_path: StrOrBytesPath) -> None: + # These methods are currently overloaded to work around python/mypy#17952 & python/mypy#11880 + # Let's ensure that they'll still work with a StrOrBytesPath if the workaround is removed + + assert_type(abspath(str_path), Union[str, bytes]) + assert_type(expanduser(str_path), Union[str, bytes]) + assert_type(expandvars(str_path), Union[str, bytes]) + + +# See python/mypy#17952 +class MyPathMissingGeneric(PathLike): # type: ignore # Explicitly testing w/ missing type argument + def __init__(self, path: str | bytes) -> None: + super().__init__() + self.path = path + + def __fspath__(self) -> str | bytes: + return self.path + + +# MyPathMissingGeneric could also be fixed by users by adding the missing generic annotation +class MyPathGeneric(PathLike[AnyStr]): + def __init__(self, path: AnyStr) -> None: + super().__init__() + self.path: AnyStr = path + + def __fspath__(self) -> AnyStr: + return self.path + + +class MyPathStr(PathLike[str]): + def __init__(self, path: str) -> None: + super().__init__() + self.path = path + + def __fspath__(self) -> str: + return self.path + + +abspath(MyPathMissingGeneric(".")) +expanduser(MyPathMissingGeneric(".")) +expandvars(MyPathMissingGeneric(".")) + +abspath(MyPathGeneric(".")) +expanduser(MyPathGeneric(".")) +expandvars(MyPathGeneric(".")) + +abspath(MyPathStr(".")) +expanduser(MyPathStr(".")) +expandvars(MyPathStr(".")) diff --git a/stdlib/posixpath.pyi b/stdlib/posixpath.pyi index 31406f8df..3313667f1 100644 --- a/stdlib/posixpath.pyi +++ b/stdlib/posixpath.pyi @@ -77,7 +77,11 @@ pathsep: LiteralString defpath: LiteralString devnull: LiteralString -def abspath(path: PathLike[AnyStr] | AnyStr) -> AnyStr: ... +# Overloads are necessary to work around python/mypy#17952 & python/mypy#11880 +@overload +def abspath(path: PathLike[AnyStr]) -> AnyStr: ... +@overload +def abspath(path: AnyStr) -> AnyStr: ... @overload def basename(p: PathLike[AnyStr]) -> AnyStr: ... @overload @@ -86,8 +90,14 @@ def basename(p: AnyOrLiteralStr) -> AnyOrLiteralStr: ... def dirname(p: PathLike[AnyStr]) -> AnyStr: ... @overload def dirname(p: AnyOrLiteralStr) -> AnyOrLiteralStr: ... -def expanduser(path: PathLike[AnyStr] | AnyStr) -> AnyStr: ... -def expandvars(path: PathLike[AnyStr] | AnyStr) -> AnyStr: ... +@overload +def expanduser(path: PathLike[AnyStr]) -> AnyStr: ... +@overload +def expanduser(path: AnyStr) -> AnyStr: ... +@overload +def expandvars(path: PathLike[AnyStr]) -> AnyStr: ... +@overload +def expandvars(path: AnyStr) -> AnyStr: ... @overload def normcase(s: PathLike[AnyStr]) -> AnyStr: ... @overload