I am attempting to convert the following pseudo-code to Python:
If <directory> does not exist: Create all subdirectories for <directory> Create a file in <directory>
This sounds simple enough to accomplish with os.makedirs
and os.path.isdir
:
if not os.path.isdir('/some/path'):
os.makedirs('/some/path')
open('/some/path/test.txt', 'w')
However, upon further inspection there is clearly a race condition present. Consider the following timeline:
/some/path
) does not existTrue
/some/path
)makedirs
raises an OSError
exception since the directory already existsThere are also problems if the directory does initially exist but is removed by another process before the final line is executed.
When it comes to Python, "it's easier to ask for forgiveness than permission." With that in mind, the fragment above could be better written:
try:
os.makedirs('/some/path')
except OSError:
pass
open('/some/path/test.txt', 'w')
This solves the two problems described above but creates a third: os.makedirs
raises an OSError
exception when one of the following conditions occurs:
This means that there is no way to determine which of the two conditions caused the exception to be raised. In other words, actual failures will be silently ignored, which is not what I want.
How can I work around this problem?
I'll note that all of this is quite a bit more sane in python 3; FileExistsError
and PermissionError
are separate (subclass of OSError
) exceptions that you can catch, and os.makedirs
even has a exist_ok
kwarg to suppress the former when you're ok with the directory already existing.
If you want to inspect the reason for the OSError
, that info is in a tuple in e.args
(or optionally e.errno
if you just want to look at the error code):
try:
os.makedirs('/etc/python')
except OSError as e:
print e.args
(17, 'File exists')
try:
os.makedirs('/etc/stuff')
except OSError as e:
print e.args
(13, 'Permission denied')
try:
os.makedirs('/etc/stuff')
except OSError as e:
print e.errno
13
So you'll have to do a bit of introspection and handle the two error codes differently in your except
block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With