diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2011-11-15 18:15:19 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2011-11-15 18:15:19 (GMT) |
commit | 28e401e7173fbd4c74140f0e5325bc9b4978ec65 (patch) | |
tree | 05eecc25d850c31002f681485e1bec1613ec57fa /Lib | |
parent | 5f7f6150c38f1ed33d83c6597ae275ab5f5b99c5 (diff) | |
download | cpython-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')
-rw-r--r-- | Lib/importlib/_bootstrap.py | 35 |
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): |