https://github.com/python/cpython/commit/b5454509612870dd0e09aaba4b79865a5faad284 commit: b5454509612870dd0e09aaba4b79865a5faad284 branch: main author: Barney Gale <barney.g...@gmail.com> committer: barneygale <barney.g...@gmail.com> date: 2025-02-28T19:29:20Z summary:
GH-130608: Remove `dirs_exist_ok` argument from `pathlib.Path.copy()` (#130610) This feature isn't sufficiently motivated. files: A Misc/NEWS.d/next/Library/2025-02-26-21-21-08.gh-issue-130608.f7ix0Y.rst M Doc/library/pathlib.rst M Lib/pathlib/_abc.py M Lib/pathlib/_local.py M Lib/pathlib/_os.py M Lib/test/test_pathlib/test_pathlib_abc.py diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 8977ccfe6e4124..a2955d28d2dd9e 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -1571,8 +1571,7 @@ Creating files and directories Copying, moving and deleting ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. method:: Path.copy(target, *, follow_symlinks=True, dirs_exist_ok=False, \ - preserve_metadata=False) +.. method:: Path.copy(target, *, follow_symlinks=True, preserve_metadata=False) Copy this file or directory tree to the given *target*, and return a new :class:`!Path` instance pointing to *target*. @@ -1582,12 +1581,6 @@ Copying, moving and deleting default), the symlink's target is copied. Otherwise, the symlink is recreated at the destination. - If the source is a directory and *dirs_exist_ok* is false (the default), a - :exc:`FileExistsError` is raised if the target is an existing directory. - If *dirs_exists_ok* is true, the copying operation will overwrite - existing files within the destination tree with corresponding files - from the source tree. - If *preserve_metadata* is false (the default), only directory structures and file data are guaranteed to be copied. Set *preserve_metadata* to true to ensure that file and directory permissions, flags, last access and @@ -1604,7 +1597,7 @@ Copying, moving and deleting .. method:: Path.copy_into(target_dir, *, follow_symlinks=True, \ - dirs_exist_ok=False, preserve_metadata=False) + preserve_metadata=False) Copy this file or directory tree into the given *target_dir*, which should be an existing directory. Other arguments are handled identically to diff --git a/Lib/pathlib/_abc.py b/Lib/pathlib/_abc.py index 6b46aea9aea4b9..930701d4789f5c 100644 --- a/Lib/pathlib/_abc.py +++ b/Lib/pathlib/_abc.py @@ -340,19 +340,18 @@ def readlink(self): """ raise NotImplementedError - def copy(self, target, follow_symlinks=True, dirs_exist_ok=False, - preserve_metadata=False): + def copy(self, target, follow_symlinks=True, preserve_metadata=False): """ Recursively copy this file or directory tree to the given destination. """ if not hasattr(target, 'with_segments'): target = self.with_segments(target) ensure_distinct_paths(self, target) - copy_file(self, target, follow_symlinks, dirs_exist_ok, preserve_metadata) + copy_file(self, target, follow_symlinks, preserve_metadata) return target.joinpath() # Empty join to ensure fresh metadata. def copy_into(self, target_dir, *, follow_symlinks=True, - dirs_exist_ok=False, preserve_metadata=False): + preserve_metadata=False): """ Copy this file or directory tree into the given existing directory. """ @@ -364,7 +363,6 @@ def copy_into(self, target_dir, *, follow_symlinks=True, else: target = self.with_segments(target_dir, name) return self.copy(target, follow_symlinks=follow_symlinks, - dirs_exist_ok=dirs_exist_ok, preserve_metadata=preserve_metadata) diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py index ba81c3de1ccb8b..83da6960f00489 100644 --- a/Lib/pathlib/_local.py +++ b/Lib/pathlib/_local.py @@ -1093,19 +1093,18 @@ def replace(self, target): target = self.with_segments(target) return target - def copy(self, target, follow_symlinks=True, dirs_exist_ok=False, - preserve_metadata=False): + def copy(self, target, follow_symlinks=True, preserve_metadata=False): """ Recursively copy this file or directory tree to the given destination. """ if not hasattr(target, 'with_segments'): target = self.with_segments(target) ensure_distinct_paths(self, target) - copy_file(self, target, follow_symlinks, dirs_exist_ok, preserve_metadata) + copy_file(self, target, follow_symlinks, preserve_metadata) return target.joinpath() # Empty join to ensure fresh metadata. def copy_into(self, target_dir, *, follow_symlinks=True, - dirs_exist_ok=False, preserve_metadata=False): + preserve_metadata=False): """ Copy this file or directory tree into the given existing directory. """ @@ -1117,7 +1116,6 @@ def copy_into(self, target_dir, *, follow_symlinks=True, else: target = self.with_segments(target_dir, name) return self.copy(target, follow_symlinks=follow_symlinks, - dirs_exist_ok=dirs_exist_ok, preserve_metadata=preserve_metadata) def move(self, target): diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py index a741f201b6d925..c8cb4be548d045 100644 --- a/Lib/pathlib/_os.py +++ b/Lib/pathlib/_os.py @@ -242,8 +242,7 @@ def ensure_different_files(source, target): raise err -def copy_file(source, target, follow_symlinks=True, dirs_exist_ok=False, - preserve_metadata=False): +def copy_file(source, target, follow_symlinks=True, preserve_metadata=False): """ Recursively copy the given source ReadablePath to the given target WritablePath. """ @@ -254,10 +253,10 @@ def copy_file(source, target, follow_symlinks=True, dirs_exist_ok=False, target._write_info(info, follow_symlinks=False) elif info.is_dir(): children = source.iterdir() - target.mkdir(exist_ok=dirs_exist_ok) + target.mkdir() for src in children: dst = target.joinpath(src.name) - copy_file(src, dst, follow_symlinks, dirs_exist_ok, preserve_metadata) + copy_file(src, dst, follow_symlinks, preserve_metadata) if preserve_metadata: target._write_info(info) else: diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py index a6e3e0709833a3..b64924d06d420b 100644 --- a/Lib/test/test_pathlib/test_pathlib_abc.py +++ b/Lib/test/test_pathlib/test_pathlib_abc.py @@ -1495,23 +1495,6 @@ def test_copy_dir_to_existing_directory(self): target.joinpath('dirD').mkdir() self.assertRaises(FileExistsError, source.copy, target) - def test_copy_dir_to_existing_directory_dirs_exist_ok(self): - base = self.cls(self.base) - source = base / 'dirC' - target = base / 'copyC' - target.mkdir() - target.joinpath('dirD').mkdir() - result = source.copy(target, dirs_exist_ok=True) - self.assertEqual(result, target) - self.assertTrue(result.info.is_dir()) - self.assertTrue(result.joinpath('dirD').info.is_dir()) - self.assertTrue(result.joinpath('dirD', 'fileD').info.is_file()) - self.assertEqual(result.joinpath('dirD', 'fileD').read_text(), - "this is file D\n") - self.assertTrue(result.joinpath('fileC').info.is_file()) - self.assertTrue(result.joinpath('fileC').read_text(), - "this is file C\n") - def test_copy_dir_to_itself(self): base = self.cls(self.base) source = base / 'dirC' diff --git a/Misc/NEWS.d/next/Library/2025-02-26-21-21-08.gh-issue-130608.f7ix0Y.rst b/Misc/NEWS.d/next/Library/2025-02-26-21-21-08.gh-issue-130608.f7ix0Y.rst new file mode 100644 index 00000000000000..240c14fbca2580 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-26-21-21-08.gh-issue-130608.f7ix0Y.rst @@ -0,0 +1,2 @@ +Remove *dirs_exist_ok* argument from :meth:`pathlib.Path.copy` and +:meth:`~pathlib.Path.copy_into`. These methods are new in Python 3.14. _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com