summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2012-10-19 11:58:18 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2012-10-19 11:58:18 (GMT)
commitb48c028ca7b1f8a0215cfe12bbc32961743a554b (patch)
tree5253b5bae70d447b31d9a9032d0eefdd273b0d68
parent02f69f6965cc3793ffb68399da76a412244da270 (diff)
downloadcpython-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.py48
-rw-r--r--Misc/NEWS3
-rw-r--r--Python/import.c6
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
diff --git a/Misc/NEWS b/Misc/NEWS
index 80fc9f6..d87b9ed 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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