Index: Doc/library/os.rst =================================================================== --- Doc/library/os.rst (revision 82985) +++ Doc/library/os.rst (working copy) @@ -1113,12 +1113,13 @@ Compose a raw device number from the major and minor device numbers. -.. function:: mkdir(path[, mode]) +.. function:: mkdir(path[, mode[, exist_ok]]) Create a directory named *path* with numeric mode *mode*. 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 the directory already - exists, :exc:`OSError` is raised. + exists, :exc:`OSError` is raised if *exist_ok* is False, otherwise no + exception is raised. It is also possible to create temporary directories; see the :mod:`tempfile` module's :func:`tempfile.mkdtemp` function. @@ -1126,7 +1127,7 @@ Availability: Unix, Windows. -.. function:: makedirs(path[, mode]) +.. function:: makedirs(path[, mode[, exist_ok]]) .. index:: single: directory; creating Index: Lib/os.py =================================================================== --- Lib/os.py (revision 82985) +++ Lib/os.py (working copy) @@ -119,8 +119,8 @@ # 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 @@ -133,14 +133,14 @@ 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) + mkdir(name, mode, exist_ok) def removedirs(name): """removedirs(path) Index: Lib/test/test_os.py =================================================================== --- Lib/test/test_os.py (revision 82985) +++ Lib/test/test_os.py (working copy) @@ -609,6 +609,14 @@ 'dir5', 'dir6') os.makedirs(path) + def test_exist_ok(self): + base = support.TESTFN + path = os.path.join(support.TESTFN, 'dir1') + os.makedirs(path) + self.assertRaises(OSError, os.makedirs, path) + self.assertRaises(OSError, os.makedirs, path, exist_ok=False) + os.makedirs(path, exist_ok=True) + def tearDown(self): path = os.path.join(support.TESTFN, 'dir1', 'dir2', 'dir3', 'dir4', 'dir5', 'dir6') Index: Modules/posixmodule.c =================================================================== --- Modules/posixmodule.c (revision 82985) +++ Modules/posixmodule.c (working copy) @@ -2727,26 +2727,29 @@ #endif /* MS_WINDOWS */ PyDoc_STRVAR(posix_mkdir__doc__, -"mkdir(path [, mode=0777])\n\n\ +"mkdir(path [, mode=0o777[, exist_ok=False]])\n\n\ Create a directory."); static PyObject * -posix_mkdir(PyObject *self, PyObject *args) +posix_mkdir(PyObject *self, PyObject *args, PyObject *kwdict) { int res; PyObject *opath; char *path; int mode = 0777; + int exist_ok = 0; + static char *kwlist[] = {"path", "mode", "exist_ok", NULL}; #ifdef MS_WINDOWS PyUnicodeObject *po; - if (PyArg_ParseTuple(args, "U|i:mkdir", &po, &mode)) { + if (PyArg_ParseTupleAndKeywords(args, kwdict, "U|ii:mkdir", + kwlist, &po, &mode, &exist_ok)) { Py_BEGIN_ALLOW_THREADS /* PyUnicode_AS_UNICODE OK without thread lock as it is a simple dereference. */ res = CreateDirectoryW(PyUnicode_AS_UNICODE(po), NULL); Py_END_ALLOW_THREADS - if (!res) + if (!res && !(res == ERROR_ALREADY_EXISTS && exist_ok)) return win32_error_unicode("mkdir", PyUnicode_AS_UNICODE(po)); Py_INCREF(Py_None); return Py_None; @@ -2754,8 +2757,8 @@ /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&|i:mkdir", - PyUnicode_FSConverter, &opath, &mode)) + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O&|ii:mkdir", kwlist, + PyUnicode_FSConverter, &opath, &mode, &exist_ok)) return NULL; path = PyBytes_AsString(opath); Py_BEGIN_ALLOW_THREADS @@ -2763,7 +2766,7 @@ it is a simple dereference. */ res = CreateDirectoryA(path, NULL); Py_END_ALLOW_THREADS - if (!res) { + if (!res && !(res == ERROR_ALREADY_EXISTS && exist_ok)) { win32_error("mkdir", path); Py_DECREF(opath); return NULL; @@ -2773,8 +2776,8 @@ return Py_None; #else - if (!PyArg_ParseTuple(args, "O&|i:mkdir", - PyUnicode_FSConverter, &opath, &mode)) + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O&|ii:mkdir", kwlist, + PyUnicode_FSConverter, &opath, &mode, &exist_ok)) return NULL; path = PyBytes_AsString(opath); Py_BEGIN_ALLOW_THREADS @@ -2784,7 +2787,7 @@ res = mkdir(path, mode); #endif Py_END_ALLOW_THREADS - if (res < 0) + if (res < 0 && !(errno == EEXIST && exist_ok)) return posix_error_with_allocated_filename(opath); Py_DECREF(opath); Py_INCREF(Py_None); @@ -7579,7 +7582,8 @@ #endif /* HAVE_LINK */ {"listdir", posix_listdir, METH_VARARGS, posix_listdir__doc__}, {"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__}, - {"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__}, + {"mkdir", (PyCFunction)posix_mkdir, METH_VARARGS | METH_KEYWORDS, + posix_mkdir__doc__}, #ifdef HAVE_NICE {"nice", posix_nice, METH_VARARGS, posix_nice__doc__}, #endif /* HAVE_NICE */