Skip to main content

RunningInCorrectDirectory — wiki

RunningInCorrectDirectory

def adjust_to_correct_appdir():
    import os, sys
    try:
        appdir = sys.argv[0] #feel free to use __file__
        if not appdir:
            raise ValueError
        appdir = os.path.abspath(os.path.dirname(sys.argv[0]))
        os.chdir(appdir)
        if not appdir in sys.path:
            sys.path.insert(0,appdir)
    except:
        #placeholder for feedback, adjust to your app.
        #remember to use only python and python standard libraries
        #not any resource or module into the appdir 
        #a window in Tkinter can be adequate for apps without console
        #a simple print with a timeout can be enough for console apps
        print 'Please run from an OS console.'
        import time
        time.sleep(10)
        sys.exit(1)
adjust_to_correct_appdir()

Usage:

Add the code in any *.py that's directly runnable (ex. game.py, leveleditor.py). It must be added near the begining of file, before importing any module living under the appdir, before opening any file with a filename relative to the appdir and before any pickle-unpickle operation.

Discussion:

Problem:

Your app is started not from the appdir. As a result:

  1. import cannot solve imports relative to the appdir
  2. file operation with filenames relatives to appdir will fail ( like f=file('data/x.png'))
  3. pickle-unpickle can fail by being unable to resolve class definitions
  4. traceback error messages can be ambiguous

This can happen due to:

  1. the app is started from a python interpreter console which is not in the appdir
  2. the app is started from a OS console wich is not in the appdir
  3. In windows, the app is started by doubleclick in a shortcut (that not have properly set the 'start in' field)
  4. the app is started from a launchbar, and the start directory has not been specified
  5. others?

Way to go:

The second problem can only be solved if at the very beginning of the app the working directory is changed to appdir (os.chdir(appdir)).

Also, if we know the appdir then we can add to the module search paths (sys.path.insert(0,appdir)), solving the problem 1. and, (I think, confirm please) the 3.

Python doesn't have functionality to directly query: what is the appdir for app 'myapp'?, but lets seek a portable solution. An old version of this recipe tells:

appdir = os.path.abspath(os.path.dirname(sys.argv[0]))

warning that sys.argv[0] its usually the command line used to start the app, but not guaranteed. By example, if the entry point for the app lies in main.py, and someone starts the app from the python interpreter console:

>>>execfile(r'\appedir\main.py') #in linux-mac '/appdir/main.py'

then sys.argv[0] would be the empty string, at least in windows A most recent recipe, the one that Im replacing, gets appdir as

appdir = os.path.abspath(os.path.dirname(__file__))

which in the python console case will fail with NameError: __file__ is not defined

Other considerations:

If you cannot resolve appdir, then the better is to give feedback to the user (print, a tkinter window, any that only uses python and standard libraries) and terminate the app.

If you let execution go ahead, expect a lot of bug reports, with ambiguous interpretation.

If you really want to support starting from the python interpreter console, then you can:

...
#in branch where sys.argv[0] or __file__ tells nothing
try:
    appdir=os.getcwd()
    f=file(os.path.join(appdir,'signature'),'rb')
    sig=file.read()
    f.close()
    if sig!='this is the myapp signature file - dont edit':
       # started from the interpreter but not in the appdir.
       raise
    # medium confirmation that the cwd is really the appdir
except:
    #warn the user and quit

Personally, I wouldn't bother.

Parting shots:

Note that the python docs are unclear (or the info is buried somewhere) as the exact circumstances in wich sys.argv[0] nor __file__ will not convey the info we want to extract. Also, from that blurriness, it is unclear if one is better than the other.

For your information, the old recipe (using sys.argv[0]) was used in magicor http://www.pygame.org/projects/21/313/?release_id=596 from a year an a half, no problems.

Sorry if this is too long, but I want to state clearly the problems so as new recipes can cover ar least the same that an older. As a matter of example, the old recipe (not writen by me) handled the two (three?) first problems, a later recipe, the one that I am replacing, forget to adress the item 1 in Problems. So, please, if you want to improve the recipe, do test if the new code cover more, and make explicit comments about what more it covers. The only addition to the older recipe code is the termination when a reliable appdir can not be built, and it was motivated by some misleading bug reports in pyweek6.