How to prevent embedded python to exit() my process

Question:

I’m having trouble while running embedded python. It turns out that I can’t capture that SystemExit exception raised by sys.exit();

This is what I have so far:

$ cat call.c 
#include <Python.h>
int main(int argc, char *argv[])
{
    Py_InitializeEx(0);
    PySys_SetArgv(argc-1, argv+1);
    if (PyRun_AnyFileEx(fopen(argv[1], "r"), argv[1], 1) != 0) {
        PyObject *exc = PyErr_Occurred();
        printf("terminated by %sn",
                PyErr_GivenExceptionMatches(exc, PyExc_SystemExit) ?
                "exit()" : "exception");
    }
    Py_Finalize();
    return 0;
}

Also, my script is:

$ cat unittest-files/python-return-code.py 
from sys import exit
exit(99)

Running it:

$ ./call unittest-files/python-return-code.py 
$ echo $?
99

I must execute a file, not a command.

Asked By: Caruccio

||

Answers:

PyRun_SimpleFileExFlags function (and all functions using it, including PyRun_AnyFileEx) handles exceptions itself by exiting for SystemExit or printing traceback. Use PyRun_File* family of functions to handle exceptions in surrounding code.

Answered By: Denis Otkidach

Based on Denis’ answer, here is a code snippet that I’ve came up with:

PyObject* main_module = PyImport_AddModule("__main__");
if (!main_module) {
    PyErr_Print();
    // Failure
} else {
    Py_INCREF(main_module);
    PyObject *pdict = PyModule_GetDict(main_module);
    if (PyRun_File(file, file_name, Py_file_input, pdict, pdict) != NULL) {
        // Success
    } else {
        Py_CLEAR(main_module);
        PyObject *exception_type = PyErr_Occurred();
        if (!PyErr_GivenExceptionMatches(exception_type, PyExc_SystemExit)) {
            PyErr_Print();
            // Failure
        } else {
            PyObject *type;
            PyObject *value;
            PyObject *traceback;
            PyErr_Fetch(&type, &value, &traceback);

            long exit_code = PyLong_AsLong(value);
            std::cout << exit_code << std::endl;
                    
            if (exit_code == 0) {
                // Success
            } else {
                // Failure: sys.exit() with non-zero code
            }

            Py_XDECREF(type);
            Py_XDECREF(value);
            Py_XDECREF(traceback);
        }
    }
    Py_XDECREF(main_module);
}
Answered By: George Vinokhodov
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.