Python 101: How to Find the Path of a Running Script

Posted by Mike on October 29th, 2013 filed in Cross-Platform, Python

This topic is actually more complicated then it first appears. In this article, we’ll spend a little time looking at this problem and some of the solutions.

Several years ago, one of my friends on the wxPython users mailing list told me that he uses the following:

import os
script_path = os.path.dirname(os.path.abspath( __file__ ))

This works for me and is what I currently use. The code above returns the absolute path, by the way. According to the documentation, it is the equivalent of

import os
os.pathnormpath(join(os.getcwd(), path))

I’ve also seen people recommending the following similar solution:

import os
os.path.dirname(os.path.realpath(__file__))

The documentation states that realpath will return the canonical path of the specified filename, eliminating any symbolic links encountered in the path, which sounds like it may be better than the solution I’ve been using.

Regardless, as some are likely to point out, you cannot use __file__ from within IDLE / the interpreter. If you do, you’ll get the following error:

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    __file__
NameError: name '__file__' is not defined

You’ll end up with the same error if you happen to “freeze” your application by creating an executable with something like py2exe. For cases like this, some would recommend the following as an alternative:

import os
os.path.dirname(sys.argv[0])

Now this will not work if you happen to call your script from another script. I’m also pretty sure that when I tried this with a frozen application and called the executable from a shortcut, it was returning the shortcut’s path instead of the executable’s. However, I may be getting that confused with os.getcwd() which will definitely not work reliably.

The solution I ended up with for the executables I created with py2exe was this one:

import os, sys
os.path.abspath(os.path.dirname(sys.argv[0]))

I’m pretty sure one of the core developers from wxPython had recommended using that, but I can’t be sure as I don’t seem to have that email any longer. Regardless, Mark Pilgrim, author of Dive Into Python, also recommends using os.path.abspath.

For now I think I will stick with either os.path.abspath or os.path.realpath for scripts and the above variation for my frozen Windows applications. I would be interested in hearing about your solution though. Let me know if you’ve found anything that works cross-platform and/or for frozen scripts.

Further Reading

Print Friendly

  • http://notatnik.mekk.waw.pl Mekk

    There is big difference between abspath and realpath.

    Try the following:

    – save your script as $HOME/scripts/tests/myscript.py

    – symlink it to bin:

    ln -s ~/scripts/tests/myscript.py ~/bin/myscript

    – run it via latter (python ~/bin/myscript, or just myscript if bin is in PATH)

  • http://www.blog.pythonlibrary.org/ Mike Driscoll

    I suspect I never had to deal with this because I used to program for Windows almost exclusively. Thanks for the insight!

  • eryksun

    Assuming you have the SeCreateSymbolicLinkPrivilege NT user right (e.g. Administrators), you can create symbolic links with os.symlink or from the cmd shell with mklink. Test for links with os.path.islink.

    Currently ntpath.realpath aliases ntpath.abspath. But ntpath._getfinalpathname calls WinAPI
    `GetFinalPathNameByHandle` to get the real path. This could be used to implement ntpath.realpath in NT 6.0+.

  • http://www.blog.pythonlibrary.org/ Mike Driscoll

    Yeah, I’m aware that Windows supports it, but none of the computers I programmed for used that functionality and at that time, I didn’t know you could do that anyway.