diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2012-10-19 11:58:18 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2012-10-19 11:58:18 (GMT) |
commit | b48c028ca7b1f8a0215cfe12bbc32961743a554b (patch) | |
tree | 5253b5bae70d447b31d9a9032d0eefdd273b0d68 | |
parent | 02f69f6965cc3793ffb68399da76a412244da270 (diff) | |
download | cpython-b48c028ca7b1f8a0215cfe12bbc32961743a554b.zip cpython-b48c028ca7b1f8a0215cfe12bbc32961743a554b.tar.gz cpython-b48c028ca7b1f8a0215cfe12bbc32961743a554b.tar.bz2 |
Issue #6074: Restore the long-broken support for running with read-only source files on Windows
-rw-r--r-- | Lib/test/test_import.py | 48 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Python/import.c | 6 |
3 files changed, 56 insertions, 1 deletions
diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py index 2f46d83..c72bca0 100644 --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -15,12 +15,24 @@ from test.test_support import (unlink, TESTFN, unload, run_unittest, rmtree, from test import symlink_support from test import script_helper -def remove_files(name): +def _iter_files(name): for f in (name + os.extsep + "py", name + os.extsep + "pyc", name + os.extsep + "pyo", name + os.extsep + "pyw", name + "$py.class"): + yield f + +def chmod_files(name): + for f in _iter_files(name): + try: + os.chmod(f, 0600) + except OSError as exc: + if exc.errno != errno.ENOENT: + raise + +def remove_files(name): + for f in _iter_files(name): unlink(f) @@ -120,6 +132,40 @@ class ImportTests(unittest.TestCase): unload(TESTFN) del sys.path[0] + def test_rewrite_pyc_with_read_only_source(self): + # Issue 6074: a long time ago on posix, and more recently on Windows, + # a read only source file resulted in a read only pyc file, which + # led to problems with updating it later + sys.path.insert(0, os.curdir) + fname = TESTFN + os.extsep + "py" + try: + # Write a Python file, make it read-only and import it + with open(fname, 'w') as f: + f.write("x = 'original'\n") + # Tweak the mtime of the source to ensure pyc gets updated later + s = os.stat(fname) + os.utime(fname, (s.st_atime, s.st_mtime-100000000)) + os.chmod(fname, 0400) + m1 = __import__(TESTFN) + self.assertEqual(m1.x, 'original') + # Change the file and then reimport it + os.chmod(fname, 0600) + with open(fname, 'w') as f: + f.write("x = 'rewritten'\n") + unload(TESTFN) + m2 = __import__(TESTFN) + self.assertEqual(m2.x, 'rewritten') + # Now delete the source file and check the pyc was rewritten + unlink(TESTFN) + unload(TESTFN) + m3 = __import__(TESTFN) + self.assertEqual(m3.x, 'rewritten') + finally: + chmod_files(TESTFN) + remove_files(TESTFN) + unload(TESTFN) + del sys.path[0] + def test_imp_module(self): # Verify that the imp module can correctly load and find .py files @@ -9,6 +9,9 @@ What's New in Python 2.7.4 Core and Builtins ----------------- +- Issue #6074: Ensure cached bytecode files can always be updated by the + user that created them, even when the source file is read-only. + - Issue #14783: Improve int() and long() docstrings and switch docstrings for unicode(), slice(), range(), and xrange() to use multi-line signatures. diff --git a/Python/import.c b/Python/import.c index 53c9b29..7daba06 100644 --- a/Python/import.c +++ b/Python/import.c @@ -910,6 +910,12 @@ write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat) time_t mtime = srcstat->st_mtime; #ifdef MS_WINDOWS /* since Windows uses different permissions */ mode_t mode = srcstat->st_mode & ~S_IEXEC; + /* Issue #6074: We ensure user write access, so we can delete it later + * when the source file changes. (On POSIX, this only requires write + * access to the directory, on Windows, we need write access to the file + * as well) + */ + mode |= _S_IWRITE; #else mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH; #endif |