tags:

views:

199

answers:

4

In relation to another question, how do you account for paths that may change? For example, if a program is calling a file in the same directory as the program, you can simply use the path ".\foo.py" in *nix. However, apparently Windows likes to have the path hard-coded, e.g. "C:\Python_project\foo.py".

What happens if the path changes? For example, the file may not be on the C: drive but on a thumb drive or external drive that can change the drive letter. The file may still be in the same directory as the program but it won't match the drive letter in the code.

I want the program to be cross-platform, but I expect I may have to use os.name or something to determine which path code block to use.

A: 

If your file is always in the same directory as your program then:

def _isInProductionMode():
    """ returns True when running the exe, 
        False when running from a script, ie development mode.
    """
    return (hasattr(sys, "frozen") or # new py2exe
           hasattr(sys, "importers") # old py2exe
           or imp.is_frozen("__main__")) #tools/freeze

def _getAppDir():
    """ returns the directory name of the script or the directory 
        name of the exe
    """
    if _isInProductionMode():
        return os.path.dirname(sys.executable)
    return os.path.dirname(__file__)

should work. Also, I've used py2exe for my own application, and haven't tested it with other exe conversion apps.

TheObserver
A: 

What -- specifically -- do you mean by "calling a file...foo.py"?

  1. Import? If so, the path is totally outside of your program. Set the PYTHONPATH environment variable with . or c:\ or whatever at the shell level. You can, for example, write 2-line shell scripts to set an environment variable and run Python.

    Windows

    SET PYTHONPATH=C:\path\to\library
    python myapp.py
    

    Linux

    export PYTHONPATH=./relative/path
    python myapp.py
    
  2. Execfile? Consider using import.

  3. Read and Eval? Consider using import.

If the PYTHONPATH is too complicated, then put your module in the Python lib/site-packages directory, where it's put onto the PYTHONPATH by default for you.

S.Lott
+4  A: 

Simple answer: You work out the absolute path based on the environment.

What you really need is a few pointers. There are various bits of runtime and environment information that you can glean from various places in the standard library (and they certainly help me when I want to deploy an application on windows).

So, first some general things:

  1. os.path - standard library module with lots of cross-platform path manipulation. Your best friend. "Follow the os.path" I once read in a book.
  2. __file__ - The location of the current module.
  3. sys.executable - The location of the running Python.

Now you can fairly much glean anything you want from these three sources. The functions from os.path will help you get around the tree:

  • os.path.join('path1', 'path2') - join path segments in a cross-platform way
  • os.path.expanduser('a_path') - find the path a_path in the user's home directory
  • os.path.abspath('a_path') - convert a relative path to an absolute path
  • os.path.dirname('a_path') - get the directory that a path is in
  • many many more...

So combining this, for example:

# script1.py
# Get the path to the script2.py in the same directory
import os
this_script_path = os.path.abspath(__file__)
this_dir_path = os.path.dirname(this_script_path)
script2_path = os.path.join(this_dir_path, 'script2.py')
print script2_path

And running it:

ali@work:~/tmp$ python script1.py 
/home/ali/tmp/script2.py

Now for your specific case, it seems you are slightly confused between the concept of a "working directory" and the "directory that a script is in". These can be the same, but they can also be different. For example the "working directory" can be changed, and so functions that use it might be able to find what they are looking for sometimes but not others. subprocess.Popen is an example of this.

If you always pass paths absolutely, you will never get into working directory issues.

Ali A
A: 

I figured out by using os.getcwd(). I also learned about using os.path.join to automatically determine the correct path format based on the OS. Here's the code:

def openNewRecord(self, event): # wxGlade: CharSheet.<event_handler>
    """Create a new, blank record sheet."""
    path = os.getcwd()
    subprocess.Popen(os.path.join(path, "TW2K_char_rec_sheet.py"), shell=True).stdout

It appears to be working. Thanks for the ideas.

crystalattice
Umm... That's not necessary. Use os.path.join. It already knows the "/" vs. "\" for your specific OS.
S.Lott
Sure, downvote me because I'm still learning. I wasn't aware of os.path.join; I'm just happy I got something that works. Sometimes I get really tired w/ this site.
crystalattice
I had to downvote your answer because it's not right. The vote is not about you, it's about everyone else who searches for an answer here. If they find wrong information, that's really bad. You could, for example, fix your answer. I would then have to remove the downvote since it's better.
S.Lott
Just curious why are you using a sub process? Does the code take so long to run that it locks up your gui?
Sam Corder
@S.Lott-fixed@Sam Corder-I was using os.popen() until it was recommended to use the subprocess module because it's better.
crystalattice
What does "better" mean? WHy not just import the module?
S.Lott
"Better" means it's the recommend replacement for os.popen(). I did import the *subprocess* module. Is there a different way to use it? If I call Popen() by itself, I just get an error; hence the explict subprocess.Popen() call.
crystalattice
Why not just import the module? Why run 'TW2K_char_rec_sheet' as a subprocess? Why not just import 'TW2K_char_rec_sheet'?
S.Lott
Because I want to create a window when the method is called, which implies a new process. I tried importing it but it just sits there. It does work like I want. Am I doing it wrong?
crystalattice
"create a window when the method is called, which implies a new process". Okay, this is heading outside the scope of the question.
S.Lott