https://github.com/python/cpython/commit/6ecd197c03c43412fc400235949fd8297f142e89
commit: 6ecd197c03c43412fc400235949fd8297f142e89
branch: main
author: Fang Li <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-05-30T14:26:03Z
summary:
gh-109503: Fix document for shutil.move() on usage of os.rename() since it's
inaccurate (GH-109507)
Nonatomic move might be used even if the files are
on the same filesystem in some cases.
files:
A Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst
M Doc/library/shutil.rst
M Lib/shutil.py
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst
index e0300a38e2f357d..177c45e4f820f6e 100644
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -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
diff --git a/Lib/shutil.py b/Lib/shutil.py
index cad9b570241f2c3..c8d02bbaeb80b4e 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -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
index 000000000000000..c3c6c57569c2ea5
--- /dev/null
+++
b/Misc/NEWS.d/next/Documentation/2023-09-16-23-42-27.gh-issue-109503.mZ-kdU.rst
@@ -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
_______________________________________________
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]