summaryrefslogtreecommitdiffstats
path: root/Lib/importlib/_bootstrap.py
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-11-15 18:15:19 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-11-15 18:15:19 (GMT)
commit28e401e7173fbd4c74140f0e5325bc9b4978ec65 (patch)
tree05eecc25d850c31002f681485e1bec1613ec57fa /Lib/importlib/_bootstrap.py
parent5f7f6150c38f1ed33d83c6597ae275ab5f5b99c5 (diff)
downloadcpython-28e401e7173fbd4c74140f0e5325bc9b4978ec65.zip
cpython-28e401e7173fbd4c74140f0e5325bc9b4978ec65.tar.gz
cpython-28e401e7173fbd4c74140f0e5325bc9b4978ec65.tar.bz2
Issue #13392: Writing a pyc file should now be atomic under Windows as well.
Diffstat (limited to 'Lib/importlib/_bootstrap.py')
-rw-r--r--Lib/importlib/_bootstrap.py35
1 files changed, 20 insertions, 15 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index 209e041..359b9e7 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -84,24 +84,29 @@ 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."""
- if not sys.platform.startswith('win'):
- # On POSIX-like platforms, renaming is atomic. 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)
+ # 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.
+ # 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:
+ with _io.FileIO(fd, 'wb') as file:
+ file.write(data)
try:
- with _io.FileIO(fd, 'wb') as file:
- file.write(data)
_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)
+ except OSError:
+ try:
+ _os.unlink(path_tmp)
except OSError:
- try:
- _os.unlink(path_tmp)
- except OSError:
- pass
- raise
- else:
- with _io.FileIO(path, 'wb') as file:
- file.write(data)
+ pass
+ raise
def _wrap(new, old):