diff options
author | Brett Cannon <bcannon@gmail.com> | 2009-11-07 23:55:05 (GMT) |
---|---|---|
committer | Brett Cannon <bcannon@gmail.com> | 2009-11-07 23:55:05 (GMT) |
commit | e52c919d67a20b235de008aed8a165778d78b2a9 (patch) | |
tree | 99b0dd63368ae71bc8dd00ff8d6cd6848e1fabfd /Lib/importlib | |
parent | 1b184d547f9421b586e92984960edc01bbb36307 (diff) | |
download | cpython-e52c919d67a20b235de008aed8a165778d78b2a9.zip cpython-e52c919d67a20b235de008aed8a165778d78b2a9.tar.gz cpython-e52c919d67a20b235de008aed8a165778d78b2a9.tar.bz2 |
When trying to write new bytecode, importlib was not catching the IOError
thrown if the file happened to be read-only to keep the failure silent.
Fixes issue #7187. Thanks, Dave Malcolm for the report and analysis of the
problem.
Diffstat (limited to 'Lib/importlib')
-rw-r--r-- | Lib/importlib/_bootstrap.py | 4 | ||||
-rw-r--r-- | Lib/importlib/test/source/test_file_loader.py | 26 |
2 files changed, 28 insertions, 2 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 466b287..02f5c49 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -526,9 +526,9 @@ class _PyPycFileLoader(PyPycLoader, _PyFileLoader): bytecode_path = self.bytecode_path(name) if not bytecode_path: bytecode_path = self._base_path + _suffix_list(imp.PY_COMPILED)[0] - file = _io.FileIO(bytecode_path, 'w') # Assuming bytes. try: - with _closing(file) as bytecode_file: + # Assuming bytes. + with _closing(_io.FileIO(bytecode_path, 'w')) as bytecode_file: bytecode_file.write(data) return True except IOError as exc: diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py index b18750c..32a6955 100644 --- a/Lib/importlib/test/source/test_file_loader.py +++ b/Lib/importlib/test/source/test_file_loader.py @@ -6,6 +6,7 @@ from . import util as source_util import imp import os import py_compile +import stat import sys import unittest @@ -121,6 +122,10 @@ class BadBytecodeTest(unittest.TestCase): But if the marshal data is bad, even if the magic number and timestamp work, a ValueError is raised and the source is not used [bad marshal]. + The case of not being able to write out the bytecode must also be handled + as it's possible it was made read-only. In that instance the attempt to + write the bytecode should fail silently [bytecode read-only]. + """ def import_(self, file, module_name): @@ -159,6 +164,7 @@ class BadBytecodeTest(unittest.TestCase): self.assertEqual(bytecode_file.read(4), source_timestamp) # [bad marshal] + @source_util.writes_bytecode_files def test_bad_marshal(self): with source_util.create_modules('_temp') as mapping: bytecode_path = source_util.bytecode_path(mapping['_temp']) @@ -172,6 +178,26 @@ class BadBytecodeTest(unittest.TestCase): self.import_(mapping['_temp'], '_temp') self.assertTrue('_temp' not in sys.modules) + # [bytecode read-only] + @source_util.writes_bytecode_files + def test_read_only_bytecode(self): + with source_util.create_modules('_temp') as mapping: + # Create bytecode that will need to be re-created. + py_compile.compile(mapping['_temp']) + bytecode_path = source_util.bytecode_path(mapping['_temp']) + with open(bytecode_path, 'r+b') as bytecode_file: + bytecode_file.seek(0) + bytecode_file.write(b'\x00\x00\x00\x00') + # Make the bytecode read-only. + os.chmod(bytecode_path, + stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) + try: + # Should not raise IOError! + self.import_(mapping['_temp'], '_temp') + finally: + # Make writable for eventual clean-up. + os.chmod(bytecode_path, stat.S_IWUSR) + def test_main(): from test.support import run_unittest |