summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerry Reedy <tjreedy@udel.edu>2010-12-02 07:05:56 (GMT)
committerTerry Reedy <tjreedy@udel.edu>2010-12-02 07:05:56 (GMT)
commit5a22b651173f142a600625a036fcf36484ade237 (patch)
tree35221434a0451ee9cf205f2e9dc17a69af69d596
parent3cdf871a8c9bc5694a598bfdf22edece49584f48 (diff)
downloadcpython-5a22b651173f142a600625a036fcf36484ade237.zip
cpython-5a22b651173f142a600625a036fcf36484ade237.tar.gz
cpython-5a22b651173f142a600625a036fcf36484ade237.tar.bz2
Issue 9299 Add exist_ok parameter to os.makedirs to suppress 'File exists' exception. Patch by Ray Allen.
-rw-r--r--Doc/library/os.rst16
-rw-r--r--Lib/os.py26
-rw-r--r--Lib/test/test_os.py22
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS4
5 files changed, 58 insertions, 11 deletions
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index f3aad19..5d9a170 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -1143,17 +1143,20 @@ Files and Directories
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 @@ Files and Directories
This function handles UNC paths correctly.
+ .. versionadded:: 3.2
+ The *exist_ok* parameter.
+
.. function:: pathconf(path, name)
diff --git a/Lib/os.py b/Lib/os.py
index 89fd1f3..3ef3db8 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -114,18 +114,26 @@ SEEK_SET = 0
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 @@ def makedirs(name, mode=0o777):
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)
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 835e1f2..e27dd7a 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -630,6 +630,28 @@ class MakedirTests(unittest.TestCase):
'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')
diff --git a/Misc/ACKS b/Misc/ACKS
index 0f7ed37..d3ec047 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -18,6 +18,7 @@ Matthew Ahrens
Nir Aides
Yaniv Aknin
Jyrki Alakuijala
+Ray Allen
Billy G. Allie
Kevin Altis
Joe Amenta
diff --git a/Misc/NEWS b/Misc/NEWS
index b2c8258..f19b6f4 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -46,6 +46,10 @@ Core and Builtins
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