How can I interact with an application on mac through python subprocess?
Question: I know there are similar questions posted already, but non of the methods I
have seen seems to work. I want to launch the application xfoil, on mac, with
python subprocess, and send xfoil a bunch of commands with a script (xfoil is
an application that runs in a terminal window and you interact with it through
text commands). I am able to launch xfoil with the script, but I can't seem to
find out how to send commands to it. This is the code I am currently trying:

    
    
    import subprocess as sp
    
    xfoil = sp.Popen(['open', '-a', '/Applications/Xfoil.app/Contents/MacOS/Xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
    
    stdout_data = xfoil.communicate(input='NACA 0012')
    

I have also tried

    
    
    xfoil.stdin.write('NACA 0012\n')
    

in order to send commands to xfoil.


Answer: As the [man
page](http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/open.1.html)
says,

> The **open** command opens a file (or a directory or URL), just as if you
> had double-clicked the file's icon.

Ultimately, the application gets started by LaunchServices, but that's not
important—what's important is that it's not a child of your shell, or Python
script.

Also, the whole point of `open` is to open the app itself, so you don't have
to dig into it and find the Unix executable file. If you already have that,
and want to run it as a Unix executable… just run it:

    
    
    xfoil = sp.Popen(['/Applications/Xfoil.app/Contents/MacOS/Xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
    

As it turns out, in this case, `MacOS/Xfoil` isn't even the right program;
it's apparently some kind of wrapper around `Resources/xfoil`, which is the
actual equivalent to what you get as `/usr/local/bin/xfoil` on linux. So you
want to do this:

    
    
    xfoil = sp.Popen(['/Applications/Xfoil.app/Contents/Resouces/xfoil'], stdin=sp.PIPE, stdout=sp.PIPE)
    

(Also, technically, your command line shouldn't even work at all; the `-a`
specifies an application, not a Unix executable, and you're supposed to pass
at least one file to open. But because LaunchServices can launch Unix
executables as if they were applications, and `open` doesn't check that the
arguments are valid, `open -a /Applications/Xfoil.app/Contents/MacOS/Xfoil`
ends up doing effectively the same thing as `open
/Applications/Xfoil.app/Contents/MacOS/Xfoil`.)

* * *

For the benefit of future readers, I'll include this information from the
comments:

If you just write a line to `stdin` and then return from the function/fall off
the end of the main script/etc., the `Popen` object will get garbage
collected, closing both of its pipes. If `xfoil` hasn't finished running yet,
it will get an error the next time it tries to write any output, and
apparently it handles this by printing `Fortran runtime error: end of file`
(to stderr?) and bailing. You need to call
[`xfoil.wait()`](http://docs.python.org/2/library/subprocess.html#subprocess.Popen.wait)
(or something else that implicitly `wait`s) to prevent this from happening.

