Issue 33968: os.makedirs and empty string
Created on 2018-06-26 12:01 by CarlAndersson, last changed 2022-04-11 14:59 by admin. This issue is now closed.
Messages (7)
msg320486 - (view)
Author: Carl Andersson (CarlAndersson)
Date: 2018-06-26 12:01
Date: 2018-06-26 14:35
Date: 2018-06-26 14:48
Date: 2018-06-26 15:18
Date: 2018-06-27 19:19
os.makedirs does not handle the empty string the same way as the os.path.XX functions does. This is (to me) unexpected behaviour, since calls like `os.makedirs(os.path.dirname(filename), exist_ok=True)` raises an exception if `filename` does not contain any directories.
Also, it raises an `FileNotFoundError` regardless of the `exist_ok` flag. I would expect `os.makedirs('')` to fail with `FileExistsError` and `os.makedirs('', exist_ok=True)` to not do anything.
msg320493 - (view)
Author: Emily Morehouse (emilyemorehouse) *
Date: 2018-06-26 14:35
This is an interesting behavior to note. I think the current behavior makes the most sense, as it corresponds to the OS-level errors that you get from running the same operations.
Interestingly, at least on Unix-based file systems, we get different error messages but the same behavior when using "" vs "." as our target:
[linux]$ mkdir ""
mkdir: cannot create directory ‘’: No such file or directory
[linux]$ mkdir .
mkdir: cannot create directory ‘.’: File exists
[mac]$ mkdir ""
mkdir: .: No such file or directory
[mac]$ mkdir .
mkdir: .: File exists
Both os.mkdir and os.makedirs follow (only os.mkdir is included as the traceback is cleaner, but they raise the same errors):
>>> os.mkdir("")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: ''
>>> os.mkdir(".")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileExistsError: [Errno 17] File exists: '.'
Since on an OS level the only time "File exists" is returned is when using "." and not "", os.makedirs with exists_ok=True also follows:
>>> os.makedirs("", exist_ok=True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/os.py", line 220, in makedirs
mkdir(name, mode)
FileNotFoundError: [Errno 2] No such file or directory: ''
>>> os.makedirs(".", exist_ok=True)
>>>
Basically, the FileExistsError gets silenced, but FileNotFoundError is left alone. I can see how the differences are nuanced and not obvious though.
Unless you think there is a succinct and worthwhile way of adding this to the documentation, I think this issue can be closed.
msg320495 - (view)
Author: Serhiy Storchaka (serhiy.storchaka) *
Date: 2018-06-26 14:48
Concur with Emily.msg320497 - (view) Author: Carl Andersson (CarlAndersson) Date: 2018-06-26 14:59
I can see the point in keeping the behaviour close to the OS-level commands, but the discrepancy between os.mkdir (or os.makedirs) and os.path.dirname is not resolved. I still think that >>> os.makedirs(os.path.dirname(filename), exist_ok=True) should be able to handle the case when "filename" does not contain any directories. A possible workaround would be to use os.path.abspath somewhere in the mix. In my humble opinion creating the directory structure required to write a file should not require this level of complexity, since it is such a common operation.msg320498 - (view) Author: Emily Morehouse (emilyemorehouse) *
Date: 2018-06-26 15:18
I'll defer to Serhiy's os.path expertise, but from what I know -- os.dirname is essentially a helper function for returning the first item of split.
What I'm gathering is that you're looking for a more advanced way of parsing a file path -- say "nested/dir/sample.txt" -- to "nested/dir" while also handling parsing "" into ".".
Not the prettiest, but you could wrap os.path.dirname in os.path.normpath:
>>> os.path.normpath(os.path.dirname("nested/dir/sample.txt"))
'nested/dir'
>>> os.path.normpath(os.path.dirname(""))
'.'
msg320552 - (view)
Author: Carl Andersson (CarlAndersson)
Date: 2018-06-27 07:57
That is in essence what I am looking for, yes. As you say, it's not pretty. My opinion is still that if the os.path convention is that '' is the same as '.', this should be respected.msg320606 - (view) Author: Emily Morehouse (emilyemorehouse) *
Date: 2018-06-27 19:19
The os.path conventions do follow, '' and '.' are not treated the same here either --
>>> os.path.exists('')
False
>>> os.path.exists('.')
True
>>> os.path.isdir('')
False
>>> os.path.isdir('.')
True
The only os.path function that I see as potentially confusing in this discussion is dirname, as that can return an empty string which yields unexpected results when used as an argument for other functions.
>>> os.path.dirname('testdir')
''
>>> os.path.dirname('./testdir')
'.'
However, changing this functionality (e.g. os.path.dirname('testdir') returning '.') would result in backward-compatibility issues that would not be warranted (IMO).
I'll leave the final word to Serhiy to close out as 'not a bug' at his discretion.
History
Date
User
Action
Args
2022-04-11 14:59:02adminsetgithub: 78149
2018-07-02 17:08:44emilyemorehousesetstatus: open -> closed
resolution: not a bug
stage: resolved 2018-06-27 19:19:24emilyemorehousesetassignee: emilyemorehouse
messages: + msg320497
2018-06-26 14:48:05serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg320495
2018-06-26 14:35:20emilyemorehousesetnosy: + emilyemorehouse
messages: + msg320493
2018-06-26 12:01:22CarlAnderssoncreate
resolution: not a bug
stage: resolved 2018-06-27 19:19:24emilyemorehousesetassignee: emilyemorehouse
messages:
+ msg320606
nosy:
+ serhiy.storchaka
messages: + msg320497
2018-06-26 14:48:05serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg320495
2018-06-26 14:35:20emilyemorehousesetnosy: + emilyemorehouse
messages: + msg320493
2018-06-26 12:01:22CarlAnderssoncreate