]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-130608: Remove `dirs_exist_ok` argument from `pathlib.Path.copy()` (#130610)
authorBarney Gale <barney.gale@gmail.com>
Fri, 28 Feb 2025 19:29:20 +0000 (19:29 +0000)
committerGitHub <noreply@github.com>
Fri, 28 Feb 2025 19:29:20 +0000 (19:29 +0000)
This feature isn't sufficiently motivated.

Doc/library/pathlib.rst
Lib/pathlib/_abc.py
Lib/pathlib/_local.py
Lib/pathlib/_os.py
Lib/test/test_pathlib/test_pathlib_abc.py
Misc/NEWS.d/next/Library/2025-02-26-21-21-08.gh-issue-130608.f7ix0Y.rst [new file with mode: 0644]

index 8977ccfe6e412494563b76e5ff5a514d84db6112..a2955d28d2dd9e26970846544e8056e971d31f88 100644 (file)
@@ -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
index 6b46aea9aea4b90b0dc4ddf80860d2126c338f84..930701d4789f5ce1b7726514d7564e28a025eff4 100644 (file)
@@ -340,19 +340,18 @@ class ReadablePath(JoinablePath):
         """
         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 @@ class ReadablePath(JoinablePath):
         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)
 
 
index ba81c3de1ccb8b602ac86be59a2d468ce1cd0e4f..83da6960f00489c581318a05b9b50b4fb623cd33 100644 (file)
@@ -1093,19 +1093,18 @@ class Path(PurePath):
             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 @@ class Path(PurePath):
         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):
index a741f201b6d925e5510df3f9daf561214d11a2bc..c8cb4be548d04503a808a8c11d0ee5003f2b314c 100644 (file)
@@ -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:
index a6e3e0709833a39defc205b68301f68e1913f831..b64924d06d420be3bc762a3edf2c7ea64924c998 100644 (file)
@@ -1495,23 +1495,6 @@ class RWPathTest(WritablePathTest, ReadablePathTest):
         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 (file)
index 0000000..240c14f
--- /dev/null
@@ -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.