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

Chad Austin caustin at gmail.com
Thu Jul 1 05:00:19 CEST 2004


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