3

I am trying to run the following code:

Py_Initialize();
PyObject *py_main = PyImport_AddModule("__main__");
PyObject *py_dict = PyModule_GetDict(py_main);
PyObject *ret = PyRun_String(SOME_PYTHON_CODE, Py_file_input, py_dict, py_dict);

But it seems there is an error somewhere in my generated python code (SOME_PYTHON_CODE) and so ret comes out as NULL indicating an exception was raised. How can I get access to this exception?

Matt
  • 21,026
  • 18
  • 63
  • 115

2 Answers2

5

You can do:

PyErr_Print();

To get a standard stack trace printed out on standard error. There are other more fine tuned function calls to handle errors, but I believe this is the simplest, bare bones approach.

And here is a question/answer about accessing the traceback objects. One of the answers shows how to get the backtrace copied into a C string, which you could then write to file (or GUI in your case).

mshildt
  • 8,782
  • 3
  • 34
  • 41
  • One of the problems I'm having is actually that I can't seem to connect python's stdin/stdout/stderr to the console window (this is a GUI application, and I had to manually open a console window). So `PyErr_Print()` would not help me at all. – Matt Aug 06 '14 at 19:00
  • You can get the actual traceback object (I've updated my answer to show how). Then look at fields within the traceback object to figure out what happened. I'm not super familiar with the traceback objects though. – mshildt Aug 06 '14 at 19:08
  • I just tried doing that, but it seems that `PyException_GetTraceback` is not defined in Python.h. – Matt Aug 06 '14 at 19:16
  • @Matt Oh, you must be using Python 2. Since it didn't say in your question I assumed you were using the latest (Python 3). In that case I think you'll need to use `PyErr_Fetch()`. – mshildt Aug 06 '14 at 19:54
  • That's a pretty bad assumption, since Python 2 is still very much more widely used, but thanks! – Matt Aug 06 '14 at 21:28
  • This answer seems to be either wrong or relying on old API behavior, at least it doesn't work at all in python 3.8: `PyErr_Occurred` will return just the *type* of the exception, not the exception itself. Trying to call `PyException_GetTraceback` on the type is going to fail. One must just call `PyErr_Fetch` to retrieve the exception, together with the traceback object. The [documentation](https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Occurred) is very clear about this. – ceztko Apr 13 '21 at 08:10
0

Since you didn't specify the number of statements SOME_PYTHON_CODE there may be another issue at play: according to this page of a Boost Python Tutorial, the output of PyRun_String also depends on the start parameter:

  • Py_eval_input for interpreting isolated expressions
  • Py_file_input for interpreting sequences of statements
  • Py_single_input for interpreting a single statement

It goes on to say:

When using Py_eval_input, the input string must contain a single expression and its result is returned. When using Py_file_input, the string can contain an abitrary number of statements and None is returned. Py_single_input works in the same way as Py_file_input but only accepts a single statement.

So if you use Py_file_input in your call to PyRun_String you'll always receive None. Instead you might use Py_single_input.

melle
  • 1
  • 2