[Python-checkins] r86930 - in python/branches/py3k: Doc/library/os.rst Lib/os.py Lib/test/test_os.py Misc/ACKS Misc/NEWS

terry.reedy python-checkins at python.org
Thu Dec 2 08:05:57 CET 2010


Author: terry.reedy
Date: Thu Dec  2 08:05:56 2010
New Revision: 86930

Log:
Issue 9299 Add exist_ok parameter to os.makedirs to suppress 'File exists' exception. Patch by Ray Allen.


Modified:
   python/branches/py3k/Doc/library/os.rst
   python/branches/py3k/Lib/os.py
   python/branches/py3k/Lib/test/test_os.py
   python/branches/py3k/Misc/ACKS
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Doc/library/os.rst
==============================================================================
--- python/branches/py3k/Doc/library/os.rst	(original)
+++ python/branches/py3k/Doc/library/os.rst	Thu Dec  2 08:05:56 2010
@@ -1143,17 +1143,20 @@
    Availability: Unix, Windows.
 
 
-.. function:: makedirs(path[, mode])
+.. function:: makedirs(path[, mode][, exist_ok=False])
 
    .. index::
       single: directory; creating
       single: UNC paths; and os.makedirs()
 
    Recursive directory creation function.  Like :func:`mkdir`, but makes all
-   intermediate-level directories needed to contain the leaf directory.  Raises
-   an :exc:`error` exception if the leaf directory already exists or cannot be
-   created.  The default *mode* is ``0o777`` (octal).  On some systems, *mode*
-   is ignored. Where it is used, the current umask value is first masked out.
+   intermediate-level directories needed to contain the leaf directory.  If
+   the target directory with the same mode as we specified already exists,
+   raises an :exc:`OSError` exception if *exist_ok* is False, otherwise no
+   exception is raised.  If the directory cannot be created in other cases,
+   raises an :exc:`OSError` exception.  The default *mode* is ``0o777`` (octal).
+   On some systems, *mode* is ignored. Where it is used, the current umask
+   value is first masked out.
 
    .. note::
 
@@ -1162,6 +1165,9 @@
 
    This function handles UNC paths correctly.
 
+   .. versionadded:: 3.2
+      The *exist_ok* parameter.
+
 
 .. function:: pathconf(path, name)
 

Modified: python/branches/py3k/Lib/os.py
==============================================================================
--- python/branches/py3k/Lib/os.py	(original)
+++ python/branches/py3k/Lib/os.py	Thu Dec  2 08:05:56 2010
@@ -114,18 +114,26 @@
 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):
-    """makedirs(path [, mode=0o777])
+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.  This is
-    recursive.
+    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
+    raised.  This is recursive.
 
     """
     head, tail = path.split(name)
@@ -133,14 +141,20 @@
         head, tail = path.split(head)
     if head and tail and not path.exists(head):
         try:
-            makedirs(head, mode)
+            makedirs(head, mode, exist_ok)
         except OSError as e:
             # be happy if someone already created the path
             if e.errno != errno.EEXIST:
                 raise
         if tail == curdir:           # xxx/newdir/. exists if xxx/newdir exists
             return
-    mkdir(name, mode)
+    try:
+        mkdir(name, mode)
+    except OSError as e:
+        import stat as st
+        if not (e.errno == errno.EEXIST and exist_ok and path.isdir(name) and
+                st.S_IMODE(lstat(name).st_mode) == _get_masked_mode(mode)):
+            raise
 
 def removedirs(name):
     """removedirs(path)

Modified: python/branches/py3k/Lib/test/test_os.py
==============================================================================
--- python/branches/py3k/Lib/test/test_os.py	(original)
+++ python/branches/py3k/Lib/test/test_os.py	Thu Dec  2 08:05:56 2010
@@ -630,6 +630,28 @@
                             'dir5', 'dir6')
         os.makedirs(path)
 
+    def test_exist_ok_existing_directory(self):
+        path = os.path.join(support.TESTFN, 'dir1')
+        mode = 0o777
+        old_mask = os.umask(0o022)
+        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, mode=mode, exist_ok=True)
+        os.umask(old_mask)
+
+    def test_exist_ok_existing_regular_file(self):
+        base = support.TESTFN
+        path = os.path.join(support.TESTFN, 'dir1')
+        f = open(path, 'w')
+        f.write('abc')
+        f.close()
+        self.assertRaises(OSError, os.makedirs, path)
+        self.assertRaises(OSError, os.makedirs, path, exist_ok=False)
+        self.assertRaises(OSError, os.makedirs, path, exist_ok=True)
+        os.remove(path)
+
     def tearDown(self):
         path = os.path.join(support.TESTFN, 'dir1', 'dir2', 'dir3',
                             'dir4', 'dir5', 'dir6')

Modified: python/branches/py3k/Misc/ACKS
==============================================================================
--- python/branches/py3k/Misc/ACKS	(original)
+++ python/branches/py3k/Misc/ACKS	Thu Dec  2 08:05:56 2010
@@ -18,6 +18,7 @@
 Nir Aides
 Yaniv Aknin
 Jyrki Alakuijala
+Ray Allen
 Billy G. Allie
 Kevin Altis
 Joe Amenta

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Thu Dec  2 08:05:56 2010
@@ -46,6 +46,10 @@
 Library
 -------
 
+- Issue #9299: Add exist_ok parameter to os.makedirs to suppress the
+  'File exists' exception when a target directory already exists with the
+  specified mode. Patch by Ray Allen.
+
 - Issue #9573: os.fork() now works correctly when triggered as a side effect
   of a module import
 


More information about the Python-checkins mailing list