Python app which reads and writes into its current working directory as a .app/exe
Question: I have a python script which reads a text file in it's current working
directory called "data.txt" then converts the data inside of it into a json
format for another separate program to handle.

The problem i'm having is that i'm not sure how to read the .txt file (and
write a new one) which is in the same directory as the .app when the python
script is all bundled up. The current method i'm using doesn't work because of
something to do with it using the fact that it's ran from the terminal instead
of executed as a .app?

Any help is appreciated!


Answer: A .app on the Mac doesn't have any reasonable current working directory when
launched.

Of course it has _some_ working directory, and you can easily find out what it
is at runtime by `os.getcwd()`, and you can test on a variety of different
ways of launching on different versions of OS X to figure out all of the
patterns, but what good does that do you?

The good news is, you apparently don't actually want the current working
directory; you need the directory of the .app bundle or .exe.

In other words, if someone does this:

    
    
    C:\Users\foo> C:\Stuff\MyProgram.exe
    

You want `C:\Stuff` (the executable's directory), not `C:\Users\foo` (the
working directory).

On Windows, this is easy. An .exe is just a file, and its path will be the
`__path__` you get in Python, so:

    
    
    import os
    pathToApp = os.path.dirname(__path__)
    

On Mac, it's harder. A .app is a bundle—a directory containing other files and
directories. Somewhere in there is an executable interpreter and a copy of
your script, and `__path__` is going to give you the latter, not the path to
the .app.

The correct way to get that is to use Cocoa (or CoreFoundation):

    
    
    import Cocoa
    pathToApp = Cocoa.NSBundle.mainBundle().bundlePath()
    

If you don't want to do that, you pretty much have to rely on some information
that the documentation says you can't rely on and could change some day. But
the following code should be safe:

    
    
    import os
    pathToApp = __file__
    while not pathToApp.endswith('.app'):
      path = os.path.dirname(path)
    

In order for this to stop working, either the script would have to be outside
the .app bundle, or inside another .app inside the one you're looking for, or
bundles would have to stop being named .app, or they'd have to stop being
structured as normal directories; none of this seems likely to change in OS X
10.*, or even OS Y 11.

As a side issue: what you're trying to do is most likely a bad idea in the
first place. A Mac application shouldn't be working with files alongside it.
Conversely, if users are going to expect to work on files alongside it, you
probably want a simple Unix executable (or just a plain Python script with
chmod +x), not an application.

