https://github.com/python/cpython/commit/b5454509612870dd0e09aaba4b79865a5faad284
commit: b5454509612870dd0e09aaba4b79865a5faad284
branch: main
author: Barney Gale <[email protected]>
committer: barneygale <[email protected]>
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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]