- Issue #21539: Add a *exists_ok* argument to `Pathlib.mkdir()` to mimic
`mkdir -p` and `os.makedirs()` functionality. When true, ignore FileExistsErrors. Patch by Berker Peksag. (With minor cleanups, additional tests, doc tweaks, etc. by Barry) Also: * Remove some unused imports in test_pathlib.py reported by pyflakes.
This commit is contained in:
parent
17fd1e1013
commit
7c549c4e64
|
@ -791,7 +791,7 @@ call fails (for example because the path doesn't exist):
|
|||
the symbolic link's information rather than its target's.
|
||||
|
||||
|
||||
.. method:: Path.mkdir(mode=0o777, parents=False)
|
||||
.. method:: Path.mkdir(mode=0o777, parents=False, exist_ok=False)
|
||||
|
||||
Create a new directory at this given path. If *mode* is given, it is
|
||||
combined with the process' ``umask`` value to determine the file mode
|
||||
|
@ -805,6 +805,16 @@ call fails (for example because the path doesn't exist):
|
|||
If *parents* is false (the default), a missing parent raises
|
||||
:exc:`FileNotFoundError`.
|
||||
|
||||
If *exist_ok* is false (the default), an :exc:`FileExistsError` is
|
||||
raised if the target directory already exists.
|
||||
|
||||
If *exist_ok* is true, :exc:`FileExistsError` exceptions will be
|
||||
ignored (same behavior as the POSIX ``mkdir -p`` command), but only if the
|
||||
last path component is not an existing non-directory file.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
The *exist_ok* parameter was added.
|
||||
|
||||
|
||||
.. method:: Path.open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)
|
||||
|
||||
|
|
|
@ -1106,14 +1106,21 @@ class Path(PurePath):
|
|||
fd = self._raw_open(flags, mode)
|
||||
os.close(fd)
|
||||
|
||||
def mkdir(self, mode=0o777, parents=False):
|
||||
def mkdir(self, mode=0o777, parents=False, exist_ok=False):
|
||||
if self._closed:
|
||||
self._raise_closed()
|
||||
if not parents:
|
||||
self._accessor.mkdir(self, mode)
|
||||
try:
|
||||
self._accessor.mkdir(self, mode)
|
||||
except FileExistsError:
|
||||
if not exist_ok or not self.is_dir():
|
||||
raise
|
||||
else:
|
||||
try:
|
||||
self._accessor.mkdir(self, mode)
|
||||
except FileExistsError:
|
||||
if not exist_ok or not self.is_dir():
|
||||
raise
|
||||
except OSError as e:
|
||||
if e.errno != ENOENT:
|
||||
raise
|
||||
|
|
|
@ -4,13 +4,10 @@ import os
|
|||
import errno
|
||||
import pathlib
|
||||
import pickle
|
||||
import shutil
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
|
||||
from test import support
|
||||
TESTFN = support.TESTFN
|
||||
|
@ -743,7 +740,6 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
|
|||
self.assertEqual(P('//Some/SHARE/a/B'), P('//somE/share/A/b'))
|
||||
|
||||
def test_as_uri(self):
|
||||
from urllib.parse import quote_from_bytes
|
||||
P = self.cls
|
||||
with self.assertRaises(ValueError):
|
||||
P('/a/b').as_uri()
|
||||
|
@ -1617,6 +1613,59 @@ class _BasePathTest(object):
|
|||
# the parent's permissions follow the default process settings
|
||||
self.assertEqual(stat.S_IMODE(p.parent.stat().st_mode), mode)
|
||||
|
||||
def test_mkdir_exist_ok(self):
|
||||
p = self.cls(BASE, 'dirB')
|
||||
st_ctime_first = p.stat().st_ctime
|
||||
self.assertTrue(p.exists())
|
||||
self.assertTrue(p.is_dir())
|
||||
with self.assertRaises(FileExistsError) as cm:
|
||||
p.mkdir()
|
||||
self.assertEqual(cm.exception.errno, errno.EEXIST)
|
||||
p.mkdir(exist_ok=True)
|
||||
self.assertTrue(p.exists())
|
||||
self.assertEqual(p.stat().st_ctime, st_ctime_first)
|
||||
|
||||
def test_mkdir_exist_ok_with_parent(self):
|
||||
p = self.cls(BASE, 'dirC')
|
||||
self.assertTrue(p.exists())
|
||||
with self.assertRaises(FileExistsError) as cm:
|
||||
p.mkdir()
|
||||
self.assertEqual(cm.exception.errno, errno.EEXIST)
|
||||
p = p / 'newdirC'
|
||||
p.mkdir(parents=True)
|
||||
st_ctime_first = p.stat().st_ctime
|
||||
self.assertTrue(p.exists())
|
||||
with self.assertRaises(FileExistsError) as cm:
|
||||
p.mkdir(parents=True)
|
||||
self.assertEqual(cm.exception.errno, errno.EEXIST)
|
||||
p.mkdir(parents=True, exist_ok=True)
|
||||
self.assertTrue(p.exists())
|
||||
self.assertEqual(p.stat().st_ctime, st_ctime_first)
|
||||
|
||||
def test_mkdir_with_child_file(self):
|
||||
p = self.cls(BASE, 'dirB', 'fileB')
|
||||
self.assertTrue(p.exists())
|
||||
# An exception is raised when the last path component is an existing
|
||||
# regular file, regardless of whether exist_ok is true or not.
|
||||
with self.assertRaises(FileExistsError) as cm:
|
||||
p.mkdir(parents=True)
|
||||
self.assertEqual(cm.exception.errno, errno.EEXIST)
|
||||
with self.assertRaises(FileExistsError) as cm:
|
||||
p.mkdir(parents=True, exist_ok=True)
|
||||
self.assertEqual(cm.exception.errno, errno.EEXIST)
|
||||
|
||||
def test_mkdir_no_parents_file(self):
|
||||
p = self.cls(BASE, 'fileA')
|
||||
self.assertTrue(p.exists())
|
||||
# An exception is raised when the last path component is an existing
|
||||
# regular file, regardless of whether exist_ok is true or not.
|
||||
with self.assertRaises(FileExistsError) as cm:
|
||||
p.mkdir()
|
||||
self.assertEqual(cm.exception.errno, errno.EEXIST)
|
||||
with self.assertRaises(FileExistsError) as cm:
|
||||
p.mkdir(exist_ok=True)
|
||||
self.assertEqual(cm.exception.errno, errno.EEXIST)
|
||||
|
||||
@with_symlinks
|
||||
def test_symlink_to(self):
|
||||
P = self.cls(BASE)
|
||||
|
@ -1852,7 +1901,6 @@ class PosixPathTest(_BasePathTest, unittest.TestCase):
|
|||
@with_symlinks
|
||||
def test_resolve_loop(self):
|
||||
# Loop detection for broken symlinks under POSIX
|
||||
P = self.cls
|
||||
# Loops with relative symlinks
|
||||
os.symlink('linkX/inside', join('linkX'))
|
||||
self._check_symlink_loop(BASE, 'linkX')
|
||||
|
|
|
@ -307,7 +307,7 @@ class PlatformTest(unittest.TestCase):
|
|||
with mock.patch('platform._UNIXCONFDIR', tempdir):
|
||||
distname, version, distid = platform.linux_distribution()
|
||||
|
||||
self.assertEqual(distname, 'Fedora')
|
||||
self.assertEqual(distname, 'Fedora')
|
||||
self.assertEqual(version, '19')
|
||||
self.assertEqual(distid, 'Schr\xf6dinger\u2019s Cat')
|
||||
|
||||
|
|
|
@ -123,6 +123,10 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #21539: Add a *exists_ok* argument to `Pathlib.mkdir()` to mimic
|
||||
`mkdir -p` and `os.makedirs()` functionality. When true, ignore
|
||||
FileExistsErrors. Patch by Berker Peksag.
|
||||
|
||||
- Issue #21047: set the default value for the *convert_charrefs* argument
|
||||
of HTMLParser to True. Patch by Berker Peksag.
|
||||
|
||||
|
|
Loading…
Reference in New Issue