Skip to content

Commit 268a2e7

Browse files
authored
Update pathlib for 3.14 (#14006)
1 parent 251570c commit 268a2e7

File tree

5 files changed

+59
-33
lines changed

5 files changed

+59
-33
lines changed

stdlib/@tests/stubtest_allowlists/py314.txt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,6 @@ multiprocessing.process.BaseProcess.interrupt
147147
multiprocessing.synchronize.SemLock.locked
148148
os.__all__
149149
os.readinto
150-
pathlib.Path.copy_into
151-
pathlib.Path.copytree
152-
pathlib.Path.delete
153-
pathlib.Path.info
154-
pathlib.Path.move
155-
pathlib.Path.move_into
156-
pathlib.Path.rmtree
157-
pathlib.PurePath.is_relative_to
158-
pathlib.PurePath.relative_to
159-
pathlib.types
160150
pdb.__all__
161151
pdb.Pdb.__init__
162152
pdb.Pdb.checkline

stdlib/@tests/test_cases/check_pathlib.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
from pathlib import Path, PureWindowsPath
55
from typing_extensions import assert_type
66

7+
8+
class MyCustomPath(Path): ...
9+
10+
711
if Path("asdf") == Path("asdf"):
812
...
913

@@ -23,8 +27,20 @@
2327

2428

2529
if sys.version_info >= (3, 13):
26-
27-
class MyCustomPath(Path): ...
28-
2930
pth = MyCustomPath.from_uri("file:///tmp/abc.txt")
3031
assert_type(pth, MyCustomPath)
32+
33+
34+
if sys.version_info >= (3, 14):
35+
pth = MyCustomPath("asdf")
36+
# With text path, type should be preserved.
37+
assert_type(pth.move_into("asdf"), MyCustomPath)
38+
assert_type(pth.move("asdf"), MyCustomPath)
39+
assert_type(pth.copy("asdf"), MyCustomPath)
40+
assert_type(pth.copy_into("asdf"), MyCustomPath)
41+
42+
# With an actual path type, that type should be preserved.
43+
assert_type(pth.move_into(Path("asdf")), Path)
44+
assert_type(pth.move(Path("asdf")), Path)
45+
assert_type(pth.copy(Path("asdf")), Path)
46+
assert_type(pth.copy_into(Path("asdf")), Path)

stdlib/VERSIONS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ os: 3.0-
228228
ossaudiodev: 3.0-3.12
229229
parser: 3.0-3.9
230230
pathlib: 3.4-
231+
pathlib.types: 3.14-
231232
pdb: 3.0-
232233
pickle: 3.0-
233234
pickletools: 3.0-

stdlib/pathlib.pyi renamed to stdlib/pathlib/__init__.pyi

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@ from collections.abc import Callable, Generator, Iterator, Sequence
1515
from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper
1616
from os import PathLike, stat_result
1717
from types import GenericAlias, TracebackType
18-
from typing import IO, Any, BinaryIO, ClassVar, Literal, overload
18+
from typing import IO, Any, BinaryIO, ClassVar, Literal, TypeVar, overload
1919
from typing_extensions import Never, Self, deprecated
2020

21+
_PathT = TypeVar("_PathT", bound=PurePath)
22+
2123
__all__ = ["PurePath", "PurePosixPath", "PureWindowsPath", "Path", "PosixPath", "WindowsPath"]
2224

25+
if sys.version_info >= (3, 14):
26+
from pathlib.types import PathInfo
27+
2328
if sys.version_info >= (3, 13):
2429
__all__ += ["UnsupportedOperation"]
2530

@@ -63,7 +68,9 @@ class PurePath(PathLike[str]):
6368
def as_uri(self) -> str: ...
6469
def is_absolute(self) -> bool: ...
6570
def is_reserved(self) -> bool: ...
66-
if sys.version_info >= (3, 12):
71+
if sys.version_info >= (3, 14):
72+
def is_relative_to(self, other: StrPath) -> bool: ...
73+
elif sys.version_info >= (3, 12):
6774
def is_relative_to(self, other: StrPath, /, *_deprecated: StrPath) -> bool: ...
6875
else:
6976
def is_relative_to(self, *other: StrPath) -> bool: ...
@@ -73,7 +80,9 @@ class PurePath(PathLike[str]):
7380
else:
7481
def match(self, path_pattern: str) -> bool: ...
7582

76-
if sys.version_info >= (3, 12):
83+
if sys.version_info >= (3, 14):
84+
def relative_to(self, other: StrPath, *, walk_up: bool = False) -> Self: ...
85+
elif sys.version_info >= (3, 12):
7786
def relative_to(self, other: StrPath, /, *_deprecated: StrPath, walk_up: bool = False) -> Self: ...
7887
else:
7988
def relative_to(self, *other: StrPath) -> Self: ...
@@ -154,17 +163,25 @@ class Path(PurePath):
154163
def mkdir(self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False) -> None: ...
155164

156165
if sys.version_info >= (3, 14):
157-
def copy(self, target: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> None: ...
158-
def copytree(
159-
self,
160-
target: StrPath,
161-
*,
162-
follow_symlinks: bool = True,
163-
preserve_metadata: bool = False,
164-
dirs_exist_ok: bool = False,
165-
ignore: Callable[[Self], bool] | None = None,
166-
on_error: Callable[[OSError], object] | None = None,
167-
) -> None: ...
166+
167+
@property
168+
def info(self) -> PathInfo: ...
169+
@overload
170+
def move_into(self, target_dir: _PathT) -> _PathT: ... # type: ignore[overload-overlap]
171+
@overload
172+
def move_into(self, target_dir: StrPath) -> Self: ... # type: ignore[overload-overlap]
173+
@overload
174+
def move(self, target: _PathT) -> _PathT: ... # type: ignore[overload-overlap]
175+
@overload
176+
def move(self, target: StrPath) -> Self: ... # type: ignore[overload-overlap]
177+
@overload
178+
def copy_into(self, target_dir: _PathT, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> _PathT: ... # type: ignore[overload-overlap]
179+
@overload
180+
def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Self: ... # type: ignore[overload-overlap]
181+
@overload
182+
def copy(self, target: _PathT, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> _PathT: ... # type: ignore[overload-overlap]
183+
@overload
184+
def copy(self, target: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Self: ... # type: ignore[overload-overlap]
168185

169186
# Adapted from builtins.open
170187
# Text mode: always returns a TextIOWrapper
@@ -253,9 +270,6 @@ class Path(PurePath):
253270

254271
def resolve(self, strict: bool = False) -> Self: ...
255272
def rmdir(self) -> None: ...
256-
if sys.version_info >= (3, 14):
257-
def delete(self, ignore_errors: bool = False, on_error: Callable[[OSError], object] | None = None) -> None: ...
258-
259273
def symlink_to(self, target: StrOrBytesPath, target_is_directory: bool = False) -> None: ...
260274
if sys.version_info >= (3, 10):
261275
def hardlink_to(self, target: StrOrBytesPath) -> None: ...
@@ -286,9 +300,6 @@ class Path(PurePath):
286300
self, top_down: bool = ..., on_error: Callable[[OSError], object] | None = ..., follow_symlinks: bool = ...
287301
) -> Iterator[tuple[Self, list[str], list[str]]]: ...
288302

289-
if sys.version_info >= (3, 14):
290-
def rmtree(self, ignore_errors: bool = False, on_error: Callable[[OSError], object] | None = None) -> None: ...
291-
292303
class PosixPath(Path, PurePosixPath): ...
293304
class WindowsPath(Path, PureWindowsPath): ...
294305

stdlib/pathlib/types.pyi

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from typing import Protocol, runtime_checkable
2+
3+
@runtime_checkable
4+
class PathInfo(Protocol):
5+
def exists(self, *, follow_symlinks: bool = True) -> bool: ...
6+
def is_dir(self, *, follow_symlinks: bool = True) -> bool: ...
7+
def is_file(self, *, follow_symlinks: bool = True) -> bool: ...
8+
def is_symlink(self) -> bool: ...

0 commit comments

Comments
 (0)