| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9e86d21 commit df59b64
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -204,7 +204,11 @@ def _write_atomic(path, data, mode=0o666): | |||
| 204 | 204 | # We first write data to a temporary file, and then use os.replace() to | |
| 205 | 205 | # perform an atomic rename. | |
| 206 | 206 | with _io.FileIO(fd, 'wb') as file: | |
| 207 | - file.write(data) | ||
| 207 | + bytes_written = file.write(data) | ||
| 208 | + if bytes_written != len(data): | ||
| 209 | + # Raise an OSError so the 'except' below cleans up the partially | ||
| 210 | + # written file. | ||
| 211 | + raise OSError("os.write() didn't write the full pyc file") | ||
| 208 | 212 | _os.replace(path_tmp, path) | |
| 209 | 213 | except OSError: | |
| 210 | 214 | try: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,12 +6,14 @@ | |||
| 6 | 6 | importlib_util = util.import_importlib('importlib.util') | |
| 7 | 7 | ||
| 8 | 8 | import importlib.util | |
| 9 | + from importlib import _bootstrap_external | ||
| 9 | 10 | import os | |
| 10 | 11 | import pathlib | |
| 11 | 12 | import re | |
| 12 | 13 | import string | |
| 13 | 14 | import sys | |
| 14 | 15 | from test import support | |
| 16 | + from test.support import os_helper | ||
| 15 | 17 | import textwrap | |
| 16 | 18 | import types | |
| 17 | 19 | import unittest | |
@@ -758,5 +760,35 @@ def test_complete_multi_phase_init_module(self): | |||
| 758 | 760 | self.run_with_own_gil(script) | |
| 759 | 761 | ||
| 760 | 762 | ||
| 763 | + class MiscTests(unittest.TestCase): | ||
| 764 | + def test_atomic_write_should_notice_incomplete_writes(self): | ||
| 765 | + import _pyio | ||
| 766 | + | ||
| 767 | + oldwrite = os.write | ||
| 768 | + seen_write = False | ||
| 769 | + | ||
| 770 | + truncate_at_length = 100 | ||
| 771 | + | ||
| 772 | + # Emulate an os.write that only writes partial data. | ||
| 773 | + def write(fd, data): | ||
| 774 | + nonlocal seen_write | ||
| 775 | + seen_write = True | ||
| 776 | + return oldwrite(fd, data[:truncate_at_length]) | ||
| 777 | + | ||
| 778 | + # Need to patch _io to be _pyio, so that io.FileIO is affected by the | ||
| 779 | + # os.write patch. | ||
| 780 | + with (support.swap_attr(_bootstrap_external, '_io', _pyio), | ||
| 781 | + support.swap_attr(os, 'write', write)): | ||
| 782 | + with self.assertRaises(OSError): | ||
| 783 | + # Make sure we write something longer than the point where we | ||
| 784 | + # truncate. | ||
| 785 | + content = b'x' * (truncate_at_length * 2) | ||
| 786 | + _bootstrap_external._write_atomic(os_helper.TESTFN, content) | ||
| 787 | + assert seen_write | ||
| 788 | + | ||
| 789 | + with self.assertRaises(OSError): | ||
| 790 | + os.stat(support.os_helper.TESTFN) # Check that the file did not get written. | ||
| 791 | + | ||
| 792 | + | ||
| 761 | 793 | if __name__ == '__main__': | |
| 762 | 794 | unittest.main() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + Fix :mod:`importlib` to not write an incomplete .pyc files when a ulimit or some | ||
| 2 | + other operating system mechanism is preventing the write to go through | ||
| 3 | + fully. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments