[Python-checkins] cpython (3.2): Issue #6074: Forward port Windows read-only source file fix from 2.7

nick.coghlan python-checkins at python.org
Fri Oct 19 14:38:29 CEST 2012


http://hg.python.org/cpython/rev/1856d57abfc8
changeset:   79828:1856d57abfc8
branch:      3.2
parent:      79826:7f0d9637a3ad
user:        Nick Coghlan <ncoghlan at gmail.com>
date:        Fri Oct 19 22:38:14 2012 +1000
summary:
  Issue #6074: Forward port Windows read-only source file fix from 2.7

files:
  Lib/test/test_import.py |  56 ++++++++++++++++++++++++++--
  Misc/NEWS               |   3 +
  Python/import.c         |   6 +++
  3 files changed, 60 insertions(+), 5 deletions(-)


diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py
--- a/Lib/test/test_import.py
+++ b/Lib/test/test_import.py
@@ -20,12 +20,24 @@
 from test import script_helper
 
 
+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, 0o600)
+        except OSError as exc:
+            if exc.errno != errno.ENOENT:
+                raise
+
 def remove_files(name):
-    for f in (name + ".py",
-              name + ".pyc",
-              name + ".pyo",
-              name + ".pyw",
-              name + "$py.class"):
+    for f in _iter_files(name):
         unlink(f)
     rmtree('__pycache__')
 
@@ -122,6 +134,40 @@
                 remove_files(TESTFN)
                 unload(TESTFN)
 
+    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, 0o400)
+            m1 = __import__(TESTFN)
+            self.assertEqual(m1.x, 'original')
+            # Change the file and then reimport it
+            os.chmod(fname, 0o600)
+            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
         # XXX (ncoghlan): It would be nice to use support.CleanImport
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 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() docstring and switch docstrings for str(),
   range(), and slice() to use multi-line signatures.
 
diff --git a/Python/import.c b/Python/import.c
--- a/Python/import.c
+++ b/Python/import.c
@@ -1174,6 +1174,12 @@
     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;
     mode_t dirmode = (srcstat->st_mode |

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list