Search code examples
c++python-embedding

How can I get output of PyErr_Print in windows or save it as a string


I am writing embedded python interpretor, there is a function PyErr_Print() (https://docs.python.org/3/c-api/exceptions.html) which writes to standard error text explaining why C function I called failed.

This doesn't seem to work on windows as it never writes anything to terminal, is there a way to redirect it somewhere, or store as a string so that I can see it?


Solution

  • Here is a solution using boost::python:

    #include <ostream>
    #include <boost/python.hpp>
    
    std::ostream& operator<<(std::ostream& os, boost::python::error_already_set& e) {
      using namespace boost::python;
      // acquire the Global Interpreter Lock
    
      PyObject * extype, * value, * traceback;
      PyErr_Fetch(&extype, &value, &traceback);
      if (!extype) return os;
    
      object o_extype(handle<>(borrowed(extype)));
      object o_value(handle<>(borrowed(value)));
      object o_traceback(handle<>(borrowed(traceback)));
    
      object mod_traceback = import("traceback");
      object lines = mod_traceback.attr("format_exception")(
        o_extype, o_value, o_traceback);
    
      for (int i = 0; i < len(lines); ++i)
        os << extract<std::string>(lines[i])();
    
      // PyErr_Fetch clears the error state, uncomment
      // the following line to restore the error state:
      // PyErr_Restore(extype, value, traceback);
    
      // release the GIL
      return os;
    }
    

    Use like this:

    #include <iostream>
    #include <boost/python.hpp>
    
    try {
       // some code that raises
    catch (boost::python::error_already_set& e) {
       std::cout << e << std::endl; // or stream to somewhere else
    }