This may seem like a newbie question, but it is not. Some common approaches don't work in all cases:
sys.argv[0]
This means using path = os.path.abspath(os.path.dirname(sys.argv[0]))
, but this does not work if you are running from another Python script in another directory, and this can happen in real life.
__file__
This means using path = os.path.abspath(os.path.dirname(__file__))
, but I found that this doesn't work:
py2exe
doesn't have a__file__
attribute, but there is a workaround- When you run from IDLE with
execute()
there is no__file__
attribute - OS X 10.6 where I get
NameError: global name '__file__' is not defined
Related questions with incomplete answers:
- Python - Find Path to File Being Run
- Path to current file depends on how I execute the program
- How to know the path of the running script in Python?
- Change directory to the directory of a Python script
I'm looking for a generic solution, one that would work in all above use cases.
Update
Here is the result of a testcase:
Output of python a.py (on Windows)
a.py: __file__= a.py
a.py: os.getcwd()= C:\zzz
b.py: sys.argv[0]= a.py
b.py: __file__= a.py
b.py: os.getcwd()= C:\zzz
a.py
#! /usr/bin/env python
import os, sys
print "a.py: sys.argv[0]=", sys.argv[0]
print "a.py: __file__=", __file__
print "a.py: os.getcwd()=", os.getcwd()
print
execfile("subdir/b.py")
subdir/b.py
#! /usr/bin/env python
import os, sys
print "b.py: sys.argv[0]=", sys.argv[0]
print "b.py: __file__=", __file__
print "b.py: os.getcwd()=", os.getcwd()
print
tree
C:.
| a.py
\---subdir
b.py
You can use
Path
from thepathlib
module:You can use call to
parent
to go further in the path:The short answer is that there is no guaranteed way to get the information you want, however there are heuristics that work almost always in practice. You might look at How do I find the location of the executable in C?. It discusses the problem from a C point of view, but the proposed solutions are easily transcribed into Python.
this solution is robust even in executables
This should do the trick in a cross-platform way (so long as you're not using the interpreter or something):
sys.path[0]
is the directory that your calling script is in (the first place it looks for modules to be used by that script). We can take the name of the file itself off the end ofsys.argv[0]
(which is what I did withos.path.basename
).os.path.join
just sticks them together in a cross-platform way.os.path.realpath
just makes sure if we get any symbolic links with different names than the script itself that we still get the real name of the script.I don't have a Mac; so, I haven't tested this on one. Please let me know if it works, as it seems it should. I tested this in Linux (Xubuntu) with Python 3.4. Note that many solutions for this problem don't work on Macs (since I've heard that
__file__
is not present on Macs).Note that if your script is a symbolic link, it will give you the path of the file it links to (and not the path of the symbolic link).
If the code is coming from a file, you can get its full name
You can also retrieve the function name as
f_code.co_name
First, you need to import from
inspect
andos
Next, wherever you want to find the source file from you just use