]> granicus.if.org Git - python/commitdiff
bpo-25803: Avoid incorrect errors raised by Path.mkdir(exist_ok=True) (#805) (#807)
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 24 Mar 2017 19:46:46 +0000 (21:46 +0200)
committerGitHub <noreply@github.com>
Fri, 24 Mar 2017 19:46:46 +0000 (21:46 +0200)
when the OS gives priority to errors such as EACCES over EEXIST.

(cherry picked from commit af7b9ec5c855366feef4c67dc492d64b3baf84ca)

Lib/pathlib.py
Lib/test/test_pathlib.py
Misc/NEWS

index c0d858ef56120aa471e8cbaf5a71dc5a30495ec6..16b99cddbc71834dd8182af2c6686f23cebc4abb 100644 (file)
@@ -1207,25 +1207,23 @@ class Path(PurePath):
         os.close(fd)
 
     def mkdir(self, mode=0o777, parents=False, exist_ok=False):
+        """
+        Create a new directory at this given path.
+        """
         if self._closed:
             self._raise_closed()
-        if not parents:
-            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 or self.parent == self:
-                    raise
-                self.parent.mkdir(parents=True)
-                self._accessor.mkdir(self, mode)
+        try:
+            self._accessor.mkdir(self, mode)
+        except FileNotFoundError:
+            if not parents or self.parent == self:
+                raise
+            self.parent.mkdir(parents=True)
+            self._accessor.mkdir(self, mode)
+        except OSError:
+            # Cannot rely on checking for EEXIST, since the operating system
+            # could give priority to other errors like EACCES or EROFS
+            if not exist_ok or not self.is_dir():
+                raise
 
     def chmod(self, mode):
         """
index 28e3ea4da6e28c573ca4e52037563b727734073b..86d3077d5c4458836b048acdb14d5bda1c10bc44 100644 (file)
@@ -1727,6 +1727,11 @@ class _BasePathTest(object):
         self.assertTrue(p.exists())
         self.assertEqual(p.stat().st_ctime, st_ctime_first)
 
+    def test_mkdir_exist_ok_root(self):
+        # Issue #25803: A drive root could raise PermissionError on Windows
+        self.cls('/').resolve().mkdir(exist_ok=True)
+        self.cls('/').resolve().mkdir(parents=True, exist_ok=True)
+
     @only_nt    # XXX: not sure how to test this on POSIX
     def test_mkdir_with_unknown_drive(self):
         for d in 'ZYXWVUTSRQPONMLKJIHGFEDCBA':
index cc219d4bed0d49d9874b5b7918ce8a193d105145..f541504e0cdc5fd0d4c13434efe6412bdbf67453 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -46,6 +46,9 @@ Extension Modules
 Library
 -------
 
+- bpo-25803: Avoid incorrect errors raised by Path.mkdir(exist_ok=True)
+  when the OS gives priority to errors such as EACCES over EEXIST.
+
 - bpo-29861: Release references to tasks, their arguments and their results
   as soon as they are finished in multiprocessing.Pool.