2/21/2004

Running scripts in pythonw from Xcode

The previous tip works fine if your Python script is just a command-line script that doesn't require any interaction with the WindowServer. However, if your script needs to be run with pythonw normally in order to interact with the user in a GUI fashion, it won't work. Xcode won't let you select /usr/bin/pythonw as the executable because it is just a shell script, not a binary executable. To work around this, use /bin/sh as the executable and pass pythonw and your python file as arguments to sh:

Choose Project->New Custom Executable
Type /bin/sh as the Executable Path
Double-click on the new executable
Click the plus button under Arguments and type:
/usr/bin/pythonw /path/to/your/script/here.py

Update: Bob has pointed out in a comment that you can use the executable that the pythonw script runs directly. I have tested it and it seems to work for me. Set the executable path to:

/System/Library/Frameworks/Python.framework/Versions/2.3/Resources/Python.app/Contents/MacOS/Python

And the arguments to the path of your script. Thanks Bob!

2/19/2004

Running Python scripts inside Xcode

It's not terribly difficult to tell Xcode to launch a Python process and start your script, but it comes up now and again, so I thought I would spell out the steps required.

Choose File->New Project.
Choose Empty project.
Choose where to save it and what to name it, and click Finish.

Choose Project->New custom executable
Give the executable any name you want (I usually call it 'python') and *type in* the executable path to the python you want to run (/usr/bin/python or /usr/local/bin/python) and click Finish.
You can now use Debug->Run executable (Command-R) to get a Python prompt. Be warned that you can't send Control-D to this process, and clicking the stop task button rather harshly kills the process. This is the one drawback I have found to using this method.

Now, double-click on the 'python' executable you just created in the Executables list. You will be able to set the launch arguments, environment variables, working directory and more.

Press the plus button under Arguments, and type in the fully-qualified path of your main python script.

It is good if your script can run to completion, so hopefully it is just a script that does something and exits, or if it is an application which enters a mainloop and runs forever, it has some way of externally shutting it down. You can kill it with the stop button, but it's not a clean kill at all.

2/11/2004

Have you met my Evil Twin?

Well, I finally did it. I re-implemented LivePage in Nevow. It was a piece of cake, really. The hardest part was coming up with the right design for how to allow programmers access to the client object which represents a user's browser. After talking to itamar about it at length, I finally realized that the cred 'mind' concept was the perfect solution. With very little code, a programmer can write a new realm which mediates for the entire application. It can then be the central point for all the clients to communicate with each other, such as in a chat application.

I wrote a simple example chat application called Chatola. You can get the source here:

http://soundfarmer.com/content/code/chatola/

Download all three files and run the tac file using:

twistd -noy chatola.tac

Currently, you will need to have Twisted (http://twistedmatrix.com) and a recent CVS checkout of Quotient (http://divmod.org) installed. Soon, nevow will be released as a standalone package.

CoreAudio from Python

Well, I've only been talking about doing it for 4 years now, but I finally got Python playing some buffers of audio using CoreAudio. It was about a day's worth of hacking, with a few hours on the side nailing down threading issues.

I put the code up here:

http://soundfarmer.com/content/code/coreaudio/

I also put a short description of what it is on the pythonmac wiki:

http://pythonmac.org/wiki/CoreAudio

CoreAudio calls you back in a thread, you see. A thread Python hasn't seen before. Python doesn't like that very much. This isn't the first time I have tackled this issue. CarbonEvents also call you back in a new thread you haven't seen yet. Two years ago when I wrote the CarbonEvent wrappers for Python, there were no convenient ways to deal with this situation. Before you are allowed to request the global interpreter lock, you must have a PyThreadState. You can create a new PyThreadState, but only if you have a PyInterpreterState. And if you are getting called back from a new thread that has never seen Python before, you are pretty much out of luck.
The solution I came up with for CarbonEvents, later on Windows talking to a stupid Asset Management system, and finally for CoreAudio, is to make an initialization call into my module which will eventually be generating callbacks into Python. In this call, I stash the current PyInterpreterState away in a C global. Then, when the new thread comes in and needs to make a PyThreadState you can use the stashed PyInterpreterState.
This time I was trying to use Pyrex to wrap the C calls I needed, partially because I thought it would be fast and easy and partially because I wanted to learn Pyrex. During the build-crash-debug cycle I kept thinking to myself there was an easier way that I had read about a while ago, and I was right: http://python.org/peps/pep-0311.html describes an implementation of an API specifically designed for this situation which is included in Python 2.3.
I'm happy to say it works quite well, and I was able to generate my sine wave in python code. I even went on later and used numarray to wrap the incoming and outgoing buffer for a speed boost.
My favorite thing about Python is that it is trivial for those who aren't afraid of C to get access to literally everything they need, if it's not possible already.