Update:
I ended getting the desired result by registering a new trace function. In my existing trace function I check the status of the abort button. When it's been triggered I register a NEW trace function using PyEval_SetTrace. I also use PyEval_SetProfile and point them both at my new trace function. The new trace function just raises a python exception using PyErr_SetString. Then I return -1 from the trace function. It gets called several times but eventually the script dies. This works even when the python script running is an insane set of nested try/except loops.
-- http://mail.python.org/mailman/listinfo/python-list