mirror of https://github.com/python/cpython
Issue 9299 Add exist_ok parameter to os.makedirs to suppress 'File exists' exception. Patch by Ray Allen.
This commit is contained in:
parent
3cdf871a8c
commit
5a22b65117
|
@ -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)
|
||||
|
||||
|
|
26
Lib/os.py
26
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)
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -18,6 +18,7 @@ Matthew Ahrens
|
|||
Nir Aides
|
||||
Yaniv Aknin
|
||||
Jyrki Alakuijala
|
||||
Ray Allen
|
||||
Billy G. Allie
|
||||
Kevin Altis
|
||||
Joe Amenta
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue