Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ def _write_atomic(path, data, mode=0o666):
# 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)
bytes_written = file.write(data)
if bytes_written != len(data):
raise OSError("os.write didn't write the full pyc file")
_os.replace(path_tmp, path)
except OSError:
try:
Expand Down
28 changes: 28 additions & 0 deletions Lib/test/test_importlib/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,5 +775,33 @@ def test_complete_multi_phase_init_module(self):
self.run_with_own_gil(script)


class MiscTests(unittest.TestCase):
def test_atomic_write_should_notice_incomplete_writes(self):
from importlib import _bootstrap_external
from test.support import os_helper
import _pyio
import os

oldwrite = os.write
seen_write = False

# emulate an os.write that only writes partial data
def write(fd, data):
nonlocal seen_write
seen_write = True
return oldwrite(fd, data[:100])

# need to patch _io to be _pyio, so that io.FileIO is affected by the
# os.write patch
with (unittest.mock.patch('importlib._bootstrap_external._io', _pyio),
unittest.mock.patch('os.write', write)):
with self.assertRaises(OSError):
_bootstrap_external._write_atomic(os_helper.TESTFN, b'x' * 10000)
assert seen_write

with self.assertRaises(OSError):
os.stat(os_helper.TESTFN) # did not get written


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix importlib to not write an incomplete pyc files when a ulimit or some
other operating system mechanism is preventing the write to go through
fully.
Loading