Preventing embedded python from killing your app

I was looking at a defect in Piger where a Python script could close Piger itself, it wasn’t a crash, but rather a graceful exit.

import am
am.say( "Bye", 1, 1 );
exit(1);

The problem was with the way I was calling the script rather than anything wrong with Piger or Python itself.

Somewhere in the Python virtual machine I had something like…

...
if( -1 == PyRun_SimpleString( ... ) )
{
...
}
...

And, while that works fine in most cases, if I have an exit( xyz ) in my script, piger would close.
So the answer was to replace it with …


...
PyObject * PyRes = PyRun_String(s, Py_file_input, main_dict, main_dict);
PyObject* ex = PyErr_Occurred();
if( NULL != ex)
{
...
}
...

The one last problem was, how to tell if the error was because of an exit(…) or because of an error.


...
PyObject * PyRes = PyRun_String(s, Py_file_input, main_dict, main_dict);
PyObject* ex = PyErr_Occurred();
if( NULL != ex)
{
// if we exit(...) then 'ex' is not NULL, so we must check for that.
if (!PyErr_ExceptionMatches(PyExc_SystemExit))
{
// this is a real coding error.
}
}
...

Now you can catch all the real errors and swallow all the exist code and so on.

See the exceptions handling in Python and embedding in general.