]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-109503: Fix document for shutil.move() on usage of os.rename() since it...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 9 Jun 2026 13:06:30 +0000 (15:06 +0200)
committerGitHub <noreply@github.com>
Tue, 9 Jun 2026 13:06:30 +0000 (16:06 +0300)
Nonatomic move might be used even if the files are
on the same filesystem in some cases.
(cherry picked from commit 6ecd197c03c43412fc400235949fd8297f142e89)

Co-authored-by: Fang Li <fangli@users.noreply.github.com>
Doc/library/shutil.rst
Lib/shutil.py
Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst [new file with mode: 0644]

index 6a734966d1e0a45a58ab4172a063c872f02dc3b1..6febc7a187a15f841fe4ac45a2e24d679b6f1d6e 100644 (file)
@@ -385,10 +385,14 @@ Directory and files operations
    If *dst* already exists but is not a directory, it may be overwritten
    depending on :func:`os.rename` semantics.
 
-   If the destination is on the current filesystem, then :func:`os.rename` is
-   used. Otherwise, *src* is copied to the destination using *copy_function*
-   and then removed.  In case of symlinks, a new symlink pointing to the target
-   of *src* will be created as the destination and *src* will be removed.
+   :func:`os.rename` is preferably used internally when *src* and the destination are on
+   the same filesystem. In case :func:`os.rename` fails due to :exc:`OSError`
+   (e.g. the user has write permission to the destination file but not to its parent
+   directory), this method falls back to using *copy_function*, in which case
+   *src* is copied to the destination using *copy_function* and then removed.
+
+   In case of symlinks, a new symlink pointing to the target of *src* will be
+   created in or as the destination, and *src* will be removed.
 
    If *copy_function* is given, it must be a callable that takes two arguments,
    *src* and the destination, and will be used to copy *src* to the destination
index d3ac5dc5c50a734664c21a86b8d47fc258a3e097..2ac6a39ba37e9c0c29f4d62fd175c4941aee0fcc 100644 (file)
@@ -885,10 +885,14 @@ def move(src, dst, copy_function=copy2):
     If dst already exists but is not a directory, it may be overwritten
     depending on os.rename() semantics.
 
-    If the destination is on our current filesystem, then rename() is used.
-    Otherwise, src is copied to the destination and then removed. Symlinks are
-    recreated under the new name if os.rename() fails because of cross
-    filesystem renames.
+    os.rename() is preferably used if the source and destination are on the
+    same filesystem. In case os.rename() fails due to OSError (e.g. the user
+    has write permission to *dst* file but not to its parent directory),
+    this method falls back to using *copy_function* silently.
+    Symlinks are also recreated under the new name if os.rename() fails
+    because of cross filesystem renames.
+
+    It's recommended to use os.rename() if atomic move is strictly required.
 
     The optional `copy_function` argument is a callable that will be used
     to copy the source or it will be delegated to `copytree`.
diff --git a/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst b/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst
new file mode 100644 (file)
index 0000000..c3c6c57
--- /dev/null
@@ -0,0 +1,3 @@
+Fix documentation for :func:`shutil.move` on usage of
+:func:`os.rename` since nonatomic move might be used even if the files are
+on the same filesystem. Patch by Fang Li