Search code examples
pythonwindowswindows-installercx-freeze

Is it possible to access the launching shortcut directory from a Python executalbe?


I currently have a Python scrip that runs through all Excel files in the current directory and generates a PDF report.

It works fine now but I don't want the users to be anywhere near frozen Python scripts. I created an MSI with cxFreeze which puts the EXE and scripts in the Program Files directory.

What I would like to be able to do is create a shortcut to this executable and pass the directory the shortcut was run from to the Python program so that can be set as the working directory. This would allow the user to move the shortcut to any folder of Excel files and generate a report there.

Does Windows send the location of a opened shortcut to the executable and is there a way to access it from Python?


Solution

  • When you launch a shortcut, Windows changes the working directory to the directory specified in the shortcut, in the Start in field. At this point, Windows has no memory of where the shortcut was stored.

    You could change the Start in field to point to the directory that the shortcut is in. But you'd have to do that for every single shortcut, and never make a mistake.

    The better approach is to use a script, rather than a shortcut. Place your actual Python script (which we'll call doit.py for sake of example) somewhere in your PYTHONPATH. Then create a single-line Python script that imports it:

    import doit
    

    Save it (but don't name it doit.py) and copy it to each directory from which you want to be able to invoke the main script. In doit.py you can use os.getcwd() to find out what directory you're being invoked from.

    You could also do it with a batch file. This is a little more flexible in that you can specify the exact name of the script and which Python interpreter should be used, and don't need to store the script in a directory in PYTHONPATH. Also, you don't need to worry about the file's name clashing with the name of a Python module. Simply put this line in a file:

    C:\path\to\your\python.exe C:\path\to\your\script.py
    

    Save it as (e.g.) doit.bat and copy it into the directories from which you want to invoke it. As before, your Python script can call os.getcwd() to get the directory. Or you can write it so your Python script accepts it as the first argument, and write your batch file like:

    C:\path\to\your\python.exe C:\path\to\your\script.py %cd%
    

    Another thing you can do with the batch file approach is add a pause command to the end so that the user is asked to press a key after the script runs, giving them the opportunity to read any output generated by the script. You could even make this conditional so that it only happens if an error occurs (which requires returning a proper exit code from the script). I'll leave that as an exercise. :-)