[Python-checkins] cpython (merge 3.2 -> 3.3): merge 3.2 (#21082)

benjamin.peterson python-checkins at python.org
Wed Apr 2 01:22:29 CEST 2014


http://hg.python.org/cpython/rev/6370d44013f7
changeset:   90095:6370d44013f7
branch:      3.3
parent:      90071:cb3a8abc0870
parent:      90094:9186f4a18584
user:        Benjamin Peterson <benjamin at python.org>
date:        Tue Apr 01 19:17:57 2014 -0400
summary:
  merge 3.2 (#21082)

files:
  Doc/library/os.rst  |  14 +++++++++-----
  Lib/os.py           |  30 +++++-------------------------
  Lib/test/test_os.py |   7 +++----
  Misc/NEWS           |   3 +++
  4 files changed, 20 insertions(+), 34 deletions(-)


diff --git a/Doc/library/os.rst b/Doc/library/os.rst
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -1563,11 +1563,8 @@
    The default *mode* is ``0o777`` (octal).  On some systems, *mode* is
    ignored.  Where it is used, the current umask value is first masked out.
 
-   If *exist_ok* is ``False`` (the default), an :exc:`OSError` is raised if
-   the target directory already exists.  If *exist_ok* is ``True`` an
-   :exc:`OSError` is still raised if the umask-masked *mode* is different from
-   the existing mode, on systems where the mode is used.  :exc:`OSError` will
-   also be raised if the directory creation fails.
+   If *exist_ok* is ``False`` (the default), an :exc:`OSError` is raised if the
+   target directory already exists.
 
    .. note::
 
@@ -1579,6 +1576,13 @@
    .. versionadded:: 3.2
       The *exist_ok* parameter.
 
+   .. versionchanged:: 3.3.6
+
+      Before Python 3.3.6, if *exist_ok* was ``True`` and the directory existed,
+      :func:`makedirs` would still raise an error if *mode* did not match the
+      mode of the existing directory. Since this behavior was impossible to
+      implement safely, it was removed in Python 3.3.6. See :issue:`21082`.
+
 
 .. function:: mkfifo(path, mode=0o666, *, dir_fd=None)
 
diff --git a/Lib/os.py b/Lib/os.py
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -230,23 +230,16 @@
 SEEK_CUR = 1
 SEEK_END = 2
 
-
-def _get_masked_mode(mode):
-    mask = umask(0)
-    umask(mask)
-    return mode & ~mask
-
 # Super directory utilities.
 # (Inspired by Eric Raymond; the doc strings are mostly his)
 
 def makedirs(name, mode=0o777, exist_ok=False):
     """makedirs(path [, mode=0o777][, exist_ok=False])
 
-    Super-mkdir; create a leaf directory and all intermediate ones.
-    Works like mkdir, except that any intermediate path segment (not
-    just the rightmost) will be created if it does not exist. If the
-    target directory with the same mode as we specified already exists,
-    raises an OSError if exist_ok is False, otherwise no exception is
+    Super-mkdir; create a leaf directory and all intermediate ones.  Works like
+    mkdir, except that any intermediate path segment (not just the rightmost)
+    will be created if it does not exist. If the target directory already
+    exists, raise an OSError if exist_ok is False. Otherwise no exception is
     raised.  This is recursive.
 
     """
@@ -268,20 +261,7 @@
     try:
         mkdir(name, mode)
     except OSError as e:
-        dir_exists = path.isdir(name)
-        expected_mode = _get_masked_mode(mode)
-        if dir_exists:
-            # S_ISGID is automatically copied by the OS from parent to child
-            # directories on mkdir.  Don't consider it being set to be a mode
-            # mismatch as mkdir does not unset it when not specified in mode.
-            actual_mode = st.S_IMODE(lstat(name).st_mode) & ~st.S_ISGID
-        else:
-            actual_mode = -1
-        if not (e.errno == errno.EEXIST and exist_ok and dir_exists and
-                actual_mode == expected_mode):
-            if dir_exists and actual_mode != expected_mode:
-                e.strerror += ' (mode %o != expected mode %o)' % (
-                        actual_mode, expected_mode)
+        if not exist_ok or e.errno != errno.EEXIST or not path.isdir(name):
             raise
 
 def removedirs(name):
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -872,7 +872,7 @@
         os.makedirs(path, mode)
         self.assertRaises(OSError, os.makedirs, path, mode)
         self.assertRaises(OSError, os.makedirs, path, mode, exist_ok=False)
-        self.assertRaises(OSError, os.makedirs, path, 0o776, exist_ok=True)
+        os.makedirs(path, 0o776, exist_ok=True)
         os.makedirs(path, mode=mode, exist_ok=True)
         os.umask(old_mask)
 
@@ -898,9 +898,8 @@
             os.makedirs(path, mode, exist_ok=True)
             # remove the bit.
             os.chmod(path, stat.S_IMODE(os.lstat(path).st_mode) & ~S_ISGID)
-            with self.assertRaises(OSError):
-                # Should fail when the bit is not already set when demanded.
-                os.makedirs(path, mode | S_ISGID, exist_ok=True)
+            # May work even when the bit is not already set when demanded.
+            os.makedirs(path, mode | S_ISGID, exist_ok=True)
         finally:
             os.umask(old_mask)
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -15,6 +15,9 @@
 
 - Issue #20633: Replace relative import by absolute import.
 
+- Issue #21082: In os.makedirs, do not set the process-wide umask. Note this
+  changes behavior of makedirs when exist_ok=True.
+
 - Issue #20875: Prevent possible gzip "'read' is not defined" NameError.
   Patch by Claudiu Popa.
 

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


More information about the Python-checkins mailing list