[C++-sig] Re: Calling a python function from C++ (from Jeff Holle)

Jeffrey Holle jeff.holle at verizon.net
Sun Jul 4 04:24:42 CEST 2004


I want to thank you for this.

I've attempted to improve it, based on code I've found on the internet.
It basically adds "Extra Extraa paranoia" about the nature of whats 
returned from PyErr_Fetch.  Don't know if this level of paranoia is 
needed.  But I try to assume nothing.

I've attempted to tackle the traceback info too.  At this point I don't 
believe its possible because of inadequeses in the Python "C" API.

The one traceset specific function that I do use is undocumented, and it 
just verifies that the python object is really a traceback object.

If you, or anybody, have a different opinion, I'd like to know about it.

My code, modified your example is:

   // Extra paranoia...
   if (!PyErr_Occurred()) {
     return;
   }
   // PyErr_Print();
   PyObject *type = NULL, *value = NULL, *traceback = NULL, *pyString = 
NULL;
   PyErr_Fetch(&type, &value, &traceback);
   PyErr_Clear();
   _M_msg = "Python error: ";
   if (type != NULL && (pyString=PyObject_Str(type))!=NULL && 
(PyString_Check(pyString)))
     _M_msg += PyString_AsString(pyString);
   else
     _M_msg += "<unknown exception type> ";
   Py_XDECREF(pyString);
   if (value != NULL && (pyString=PyObject_Str(value))!=NULL && 
(PyString_Check(pyString))) {
     _M_msg += ": ";
     _M_msg += PyString_AsString(value);
   } else
     _M_msg += "<unknown exception date> ";
   Py_XDECREF(pyString);
   if (traceback != NULL && PyTraceBack_Check(traceback)) {
     // what belongs here? TBD
   }
   Py_XDECREF(type);
   Py_XDECREF(value);
   Py_XDECREF(traceback);




Chad Austin wrote:
> Straight from my codebase:
> 
>     std::string getPythonErrorString() {
>         // Extra paranoia...
>         if (!PyErr_Occurred()) {
>             return "No Python error";
>         }
> 
>         PyObject *type, *value, *traceback;
>         PyErr_Fetch(&type, &value, &traceback);
>         PyErr_Clear();
> 
>         std::string message = "Python error: ";
>         if (type) {
>             type = PyObject_Str(type);
>             message += PyString_AsString(type);
>         }
>         if (value) {
>             value = PyObject_Str(value);
>             message += ": ";
>             message += PyString_AsString(value);
>         }
>         Py_XDECREF(type);
>         Py_XDECREF(value);
>         Py_XDECREF(traceback);
> 
>         return message;
>     }
> 
>     void checkForPythonError() {
>         if (PyErr_Occurred()) {
>             throw PythonError(getPythonErrorString());
>         }
>     }
> 
>     void requirePythonError() {
>         if (!PyErr_Occurred()) {
>             throw PythonError("Boost.Python exception, "
>                               "but no Python error set.");
>         }
>     }
> 
> ...
> 
>     PYR_DEFINE_RUNTIME_ERROR(PythonError);
> 
>     std::string getPythonErrorString();
>     void checkForPythonError();
>     void requirePythonError();
> 
>     /**
>      * Allows us to check for Python errors at the end of a Python
>      * code block whether control left the end of the block or
>      * 'return' was used.
>      */
>     struct PythonCodeErrorSentry {
>         ~PythonCodeErrorSentry() {
>             if (!std::uncaught_exception()) {
>                 checkForPythonError();
>             }
>         }
>     };
> 
>     #define PYR_NO_UNUSED_WARNING(x) ((void)&(x))
> 
>     #define PYR_BEGIN_PYTHON_CODE()                          \
>         try {                                                \
>             PythonCodeErrorSentry sentry__;                  \
>             PYR_NO_UNUSED_WARNING(sentry__);  // silly gcc
> 
>     #define PYR_END_PYTHON_CODE()                            \
>         }                                                    \
>         catch (const boost::python::error_already_set&) {    \
>             requirePythonError();                            \
>             throw PythonError(getPythonErrorString());       \
>         }
> 
> 
> May have bugs, but it should give you an idea of what to do.  Notice I
> don't do anything with the stacktrace object yet, but it wouldn't take
> much more work.
> 
> HTH,
> Chad
> 
> 
> On Wed, 30 Jun 2004 02:39:46 -0400, Jeffrey Holle
> <jeff.holle at verizon.net> wrote:
> 
>>Given what the name of this exception, I assume there is a source of
>>information to obtain useful information about it.
>>To this end, I've dug a bit into the Python C API and found the added
>>the following to my code example:
>>
>>   catch (error_already_set& x) {
>>        PyObject *err_type,*err_value,*err_traceback;
>>        PyErr_Fetch(&err_type,&err_value,&err_traceback);
>>         cout << "something bad happened" << endl;
>>     }
>>
>>While I see that err_type and error_value are not null pointers after
>>the call to PyErr_Fetch, I don't know what to do with either to get at a
>>useful message.
>>Can anybody provide any hints?
>>
>>
>>
>>Jeffrey Holle wrote:
>>
>>>I've explored whats actually going on some with my debugger and now see
>>>what is being thrown.
>>>It is "error_already_set".  This is a trivial object (it has no
>>>attributes at all), and isn't much better than "catch (...)".
>>>However, its name implies something.  Is there a meaningful error
>>>message set somewhere else that can be accessed within the catch clause
>>>of "error_already_set"?
>>>
>>>Jeff Holle wrote:
>>>
>>>
>>>>>
>>>>>>An underlining concern I have is error handling.  When
>>>>>>PyImport_ImportModule fails, a NULL pointer is returned.
>>>>>>Seems like the underlining machinery in "handle<>" is intolerant of
>>>>>>this.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>What makes you say that?
>>>>>
>>>>
>>>>You are correct about the success in compiling your much cleaner
>>>>example, and it works :-) , but has a flaw.
>>>>
>>>>When I hide the needed python script, the call to
>>>>PyImport_ImportModule returns NULL.
>>>>When this occurres, both your example and what I had created, but
>>>>commented out throws something because I can catch it with
>>>>"catch(...)".  I don't however know how to be more specific.  Any
>>>>hints?  Whatever it is, it doesn't inherit from "exception".
>>>>
>>>>If I was operating on windows, I would anticipate it was a "structured
>>>>exception", or whatever Microsoft calls their propritary stuff.  Don't
>>>>know of the equivalent on linux though.  Without the "catch (...)",
>>>>the command line program exits with "Aborted".
>>
>>_______________________________________________
>>C++-sig mailing list
>>C++-sig at python.org
>>http://mail.python.org/mailman/listinfo/c++-sig
>>




More information about the Cplusplus-sig mailing list