Skip to content

Commit 0805291

Browse files
committed
Fix behavior of fake os.makedirs
- use a similar implementation as the real fs
1 parent 7285b67 commit 0805291

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ The released versions correspond to PyPI releases.
3232
(see [#979](../../issues/979))
3333
* fixed handling of errors on opening files via file descriptor (see [#967](../../issues/967))
3434
* fixed handling of `umask` - it is now applied by default
35+
* fixed behavior of `os.makedirs` (see [#987](../../issues/987))
3536

3637
### Infrastructure
3738
* replace `undefined` by own minimal implementation to avoid importing it

pyfakefs/fake_os.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,27 @@ def makedirs(
931931
"""
932932
if exist_ok is None:
933933
exist_ok = False
934-
self.filesystem.makedirs(name, mode, exist_ok)
934+
935+
# copied and adapted from real implementation in os.py (Python 3.12)
936+
head, tail = self.filesystem.splitpath(name)
937+
if not tail:
938+
head, tail = self.filesystem.splitpath(head)
939+
if head and tail and not self.filesystem.exists(head):
940+
try:
941+
self.makedirs(head, exist_ok=exist_ok)
942+
except FileExistsError:
943+
pass
944+
cdir = self.filesystem.cwd
945+
if isinstance(tail, bytes):
946+
if tail == bytes(cdir, "ASCII"):
947+
return
948+
elif tail == cdir:
949+
return
950+
try:
951+
self.mkdir(name, mode)
952+
except OSError:
953+
if not exist_ok or not self.filesystem.isdir(name):
954+
raise
935955

936956
def _path_with_dir_fd(
937957
self,

pyfakefs/tests/fake_os_test.py

+8
Original file line numberDiff line numberDiff line change
@@ -1893,6 +1893,14 @@ def test_makedirs_raises_on_empty_path(self):
18931893
self.assert_raises_os_error(errno.ENOENT, self.os.makedirs, "", exist_ok=False)
18941894
self.assert_raises_os_error(errno.ENOENT, self.os.makedirs, "", exist_ok=True)
18951895

1896+
def test_makedirs_with_relative_paths(self):
1897+
# regression test for #987
1898+
path = self.make_path("base", "foo", "..", "bar")
1899+
self.os.makedirs(path)
1900+
self.assertTrue(self.os.path.isdir(self.make_path("base", "bar")))
1901+
self.assertTrue(self.os.path.isdir(self.make_path("base", "foo")))
1902+
self.assertFalse(self.os.path.isdir(self.make_path("base", "foo", "bar")))
1903+
18961904
# test fsync and fdatasync
18971905
def test_fsync_raises_on_non_int(self):
18981906
with self.assertRaises(TypeError):

0 commit comments

Comments
 (0)