summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorBrett Cannon <brett@python.org>2012-02-17 14:26:53 (GMT)
committerBrett Cannon <brett@python.org>2012-02-17 14:26:53 (GMT)
commitba17fe256eefa958dcdc912dc01dbad3b5e843e2 (patch)
tree14828fd9b0eac7df8f2fd454bf020d7ee48aac48 /Lib
parent4fcad3c7ab551110bce65fdac3b8e914dff1aa5c (diff)
downloadcpython-ba17fe256eefa958dcdc912dc01dbad3b5e843e2.zip
cpython-ba17fe256eefa958dcdc912dc01dbad3b5e843e2.tar.gz
cpython-ba17fe256eefa958dcdc912dc01dbad3b5e843e2.tar.bz2
Have importlib use os.replace() for atomic renaming.
Closes issue #13961. Thanks to Charles-François Natali for the patch.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/importlib/_bootstrap.py23
1 files changed, 6 insertions, 17 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index 39cf76a..56afe57 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -137,26 +137,16 @@ def _path_absolute(path):
def _write_atomic(path, data):
- """Best-effort function to write data to a path atomically.
- Be prepared to handle a FileExistsError if concurrent writing of the
- temporary file is attempted."""
- # Renaming should be atomic on most platforms (including Windows).
- # Under Windows, the limitation is that we can't rename() to an existing
- # path, while POSIX will overwrite it. But here we don't really care
- # if there is a glimpse of time during which the final pyc file doesn't
- # exist.
+ """Function to write data to a path atomically."""
# id() is used to generate a pseudo-random filename.
path_tmp = '{}.{}'.format(path, id(path))
fd = _os.open(path_tmp, _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY, 0o666)
try:
+ # We first write data to a temporary file, and then use os.replace() to
+ # perform an atomic rename.
with _io.FileIO(fd, 'wb') as file:
file.write(data)
- try:
- _os.rename(path_tmp, path)
- except FileExistsError:
- # Windows (if we had access to MoveFileEx, we could overwrite)
- _os.unlink(path)
- _os.rename(path_tmp, path)
+ _os.replace(path_tmp, path)
except OSError:
try:
_os.unlink(path_tmp)
@@ -602,9 +592,8 @@ class _SourceFileLoader(_FileLoader, SourceLoader):
return
try:
_write_atomic(path, data)
- except (PermissionError, FileExistsError):
- # Don't worry if you can't write bytecode or someone is writing
- # it at the same time.
+ except PermissionError:
+ # Don't worry if you can't write bytecode.
pass