Issue #17244: Don't mask exceptions raised during the creation of

bytecode files in py_compile.

Thanks to Arfrever Frehtes Taifersar Arahesis for the bug report.
This commit is contained in:
Brett Cannon 2013-04-14 12:48:15 -04:00
parent 672559fc4f
commit edfd6ae79c
4 changed files with 3529 additions and 3498 deletions

View File

@ -474,6 +474,18 @@ def _get_sourcefile(bytecode_path):
return source_path if _path_isfile(source_stats) else bytecode_path return source_path if _path_isfile(source_stats) else bytecode_path
def _calc_mode(path):
"""Calculate the mode permissions for a bytecode file."""
try:
mode = _os.stat(path).st_mode
except OSError:
mode = 0o666
# We always ensure write access so we can update cached files
# later even when the source files are read-only on Windows (#6074)
mode |= 0o200
return mode
def _verbose_message(message, *args, verbosity=1): def _verbose_message(message, *args, verbosity=1):
"""Print the message to stderr if -v/PYTHONVERBOSE is turned on.""" """Print the message to stderr if -v/PYTHONVERBOSE is turned on."""
if sys.flags.verbose >= verbosity: if sys.flags.verbose >= verbosity:
@ -1060,13 +1072,7 @@ class SourceFileLoader(FileLoader, SourceLoader):
def _cache_bytecode(self, source_path, bytecode_path, data): def _cache_bytecode(self, source_path, bytecode_path, data):
# Adapt between the two APIs # Adapt between the two APIs
try: mode = _calc_mode(source_path)
mode = _os.stat(source_path).st_mode
except OSError:
mode = 0o666
# We always ensure write access so we can update cached files
# later even when the source files are read-only on Windows (#6074)
mode |= 0o200
return self.set_data(bytecode_path, data, _mode=mode) return self.set_data(bytecode_path, data, _mode=mode)
def set_data(self, path, data, *, _mode=0o666): def set_data(self, path, data, *, _mode=0o666):

View File

@ -106,7 +106,7 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
source_bytes = loader.get_data(file) source_bytes = loader.get_data(file)
try: try:
code = loader.source_to_code(source_bytes, dfile or file, code = loader.source_to_code(source_bytes, dfile or file,
_optimize=optimize) _optimize=optimize)
except Exception as err: except Exception as err:
py_exc = PyCompileError(err.__class__, err, dfile or file) py_exc = PyCompileError(err.__class__, err, dfile or file)
if doraise: if doraise:
@ -121,11 +121,13 @@ def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
except FileExistsError: except FileExistsError:
pass pass
source_stats = loader.path_stats(file) source_stats = loader.path_stats(file)
bytecode = importlib._bootstrap._code_to_bytecode(code, bytecode = importlib._bootstrap._code_to_bytecode(
source_stats['mtime'], len(source_bytes)) code, source_stats['mtime'], source_stats['size'])
loader._cache_bytecode(file, cfile, bytecode) mode = importlib._bootstrap._calc_mode(file)
importlib._bootstrap._write_atomic(cfile, bytecode, mode)
return cfile return cfile
def main(args=None): def main(args=None):
"""Compile several source files. """Compile several source files.

View File

@ -2,6 +2,7 @@ import imp
import os import os
import py_compile import py_compile
import shutil import shutil
import stat
import tempfile import tempfile
import unittest import unittest
@ -54,8 +55,18 @@ class PyCompileTests(unittest.TestCase):
self.assertTrue(os.path.exists(self.pyc_path)) self.assertTrue(os.path.exists(self.pyc_path))
self.assertFalse(os.path.exists(self.cache_path)) self.assertFalse(os.path.exists(self.cache_path))
def test_main(): def test_exceptions_propagate(self):
support.run_unittest(PyCompileTests) # Make sure that exceptions raised thanks to issues with writing
# bytecode.
# http://bugs.python.org/issue17244
mode = os.stat(self.directory)
os.chmod(self.directory, stat.S_IREAD)
try:
with self.assertRaises(IOError):
py_compile.compile(self.source_path, self.pyc_path)
finally:
os.chmod(self.directory, mode.st_mode)
if __name__ == "__main__": if __name__ == "__main__":
test_main() unittest.main()

File diff suppressed because it is too large Load Diff