Python – How to reliably open a file in the same directory as the currently running script

directorypython

I used to open files that were in the same directory as the currently running Python script by simply using a command like:

open("Some file.txt", "r")

However, I discovered that when the script was run in Windows by double-clicking it, it would try to open the file from the wrong directory.

Since then I've used a command of the form

open(os.path.join(sys.path[0], "Some file.txt"), "r")

whenever I wanted to open a file. This works for my particular usage, but I'm not sure if sys.path[0] might fail in some other use case.

So my question is: What is the best and most reliable way to open a file that's in the same directory as the currently running Python script?

Here's what I've been able to figure out so far:

  • os.getcwd() and os.path.abspath('') return the "current working directory", not the script directory.

  • os.path.dirname(sys.argv[0]) and os.path.dirname(__file__) return the path used to call the script, which may be relative or even blank (if the script is in the cwd). Also, __file__ does not exist when the script is run in IDLE or PythonWin.

  • sys.path[0] and os.path.abspath(os.path.dirname(sys.argv[0])) seem to return the script directory. I'm not sure if there's any difference between these two.

Edit:

I just realized that what I want to do would be better described as "open a file in the same directory as the containing module". In other words, if I import a module I wrote that's in another directory, and that module opens a file, I want it to look for the file in the module's directory. I don't think anything I've found is able to do that…

Best Answer

I always use:

__location__ = os.path.realpath(
    os.path.join(os.getcwd(), os.path.dirname(__file__)))

The join() call prepends the current working directory, but the documentation says that if some path is absolute, all other paths left of it are dropped. Therefore, getcwd() is dropped when dirname(__file__) returns an absolute path.

Also, the realpath call resolves symbolic links if any are found. This avoids troubles when deploying with setuptools on Linux systems (scripts are symlinked to /usr/bin/ -- at least on Debian).

You may the use the following to open up files in the same folder:

f = open(os.path.join(__location__, 'bundled-resource.jpg'))
# ...

I use this to bundle resources with several Django application on both Windows and Linux and it works like a charm!