Workflow to create a folder if it doesn't exist already - python

In this interesting thread, the users give some options to create a directory if it doesn't exist.
The answer with most votes it's obviously the most popular, I guess because its the shortest way:
if not os.path.exists(directory):
os.makedirs(directory)
The function included in the 2nd answer seems more robust, and in my opinion the best way to do it.
import os
import errno
def make_sure_path_exists(path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
So I was wondering, what does people do in their scripts? Type 2 lines just to create a folder? Or even worst, copy, and paste the function make_sure_path_exists in every script that needs to create a folder?
I'd expect that such a wide spread programming language as Python would already have a library with includes a similar function.
The other 2 programming languages that I know, which are more like scripting languages, can do this with ease.
Bash: mkdir -p path
Powershell: New-Item -Force path
Please don't take this question as a rant against Python, because it's not intended to be like that.
I'm planing to learn Python to write scripts where 90% of the time I'll have to create folders, and I'd like to know what is the most productive way to do so.
I really think I'm missing something about Python.

you can use the below
# file handler
import os
filename = "./logs/mylog.log"
os.makedirs(os.path.dirname(filename), exist_ok=True)

make a module with make_sure_path_exists defined in it. import it when needed.

Getting help from different answers I produced this code
if not os.path.exists(os.getcwd() + '/' + folderName):
os.makedirs(os.getcwd() + '/' + folderName, exist_ok=True)

import os
def main():
dirName = 'C:/SANAL'
# Create target directory & all intermediate directories if don't exists
try:
os.makedirs(dirName)
print("Directory " , dirName , " Created ")
except FileExistsError:
print("Directory " , dirName , " already exists")
if __name__ == '__main__':
main()
f = open('C:/SANAL/merhabadünya.txt','w')
for i in range (10):
f.write('MERHABA %d\r\n' % (i+1))
f.close()
f = open('C:/SANAL/merhabadünya.txt','r')
message = f.read()
print(message)
f.close()

None of the current answers provide a clear explanation on how to make os.makedirs idempotent and many are superfluous. Here’s a clear answer with minimal examples:
Python 3
We simply set the exists_ok flag to True.
A Working Example
import os
directory = “my/test/directory/”
os.makedirs(directory, exists_ok = True)
Python 2
We can manually handle it. One way to do this is to check whether the directory already exists using a conditional:
A Working Example
import os
directory = “my/test/directory/”
if not os.path.exists(directory):
os.makedirs(directory)
Running each working example, you should get no error after multiple executions.

Related

How do I get the current file path in python dm-script

I want to get the file path of the current file in Digital Micrograph in python. How do I do this?
I tried to use
__file__
but I get NameError: Name not found globally.
I tried to use the dm-script GetCurrentScriptSourceFilePath() with the following code to get the value to python
import DigitalMicrograph as DM
import time
# get the __file__ by executing dm-scripts GetCurrentScriptSourceFilePath()
# function, then save the value in the persistent tags and delete the key
# again
tag = "__python__file__{}".format(round(time.time() * 100))
DM.ExecuteScriptString(
"String __file__;\n" +
"GetCurrentScriptSourceFilePath(__file__);\n" +
"number i = GetPersistentTagGroup().TagGroupCreateNewLabeledTag(\"" + tag + "\");\n" +
"GetPersistentTagGroup().TagGroupSetIndexedTagAsString(i, __file__);\n"
);
_, __file__ = DM.GetPersistentTagGroup().GetTagAsString(tag);
DM.ExecuteScriptString("GetPersistentTagGroup().TagGroupDeleteTagWithLabel(\"" + tag + "\");")
but it seems that the GetCurrentScriptSourceFilePath() function does not contain a path (which makes sense because it is executed from a string).
I found this post recommending
import inspect
src_file_path = inspect.getfile(lambda: None)
but the src_file_path is "<string>" which is obviously wrong.
I tried to raise an exception and then get the filename of it with the following code
try:
raise Exception("No error")
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
filename = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print("File: ", filename)
but again I get <string> as the filename.
I tried to get the path out of the script window but I could not find any function to get it. But the script window has to know where its path is, otherwise Ctrl+S cannot work.
Some background
I am developing a module used for Digital Micrograph. There I also have test files. But to import the (still developed) module in the test file(s), I need the path relative to the test file.
Later the module will be installed somewhere so this should not be a problem then. But for offering a compelte set of tests, I want to be able to execute the tests without having to install the (not working) module.
For the file path to your current working directory, use:
import os
os.getcwd()
In DM-script, which you could call from a Python script, the command GetApplicationDirectory() gives you what you need. Usually, you would want to use the "open_save" one, i.e.
GetApplicationDirectory("open_save",0)
This will return the directory (String variable) that appears when File/Open is used, or File/Save is used on a new image. It is, however, not what is used on a "File/Save Workspace" or other saves.
From the F1 help documentation on that command:
Note, that the concept of "current" directory is somewhat broken on Win10 with applications - including GMS.In particular the "SetApplicationDirectory" commands do not always work as expected...
If you want to find out what the folder of a specific, currently shown document is (image or text) you can use the following DM-script. The assumption here is, that the window is the front-most window.
documentwindow win = GetDocumentWindow(0)
if ( win.WindowIsvalid() )
if ( win.WindowIsLinkedToFile() )
Result("\n" + win.WindowGetCurrentFile())
For everyone who also needs this (and just wants to copy some code) I created the following code based on #BmyGuests answer. This takes the file the script window is bound to and saves it as a persistent tag. This tag is then read from the python file (and the tag is deleted).
Important Note: This only works in the python script window where you press the Execute Script button and only if this file is saved! But from there on you probably are importing scripts which should provide the module.__file__ attribute. This meas this does not work for plugins/libraries.
import DigitalMicrograph as DM
# the name of the tag is used, this is deleted so it shouldn't matter anyway
file_tag_name = "__python__file__"
# the dm-script to execute, double curly brackets are used because of the
# python format function
script = ("\n".join((
"DocumentWindow win = GetDocumentWindow(0);",
"if(win.WindowIsvalid()){{",
"if(win.WindowIsLinkedToFile()){{",
"TagGroup tg = GetPersistentTagGroup();",
"if(!tg.TagGroupDoesTagExist(\"{tag_name}\")){{",
"number index = tg.TagGroupCreateNewLabeledTag(\"{tag_name}\");",
"tg.TagGroupSetIndexedTagAsString(index, win.WindowGetCurrentFile());",
"}}",
"else{{",
"tg.TagGroupSetTagAsString(\"{tag_name}\", win.WindowGetCurrentFile());",
"}}",
"}}",
"}}"
))).format(tag_name=file_tag_name)
# execute the dm script
DM.ExecuteScriptString(script)
# read from the global tags to get the value to the python script
global_tags = DM.GetPersistentTagGroup()
if global_tags.IsValid():
s, __file__ = global_tags.GetTagAsString(file_tag_name);
if s:
# delete the created tag again
DM.ExecuteScriptString(
"GetPersistentTagGroup()." +
"TagGroupDeleteTagWithLabel(\"{}\");".format(file_tag_name)
)
else:
del __file__
try:
__file__
except NameError:
# set a default if the __file__ could not be received
__file__ = ""
print(__file__);

Issue with Exception in Python

I have a chunk of Python code that is supposed to create MySQL schemas when executed. The issue is that whenever I run it, I get an error saying Raise Exception(e). Exception: [Error 2] the system cannot find the file specified
Below is my code:
from test.db.db import DB
from test.config import loggingSetup
loggingSetup.initializeLogging("createTest.py")
import logging
def createSports(db):
sqlFile = "..\\sql\\createSchema.sql"
db.run(sqlFile)
def create():
db=DB()
createSports(db)
def Main():
create()
if__name__=='__main__':
try:
main()
except Exception, e:
logging.info(e.message)
raise Exception(e)
Now I will admit, this code isn't entirely mine. I found this online, and I'm trying to rework it so it will fit my needs. My experience with python is minimal at best, but you have to start somewhere. On a basic level I under stand that the if statement is saying if __name__=='__main__' then try main(), but i guess I'm fuzzy as to why this exception is being thrown. I know this chunk of code has worked for others who have used it for similar projects, is there something wrong with my syntax that is throwing this off?
Try this :
initialize_logging(__file__)
It's because the file which you pass to the logging function isn't found. file in short gives you the path to the currently loaded module.
Read more about file here.
def createSports(db):
sqlFile = "..\\sql\\createSchema.sql" #file path goes here
in here you have to write your file path. It's an example. Complete the path and make sure this file is exist.
You should know the difference between "working directory" and actually directory. During the runtime, if you don't use the absolute path, the Code(not only python, but other language such as C++, Java), will treat the path as relative path. so the question is what it is relative to ? the answer is "working directory", you can change your working directory easily by "os.chdir". In this case, you need to transfer it to the absolute path:
solution:
1)
def createSports(db):
sqlFile = "..\\sql\\createSchema.sql"
sqlFile = os.path.abspath(sqlFile)
if not os.path.exists(sqlFile):
msg = "file %s doesn't exist" % sqlFile
raise Exception(msg)
else:
db.run(sqlFile)
2) use the full path, but pay attention to the escaped character, you should use this sqlFile = r"C:\User\Desktop\Test\sql\createSchema.sql", use the "r" to mean that this is raw sting, do NOT escape "\"

Using getopt() to get values passed from the command line

I am writing a Python script to create directories for a given term and course. I would like to make use of the Python modules os, sys, and getopt (with both short and long form options) so that the running script would look like:
>python directory.py –t fall2013 –c cs311-400
>python directory.py –-term fall2013 –-class cs311-400
The code that I have write now looks like this:
import os
import sys
import getopt
term = ""
course = ""
options, args = getopt.getopt(sys.argv[1:], 't:c:', ['term=', 'course='])
for opt, arg in options:
if opt in ('-t', '--term'):
term = arg
elif opt in ('-c', '--course'):
course = arg
After this, I have a function that takes in the term and course an uses os.mkdir and such:
def make_folders(term, course):
if not os.path.isdir(term + course):
os.mkdir(term + course)
path = os.path.join(term + course, "assignments")
os.makedirs(path)
path = os.path.join(term + course, "examples")
os.makedirs(path)
path = os.path.join(term + course, "exams")
os.makedirs(path)
path = os.path.join(term + course, "lecture_notes")
os.makedirs(path)
path = os.path.join(term + course, "submissions")
os.makedirs(path)
make_folders(term, course)
For some reason, the folder that gets made only has a name that represents the term rather than both the term and the course. I feel like this might have something to do with my use of getopt, but I'm not certain. Any advice?
os.path.join is a clever function. Just pass as many folders as you need:
>>> import os
>>> os.path.join("first", "second", "third")
'first/second/third'
When you write term + course, Python concatenates the strings in term and course directly, before os.path.join() even sees them. That is, if, say, term == "fall2013" and course == "cs311-400", then term + course == "fall2013cs311-400" with nothing in between.
One way around that would be to insert an explicit slash between the term and the course, as in term + "/" + course. However, since you've presumably been instructed to use os.path.join() (which is a good idea, anyway), you can just pass all the path components you want to join to it as separate arguments and let it take care of joining them for you:
path = os.path.join(term, course, "exams")
Also, a few tips for your assignment, and for good Python coding in general:
While the getopt module is not actually deprecated like rtrwalker claims in the comments, you're probably better off using argparse unless you have to use getopt for some reason (like, say, the assignment tells you to).
Your code looks very repetitive. Repetitive code is a "smell" that should suggest the need for a loop, perhaps like this:
dirs = ("assignments", "examples", "exams", "lecture_notes", "submissions")
for folder in dirs:
path = os.path.join(term, course, folder)
os.makedirs(path)
I'm actually in your class; at least I'm almost positive I am. Was running into this exact problem and was having trouble getting that sub-directory. A google search landed me here! Well, after a few more googles and LOTS of troubleshooting, found the answer to our problem!
os.makedirs(''+term+'/'+course+'')
path = os.path.join(''+term+'/'+course+'', "exams")
os.makedirs(path)
That should clean it up for you and give your your new directory and sub-directories! Good luck with the rest of the assignment.

Is there a more Pythonic approach to this?

This is my first python script, be ye warned.
I pieced this together from Dive Into Python, and it works great. However since it is my first Python script I would appreciate any tips on how it can be made better or approaches that may better embrace the Python way of programming.
import os
import shutil
def getSourceDirectory():
"""Get the starting source path of folders/files to backup"""
return "/Users/robert/Music/iTunes/iTunes Media/"
def getDestinationDirectory():
"""Get the starting destination path for backup"""
return "/Users/robert/Desktop/Backup/"
def walkDirectory(source, destination):
"""Walk the path and iterate directories and files"""
sourceList = [os.path.normcase(f)
for f in os.listdir(source)]
destinationList = [os.path.normcase(f)
for f in os.listdir(destination)]
for f in sourceList:
sourceItem = os.path.join(source, f)
destinationItem = os.path.join(destination, f)
if os.path.isfile(sourceItem):
"""ignore system files"""
if f.startswith("."):
continue
if not f in destinationList:
"Copying file: " + f
shutil.copyfile(sourceItem, destinationItem)
elif os.path.isdir(sourceItem):
if not f in destinationList:
print "Creating dir: " + f
os.makedirs(destinationItem)
walkDirectory(sourceItem, destinationItem)
"""Make sure starting destination path exists"""
source = getSourceDirectory()
destination = getDestinationDirectory()
if not os.path.exists(destination):
os.makedirs(destination)
walkDirectory(source, destination)
As others mentioned, you probably want to use walk from the built-in os module. Also, consider using PEP 8 compatible style (no camel-case but this_stye_of_function_naming()). Wrapping directly executable code (i.e. no library/module) into a if __name__ == '__main__': ... block is also a good practice.
The code
has no docstring describing what it does
re-invents the "battery" of shutil.copytree
has a function called walkDirectory which doesn't do what its name implies
contains get* functions that provide no utility
those get functions embed high-level arguments deeper than they ought
is obligatorily chatty (print whether you want it or not)
Use os.path.walk. It does most all the bookkeeping for you; you then just feed a visitor function to it to do what you need.
Or, oh damn, looks like os.path.walk has been deprecated. Use os.walk then, and you get
for r, d, f in os.walk('/root/path')
for file in f:
# do something good.
I recommend using os.walk. It does what it looks like you're doing. It offers a nice interface that's easy to utilize to do whatever you need.
The main thing to make things more Pythonic is to adopt Python's PEP8, the style guide. It uses underscore for functions.1
If you're returning a fixed string, e.g. your get* functions, a variable is probably a
better approach. By this, I mean replace your getSourceDirectory with something like this:
source_directory = "/Users/robert/Music/iTunes/iTunes Media/"
Adding the following conditional will mean that code that is specific for running the module as a program does not get called when the module is imported.
if __name__ == '__main__':
source = getSourceDirectory()
destination = getDestinationDirectory()
if not os.path.exists(destination):
os.makedirs(destination)
walkDirectory(source, destination)
I would use a try & except block, rather than a conditional to test if walkDirectory can operate successfully. Weird things can happen with multiple processes & filesystems:
try:
walkDirectory(source, destination)
except IOError:
os.makedirs(destination)
walkDirectory(source, destination)
1 I've left out discussion about whether to use the standard library. At this stage of your Python journey, I think you're just after a feel how the language should be used in general terms. I don't think knowing the details of os.walk is really that important right now.

How can I safely create a directory (possibly including intermediate directories)?

I am writing a file using Python, and I want it to be placed in a specific path. How can I safely make sure that the path exists?
That is: how can I check whether the folder exists, along with its parents? If there are missing folders along the path, how can I create them?
On Python ≥ 3.5, use pathlib.Path.mkdir:
from pathlib import Path
Path("/my/directory").mkdir(parents=True, exist_ok=True)
For older versions of Python, I see two answers with good qualities, each with a small flaw, so I will give my take on it:
Try os.path.exists, and consider os.makedirs for the creation.
import os
if not os.path.exists(directory):
os.makedirs(directory)
As noted in comments and elsewhere, there's a race condition – if the directory is created between the os.path.exists and the os.makedirs calls, the os.makedirs will fail with an OSError. Unfortunately, blanket-catching OSError and continuing is not foolproof, as it will ignore a failure to create the directory due to other factors, such as insufficient permissions, full disk, etc.
One option would be to trap the OSError and examine the embedded error code (see Is there a cross-platform way of getting information from Python’s OSError):
import os, errno
try:
os.makedirs(directory)
except OSError as e:
if e.errno != errno.EEXIST:
raise
Alternatively, there could be a second os.path.exists, but suppose another created the directory after the first check, then removed it before the second one – we could still be fooled.
Depending on the application, the danger of concurrent operations may be more or less than the danger posed by other factors such as file permissions. The developer would have to know more about the particular application being developed and its expected environment before choosing an implementation.
Modern versions of Python improve this code quite a bit, both by exposing FileExistsError (in 3.3+)...
try:
os.makedirs("path/to/directory")
except FileExistsError:
# directory already exists
pass
...and by allowing a keyword argument to os.makedirs called exist_ok (in 3.2+).
os.makedirs("path/to/directory", exist_ok=True) # succeeds even if directory exists.
Python 3.5+:
import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True)
pathlib.Path.mkdir as used above recursively creates the directory and does not raise an exception if the directory already exists. If you don't need or want the parents to be created, skip the parents argument.
Python 3.2+:
Using pathlib:
If you can, install the current pathlib backport named pathlib2. Do not install the older unmaintained backport named pathlib. Next, refer to the Python 3.5+ section above and use it the same.
If using Python 3.4, even though it comes with pathlib, it is missing the useful exist_ok option. The backport is intended to offer a newer and superior implementation of mkdir which includes this missing option.
Using os:
import os
os.makedirs(path, exist_ok=True)
os.makedirs as used above recursively creates the directory and does not raise an exception if the directory already exists. It has the optional exist_ok argument only if using Python 3.2+, with a default value of False. This argument does not exist in Python 2.x up to 2.7. As such, there is no need for manual exception handling as with Python 2.7.
Python 2.7+:
Using pathlib:
If you can, install the current pathlib backport named pathlib2. Do not install the older unmaintained backport named pathlib. Next, refer to the Python 3.5+ section above and use it the same.
Using os:
import os
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise
While a naive solution may first use os.path.isdir followed by os.makedirs, the solution above reverses the order of the two operations. In doing so, it prevents a common race condition having to do with a duplicated attempt at creating the directory, and also disambiguates files from directories.
Note that capturing the exception and using errno is of limited usefulness because OSError: [Errno 17] File exists, i.e. errno.EEXIST, is raised for both files and directories. It is more reliable simply to check if the directory exists.
Alternative:
mkpath creates the nested directory, and does nothing if the directory already exists. This works in both Python 2 and 3. Note however that distutils has been deprecated, and is scheduled for removal in Python 3.12.
import distutils.dir_util
distutils.dir_util.mkpath(path)
Per Bug 10948, a severe limitation of this alternative is that it works only once per python process for a given path. In other words, if you use it to create a directory, then delete the directory from inside or outside Python, then use mkpath again to recreate the same directory, mkpath will simply silently use its invalid cached info of having previously created the directory, and will not actually make the directory again. In contrast, os.makedirs doesn't rely on any such cache. This limitation may be okay for some applications.
With regard to the directory's mode, please refer to the documentation if you care about it.
Using try except and the right error code from errno module gets rid of the race condition and is cross-platform:
import os
import errno
def make_sure_path_exists(path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
In other words, we try to create the directories, but if they already exist we ignore the error. On the other hand, any other error gets reported. For example, if you create dir 'a' beforehand and remove all permissions from it, you will get an OSError raised with errno.EACCES (Permission denied, error 13).
Starting from Python 3.5, pathlib.Path.mkdir has an exist_ok flag:
from pathlib import Path
path = Path('/my/directory/filename.txt')
path.parent.mkdir(parents=True, exist_ok=True)
# path.parent ~ os.path.dirname(path)
This recursively creates the directory and does not raise an exception if the directory already exists.
(just as os.makedirs got an exist_ok flag starting from python 3.2 e.g os.makedirs(path, exist_ok=True))
Note: when i posted this answer none of the other answers mentioned exist_ok...
I would personally recommend that you use os.path.isdir() to test instead of os.path.exists().
>>> os.path.exists('/tmp/dirname')
True
>>> os.path.exists('/tmp/dirname/filename.etc')
True
>>> os.path.isdir('/tmp/dirname/filename.etc')
False
>>> os.path.isdir('/tmp/fakedirname')
False
If you have:
>>> directory = raw_input(":: ")
And a foolish user input:
:: /tmp/dirname/filename.etc
... You're going to end up with a directory named filename.etc when you pass that argument to os.makedirs() if you test with os.path.exists().
Check os.makedirs: (It makes sure the complete path exists.)
To handle the fact the directory might exist, catch OSError.
(If exist_ok is False (the default), an OSError is raised if the target directory already exists.)
import os
try:
os.makedirs('./path/to/somewhere')
except OSError:
pass
Try the os.path.exists function
if not os.path.exists(dir):
os.mkdir(dir)
Insights on the specifics of this situation
You give a particular file at a certain path and you pull the directory from the file path. Then after making sure you have the directory, you attempt to open a file for reading. To comment on this code:
filename = "/my/directory/filename.txt"
dir = os.path.dirname(filename)
We want to avoid overwriting the builtin function, dir. Also, filepath or perhaps fullfilepath is probably a better semantic name than filename so this would be better written:
import os
filepath = '/my/directory/filename.txt'
directory = os.path.dirname(filepath)
Your end goal is to open this file, you initially state, for writing, but you're essentially approaching this goal (based on your code) like this, which opens the file for reading:
if not os.path.exists(directory):
os.makedirs(directory)
f = file(filename)
Assuming opening for reading
Why would you make a directory for a file that you expect to be there and be able to read?
Just attempt to open the file.
with open(filepath) as my_file:
do_stuff(my_file)
If the directory or file isn't there, you'll get an IOError with an associated error number: errno.ENOENT will point to the correct error number regardless of your platform. You can catch it if you want, for example:
import errno
try:
with open(filepath) as my_file:
do_stuff(my_file)
except IOError as error:
if error.errno == errno.ENOENT:
print 'ignoring error because directory or file is not there'
else:
raise
Assuming we're opening for writing
This is probably what you're wanting.
In this case, we probably aren't facing any race conditions. So just do as you were, but note that for writing, you need to open with the w mode (or a to append). It's also a Python best practice to use the context manager for opening files.
import os
if not os.path.exists(directory):
os.makedirs(directory)
with open(filepath, 'w') as my_file:
do_stuff(my_file)
However, say we have several Python processes that attempt to put all their data into the same directory. Then we may have contention over creation of the directory. In that case it's best to wrap the makedirs call in a try-except block.
import os
import errno
if not os.path.exists(directory):
try:
os.makedirs(directory)
except OSError as error:
if error.errno != errno.EEXIST:
raise
with open(filepath, 'w') as my_file:
do_stuff(my_file)
I have put the following down. It's not totally foolproof though.
import os
dirname = 'create/me'
try:
os.makedirs(dirname)
except OSError:
if os.path.exists(dirname):
# We are nearly safe
pass
else:
# There was an error on creation, so make sure we know about it
raise
Now as I say, this is not really foolproof, because we have the possiblity of failing to create the directory, and another process creating it during that period.
Check if a directory exists and create it if necessary?
The direct answer to this is, assuming a simple situation where you don't expect other users or processes to be messing with your directory:
if not os.path.exists(d):
os.makedirs(d)
or if making the directory is subject to race conditions (i.e. if after checking the path exists, something else may have already made it) do this:
import errno
try:
os.makedirs(d)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
But perhaps an even better approach is to sidestep the resource contention issue, by using temporary directories via tempfile:
import tempfile
d = tempfile.mkdtemp()
Here's the essentials from the online doc:
mkdtemp(suffix='', prefix='tmp', dir=None)
User-callable function to create and return a unique temporary
directory. The return value is the pathname of the directory.
The directory is readable, writable, and searchable only by the
creating user.
Caller is responsible for deleting the directory when done with it.
New in Python 3.5: pathlib.Path with exist_ok
There's a new Path object (as of 3.4) with lots of methods one would want to use with paths - one of which is mkdir.
(For context, I'm tracking my weekly rep with a script. Here's the relevant parts of code from the script that allow me to avoid hitting Stack Overflow more than once a day for the same data.)
First the relevant imports:
from pathlib import Path
import tempfile
We don't have to deal with os.path.join now - just join path parts with a /:
directory = Path(tempfile.gettempdir()) / 'sodata'
Then I idempotently ensure the directory exists - the exist_ok argument shows up in Python 3.5:
directory.mkdir(exist_ok=True)
Here's the relevant part of the documentation:
If exist_ok is true, FileExistsError exceptions will be ignored (same behavior as the POSIX mkdir -p command), but only if the last path component is not an existing non-directory file.
Here's a little more of the script - in my case, I'm not subject to a race condition, I only have one process that expects the directory (or contained files) to be there, and I don't have anything trying to remove the directory.
todays_file = directory / str(datetime.datetime.utcnow().date())
if todays_file.exists():
logger.info("todays_file exists: " + str(todays_file))
df = pd.read_json(str(todays_file))
Path objects have to be coerced to str before other APIs that expect str paths can use them.
Perhaps Pandas should be updated to accept instances of the abstract base class, os.PathLike.
fastest safest way to do it is:
it will create if not exists and skip if exists:
from pathlib import Path
Path("path/with/childs/.../").mkdir(parents=True, exist_ok=True)
Best way to do this in python
#Devil
import os
directory = "./out_dir/subdir1/subdir2"
if not os.path.exists(directory):
os.makedirs(directory)
In Python 3.4 you can also use the brand new pathlib module:
from pathlib import Path
path = Path("/my/directory/filename.txt")
try:
if not path.parent.exists():
path.parent.mkdir(parents=True)
except OSError:
# handle error; you can also catch specific errors like
# FileExistsError and so on.
For a one-liner solution, you can use IPython.utils.path.ensure_dir_exists():
from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)
From the documentation: Ensure that a directory exists. If it doesn’t exist, try to create it and protect against a race condition if another process is doing the same.
IPython is an extension package, not part of the standard library.
In Python3, os.makedirs supports setting exist_ok. The default setting is False, which means an OSError will be raised if the target directory already exists. By setting exist_ok to True, OSError (directory exists) will be ignored and the directory will not be created.
os.makedirs(path,exist_ok=True)
In Python2, os.makedirs doesn't support setting exist_ok. You can use the approach in heikki-toivonen's answer:
import os
import errno
def make_sure_path_exists(path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
The relevant Python documentation suggests the use of the EAFP coding style (Easier to Ask for Forgiveness than Permission). This means that the code
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
else:
print "\nBE CAREFUL! Directory %s already exists." % path
is better than the alternative
if not os.path.exists(path):
os.makedirs(path)
else:
print "\nBE CAREFUL! Directory %s already exists." % path
The documentation suggests this exactly because of the race condition discussed in this question. In addition, as others mention here, there is a performance advantage in querying once instead of twice the OS. Finally, the argument placed forward, potentially, in favour of the second code in some cases --when the developer knows the environment the application is running-- can only be advocated in the special case that the program has set up a private environment for itself (and other instances of the same program).
Even in that case, this is a bad practice and can lead to long useless debugging. For example, the fact we set the permissions for a directory should not leave us with the impression permissions are set appropriately for our purposes. A parent directory could be mounted with other permissions. In general, a program should always work correctly and the programmer should not expect one specific environment.
I found this Q/A after I was puzzled by some of the failures and errors I was getting while working with directories in Python. I am working in Python 3 (v.3.5 in an Anaconda virtual environment on an Arch Linux x86_64 system).
Consider this directory structure:
└── output/ ## dir
├── corpus ## file
├── corpus2/ ## dir
└── subdir/ ## dir
Here are my experiments/notes, which provides clarification:
# ----------------------------------------------------------------------------
# [1] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist
import pathlib
""" Notes:
1. Include a trailing slash at the end of the directory path
("Method 1," below).
2. If a subdirectory in your intended path matches an existing file
with same name, you will get the following error:
"NotADirectoryError: [Errno 20] Not a directory:" ...
"""
# Uncomment and try each of these "out_dir" paths, singly:
# ----------------------------------------------------------------------------
# METHOD 1:
# Re-running does not overwrite existing directories and files; no errors.
# out_dir = 'output/corpus3' ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/' ## works
# out_dir = 'output/corpus3/doc1' ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/doc1/' ## works
# out_dir = 'output/corpus3/doc1/doc.txt' ## no error but no file created (os.makedirs creates dir, not files! ;-)
# out_dir = 'output/corpus2/tfidf/' ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/' ## works
# out_dir = 'output/corpus3/a/b/c/d/' ## works
# [2] https://docs.python.org/3/library/os.html#os.makedirs
# Uncomment these to run "Method 1":
#directory = os.path.dirname(out_dir)
#os.makedirs(directory, mode=0o777, exist_ok=True)
# ----------------------------------------------------------------------------
# METHOD 2:
# Re-running does not overwrite existing directories and files; no errors.
# out_dir = 'output/corpus3' ## works
# out_dir = 'output/corpus3/' ## works
# out_dir = 'output/corpus3/doc1' ## works
# out_dir = 'output/corpus3/doc1/' ## works
# out_dir = 'output/corpus3/doc1/doc.txt' ## no error but creates a .../doc.txt./ dir
# out_dir = 'output/corpus2/tfidf/' ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/' ## works
# out_dir = 'output/corpus3/a/b/c/d/' ## works
# Uncomment these to run "Method 2":
#import os, errno
#try:
# os.makedirs(out_dir)
#except OSError as e:
# if e.errno != errno.EEXIST:
# raise
# ----------------------------------------------------------------------------
Conclusion: in my opinion, "Method 2" is more robust.
[1] How can I safely create a nested directory?
[2] https://docs.python.org/3/library/os.html#os.makedirs
You can use mkpath
# Create a directory and any missing ancestor directories.
# If the directory already exists, do nothing.
from distutils.dir_util import mkpath
mkpath("test")
Note that it will create the ancestor directories as well.
It works for Python 2 and 3.
In case you're writing a file to a variable path, you can use this on the file's path to make sure that the parent directories are created.
from pathlib import Path
path_to_file = Path("zero/or/more/directories/file.ext")
parent_directory_of_file = path_to_file.parent
parent_directory_of_file.mkdir(parents=True, exist_ok=True)
Works even if path_to_file is file.ext (zero directories deep).
See pathlib.PurePath.parent and pathlib.Path.mkdir.
Why not use subprocess module if running on a machine that supports command
mkdir with -p option ?
Works on python 2.7 and python 3.6
from subprocess import call
call(['mkdir', '-p', 'path1/path2/path3'])
Should do the trick on most systems.
In situations where portability doesn't matter (ex, using docker) the solution is a clean 2 lines. You also don't have to add logic to check if directories exist or not. Finally, it is safe to re-run without any side effects
If you need error handling:
from subprocess import check_call
try:
check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
handle...
You have to set the full path before creating the directory:
import os,sys,inspect
import pathlib
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
your_folder = currentdir + "/" + "your_folder"
if not os.path.exists(your_folder):
pathlib.Path(your_folder).mkdir(parents=True, exist_ok=True)
This works for me and hopefully, it will works for you as well
I saw Heikki Toivonen and A-B-B's answers and thought of this variation.
import os
import errno
def make_sure_path_exists(path):
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST or not os.path.isdir(path):
raise
I use os.path.exists(), here is a Python 3 script that can be used to check if a directory exists, create one if it does not exist, and delete it if it does exist (if desired).
It prompts users for input of the directory and can be easily modified.
Use this command check and create dir
if not os.path.isdir(test_img_dir):
os.mkdir(test_img_dir)
Call the function create_dir() at the entry point of your program/project.
import os
def create_dir(directory):
if not os.path.exists(directory):
print('Creating Directory '+directory)
os.makedirs(directory)
create_dir('Project directory')
If you consider the following:
os.path.isdir('/tmp/dirname')
means a directory (path) exists AND is a directory. So for me this way does what I need. So I can make sure it is folder (not a file) and exists.
You can use os.listdir for this:
import os
if 'dirName' in os.listdir('parentFolderPath')
print('Directory Exists')
This may not exactly answer the question. But I guess your real intention is to create a file and its parent directories, given its content all in 1 command.
You can do that with fastcore extension to pathlib: path.mk_write(data)
from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')
See more in fastcore documentation

Categories