tags:

views:

320

answers:

2

This may seam a newbie question but it is not. It looks that common approaches are not always working:

Currently I know only two options but none of them looks to work an 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 from another directory, and this can really happen in real life.

__file__

this means that path = os.path.abspath(os.path.dirname(__file__)) but I found that this doesn't work:

  • py2exe that doesn't have a __file__ attribute but there is an 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:

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
+3  A: 

You can't directly determine the location of the main script being executed. After all, sometimes the script didn't come from a file at all. For example, it could come from the interactive interpreter or dynamically generated code stored only in memory.

However, you can reliably determine the location of a module, since modules are always loaded from a file. If you create a module with the following code and put it in the same directory as your main script, then the main script can import the module and use that to locate itself.

some_path/module_locator.py:

def we_are_frozen():
    # All of the modules are built-in to the interpreter, e.g., by py2exe
    return hasattr(sys, "frozen")

def module_path():
    encoding = sys.getfilesystemencoding()
    if we_are_frozen():
        return os.path.dirname(unicode(sys.executable, encoding))
    return os.path.dirname(unicode(__file__, encoding))

some_path/main.py:

import module_locator
my_path = module_locator.module_path()

If you have several main scripts in different directories, you may need more than one copy of module_locator.

Of course, if your main script is loaded by some other tool that doesn't let you import modules that are co-located with your script, then you're out of luck. In cases like that, the information you're after simply doesn't exist anywhere in your program. Your best bet would be to file a bug with the authors of the tool.

Daniel Stutzbach
I mention that on OS 10.6 I get `NameError: global name '__file__' is not defined` using __file__ and this is not inside the IDLE. Think that `__file__` is defined only inside modules.
Sorin Sbarnea
@Sorin Sbarnea: I updated my answer with how I get around that.
Daniel Stutzbach
Thanks, but in fact the problem with missing `__file__` had nothing to do with Unicode. I don't know why `__file__` is not defined but I'm looking for a generic solution this will work an all cases.
Sorin Sbarnea
@Sorin Sbarnea, unicode isn't the part that I added. The key, I believe, is to put the __file__ in a module, not in the main file. In other words, you should be calling `my_module.module_path()`.
Daniel Stutzbach
Sorry this is not possible in all cases. For example I try to do this in waf.googlecode.com from inside a wscript file (python). These files are executed but they are not modules and you cannot made them modules (they can be any any subdirectory from the source tree).
Sorin Sbarnea
@Sorin Sbarnea: I've expanded and updated my answer.
Daniel Stutzbach
+1  A: 

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 http://stackoverflow.com/questions/933850/how-to-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.

Dale Hagglund