From c2cb134bb980b5a57937ebe495e54e1ddf1ea140 Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:04:07 -0500 Subject: [PATCH 1/9] Add copy_into --- stdlib/@tests/stubtest_allowlists/py314.txt | 1 - stdlib/@tests/test_cases/check_pathlib.py | 13 +++++++++++++ stdlib/pathlib.pyi | 8 +++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/py314.txt b/stdlib/@tests/stubtest_allowlists/py314.txt index 161310ad18bb..83fb0a8cc30b 100644 --- a/stdlib/@tests/stubtest_allowlists/py314.txt +++ b/stdlib/@tests/stubtest_allowlists/py314.txt @@ -162,7 +162,6 @@ multiprocessing.process.BaseProcess.interrupt multiprocessing.synchronize.SemLock.locked os.__all__ os.readinto -pathlib.Path.copy_into pathlib.Path.copytree pathlib.Path.delete pathlib.Path.info diff --git a/stdlib/@tests/test_cases/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py index 9b4d681c9e96..bff2d25d3892 100644 --- a/stdlib/@tests/test_cases/check_pathlib.py +++ b/stdlib/@tests/test_cases/check_pathlib.py @@ -4,6 +4,10 @@ from pathlib import Path, PureWindowsPath from typing_extensions import assert_type + +class MyCustomPath(Path): ... + + if Path("asdf") == Path("asdf"): ... @@ -28,3 +32,12 @@ class MyCustomPath(Path): ... pth = MyCustomPath.from_uri("file:///tmp/abc.txt") assert_type(pth, MyCustomPath) + +if sys.version_info >= (3, 14): + my_path = MyCustomPath(".") + pth = my_path.copy_into(my_path) + assert_type(pth, MyCustomPath) + + # If the destination is a non-Path, it should default to a base Path. + pth = my_path.copy_into(".") + assert_type(pth, Path) diff --git a/stdlib/pathlib.pyi b/stdlib/pathlib.pyi index 1e4d97770b7b..40de1229e5ae 100644 --- a/stdlib/pathlib.pyi +++ b/stdlib/pathlib.pyi @@ -15,9 +15,11 @@ from collections.abc import Callable, Generator, Iterator, Sequence from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper from os import PathLike, stat_result from types import GenericAlias, TracebackType -from typing import IO, Any, BinaryIO, ClassVar, Literal, overload +from typing import IO, Any, BinaryIO, ClassVar, Literal, TypeVar, overload from typing_extensions import Never, Self, deprecated +_T = TypeVar("_T", bound=PurePath) + __all__ = ["PurePath", "PurePosixPath", "PureWindowsPath", "Path", "PosixPath", "WindowsPath"] if sys.version_info >= (3, 13): @@ -154,6 +156,10 @@ class Path(PurePath): def mkdir(self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False) -> None: ... if sys.version_info >= (3, 14): + @overload + def copy_into(self, target_dir: _T, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> _T: ... + @overload + def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Path: ... def copy(self, target: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> None: ... def copytree( self, From e4a4835155cbd96df5dddbda5a76f806aa7ee02c Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:07:46 -0500 Subject: [PATCH 2/9] Fix test --- stdlib/@tests/test_cases/check_pathlib.py | 7 ++++--- stdlib/pathlib.pyi | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/stdlib/@tests/test_cases/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py index bff2d25d3892..b08734aaa193 100644 --- a/stdlib/@tests/test_cases/check_pathlib.py +++ b/stdlib/@tests/test_cases/check_pathlib.py @@ -3,6 +3,7 @@ import sys from pathlib import Path, PureWindowsPath from typing_extensions import assert_type +import pathlib class MyCustomPath(Path): ... @@ -35,9 +36,9 @@ class MyCustomPath(Path): ... if sys.version_info >= (3, 14): my_path = MyCustomPath(".") - pth = my_path.copy_into(my_path) - assert_type(pth, MyCustomPath) + pth = my_path.copy_into(pathlib.Path(".")) + assert_type(pth, pathlib.Path) # If the destination is a non-Path, it should default to a base Path. pth = my_path.copy_into(".") - assert_type(pth, Path) + assert_type(pth, MyCustomPath) diff --git a/stdlib/pathlib.pyi b/stdlib/pathlib.pyi index 40de1229e5ae..f22372e23d70 100644 --- a/stdlib/pathlib.pyi +++ b/stdlib/pathlib.pyi @@ -159,7 +159,7 @@ class Path(PurePath): @overload def copy_into(self, target_dir: _T, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> _T: ... @overload - def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Path: ... + def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Self: ... def copy(self, target: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> None: ... def copytree( self, From cb5810fb73cd76661077f27a4a756d4512ed5680 Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:10:22 -0500 Subject: [PATCH 3/9] Fix test --- stdlib/@tests/test_cases/check_pathlib.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/stdlib/@tests/test_cases/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py index b08734aaa193..813947013033 100644 --- a/stdlib/@tests/test_cases/check_pathlib.py +++ b/stdlib/@tests/test_cases/check_pathlib.py @@ -28,9 +28,6 @@ class MyCustomPath(Path): ... if sys.version_info >= (3, 13): - - class MyCustomPath(Path): ... - pth = MyCustomPath.from_uri("file:///tmp/abc.txt") assert_type(pth, MyCustomPath) From e73176c14a3f59467c42da7621f7a496377e14db Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 10 May 2025 21:11:04 +0000 Subject: [PATCH 4/9] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/@tests/test_cases/check_pathlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/@tests/test_cases/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py index 813947013033..97ee5056c91c 100644 --- a/stdlib/@tests/test_cases/check_pathlib.py +++ b/stdlib/@tests/test_cases/check_pathlib.py @@ -1,9 +1,9 @@ from __future__ import annotations +import pathlib import sys from pathlib import Path, PureWindowsPath from typing_extensions import assert_type -import pathlib class MyCustomPath(Path): ... From c4ce214c8bb5dc85b75243c0f62f1afe44746eb2 Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:11:31 -0500 Subject: [PATCH 5/9] Simplify --- stdlib/@tests/test_cases/check_pathlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/@tests/test_cases/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py index 97ee5056c91c..b19be08bc4fe 100644 --- a/stdlib/@tests/test_cases/check_pathlib.py +++ b/stdlib/@tests/test_cases/check_pathlib.py @@ -33,8 +33,8 @@ class MyCustomPath(Path): ... if sys.version_info >= (3, 14): my_path = MyCustomPath(".") - pth = my_path.copy_into(pathlib.Path(".")) - assert_type(pth, pathlib.Path) + pth = my_path.copy_into(Path(".")) + assert_type(pth, Path) # If the destination is a non-Path, it should default to a base Path. pth = my_path.copy_into(".") From 8bd4306741061326840dfde3a0fa27efa0e84489 Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:16:26 -0500 Subject: [PATCH 6/9] Ignore overlap --- stdlib/pathlib.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/pathlib.pyi b/stdlib/pathlib.pyi index f22372e23d70..7e4177793687 100644 --- a/stdlib/pathlib.pyi +++ b/stdlib/pathlib.pyi @@ -159,7 +159,7 @@ class Path(PurePath): @overload def copy_into(self, target_dir: _T, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> _T: ... @overload - def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Self: ... + def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Self: ... # type: ignore[overload-overlap] def copy(self, target: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> None: ... def copytree( self, From d25c370cb8514e1dd4e026a86625ee811d36cb31 Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:21:33 -0500 Subject: [PATCH 7/9] Remove unused import --- stdlib/@tests/test_cases/check_pathlib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/@tests/test_cases/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py index b19be08bc4fe..1120c76312aa 100644 --- a/stdlib/@tests/test_cases/check_pathlib.py +++ b/stdlib/@tests/test_cases/check_pathlib.py @@ -1,6 +1,5 @@ from __future__ import annotations -import pathlib import sys from pathlib import Path, PureWindowsPath from typing_extensions import assert_type From b78e9324d8948af66c4d47b0432f690198b6f452 Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:23:15 -0500 Subject: [PATCH 8/9] move ignore --- stdlib/pathlib.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/pathlib.pyi b/stdlib/pathlib.pyi index 7e4177793687..7a5b494b70fd 100644 --- a/stdlib/pathlib.pyi +++ b/stdlib/pathlib.pyi @@ -157,9 +157,9 @@ class Path(PurePath): if sys.version_info >= (3, 14): @overload - def copy_into(self, target_dir: _T, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> _T: ... + def copy_into(self, target_dir: _T, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> _T: ... # type: ignore[overload-overlap] @overload - def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Self: ... # type: ignore[overload-overlap] + def copy_into(self, target_dir: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> Self: ... def copy(self, target: StrPath, *, follow_symlinks: bool = True, preserve_metadata: bool = False) -> None: ... def copytree( self, From cf5969d06814eac1f0924ceebe8b19455c7f6790 Mon Sep 17 00:00:00 2001 From: Max Muoto Date: Sat, 10 May 2025 16:24:59 -0500 Subject: [PATCH 9/9] Tweak comment --- stdlib/@tests/test_cases/check_pathlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/@tests/test_cases/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py index 1120c76312aa..1ff03c9b8c68 100644 --- a/stdlib/@tests/test_cases/check_pathlib.py +++ b/stdlib/@tests/test_cases/check_pathlib.py @@ -35,6 +35,6 @@ class MyCustomPath(Path): ... pth = my_path.copy_into(Path(".")) assert_type(pth, Path) - # If the destination is a non-Path, it should default to a base Path. + # If the destination is a non-Path, it should default to `Self`. pth = my_path.copy_into(".") assert_type(pth, MyCustomPath)