Credit: Trent Mick, Alex Martelli
A good make-directory function should, first of all, make the
necessary parent directories, which os.makedirs
does quite nicely. We also want our function to complete silently if
the directory already exists but to fail if the needed directory
exists as a plain file. To get that behavior, we need to write some
code:
import os, errno def mkdirs(newdir, mode=0777): try: os.makedirs(newdir, mode) except OSError, err: # Reraise the error unless it's about an already existing directory if err.errno != errno.EEXIST or not os.path.isdir(newdir): raise
Python’s standard os.mkdir
works
much like the underlying mkdir system call
(i.e., in a pretty spare and rigorous way). For example, it raises an
exception when the directory you’re trying to make
already exists. You almost always have to handle that exception,
because it’s not generally an error if the directory
already exists as a directory, while it is indeed an error if a file
of that name is in the way. Further, all the parent directories of
the one you’re trying to make must already exist, as
os.mkdir
itself only makes the leaf directory out
of the whole path.
There used to be a time when mkdir, as used in
Unix shell scripts, worked the same way, but we’re
spoiled now. For example, the --parents
switch in
the GNU version of mkdir implicitly creates all
intermediate directories, and gives no error if the target directory
already exists as a directory. Well, why not have the same
convenience in Python?
This
recipe shows it takes very little to achieve this—the little
function mkdirs
can easily become part of your
standard bag of tricks. Of course, Python’s standard
os.makedirs
is doing most of the job. However,
mkdirs
adds the important convenience of not
propagating an exception when the requested directory already exists
and is indeed a directory. However, if the requested directory exists
as a file or if the operating system diagnoses any other kind of
trouble, function mkdirs
does explicitly re-raise
the exception, to ensure it propagates further.