Opened 14 years ago

Last modified 5 years ago

#2781 new Patches

Add python exception info extractor

Reported by: macke@… Owned by: Dave Abrahams
Milestone: Boost 1.39.0 Component: python USE GITHUB
Version: Boost 1.38.0 Severity: Not Applicable
Keywords: Cc: loonycyborg@…

Description

Something like this is useful when embedding python, and it took me almost an entire day to figure out how to do this. (Having not used boost::python before, I got many crashes when trying to extract data again.)

Example:

    try {
        boost::python::eval(...);
    } catch (boost::python::error_already_set&) {
        std::string msg = handle_pyerror();
        std::cerr << "Error runnin python code: " << msg;
    }

Implementation:

std::string handle_pyerror()
{
    using namespace boost::python;

    std::ostringstream os;
    os << "Python error:\n  " << std::flush;

    PyObject *type = 0, *val = 0, *tb = 0;
    PyErr_Fetch(&type, &val, &tb);
    handle<> e_val(val), e_type(type), e_tb(allow_null(tb));

    try {
        object t = extract<object>(e_type.get());
        object t_name = t.attr("__name__");
        std::string typestr = extract<std::string>(t_name);

        os << typestr << std::flush;
    } catch (error_already_set const &) {
        os << "Internal error getting error type:\n";
        PyErr_Print();
    }

    os << ": ";

    try {
        object v = extract<object>(e_val.get());
        std::string valuestr = extract<std::string>(v.attr("__str__")());
        os  << valuestr << std::flush;
    } catch (error_already_set const &) {
        os << "Internal error getting value type:\n";
        PyErr_Print();
    }

    if (tb) {
        try {
            object tb_list = import("traceback").attr("format_tb")(e_tb);
            object tb_str = str("").attr("join")(tb_list);
            std::string str = extract<std::string>(tb_str);

            os << "\nTraceback (recent call last):\n" << str;
        } catch (error_already_set const &) {
            os << "Internal error getting traceback:\n";
            PyErr_Print();
        }
    } else {
        os << std::endl;
    }

    return os.str();
}

I'm sure it could be done better, but I'm sure this would help quite a bit.

A wrapper for all python calls that translated python errors into C++-exceptions with proper contents would be very nice, but I can live with this.

Change History (3)

comment:1 by sohail-boost-trac@…, 13 years ago

For me, it would be most useful if I could register an exception handling callback which allows me to throw my own exception when an error occurs in Python. This way, Python code can be called from C++ code just as if it is C++ code. Otherwise, we need to have boilerplate try/catch.

For example, I'd like to write:

void my_from_python_exception_handler()
{
  throw MyException(pyerror_exctract<My::String>()); // don't hardcode above extract to std::string
}
void
somewhere_in_the_app()
{
...
  boost::python::register_from_python_exception_handler(my_from_python_exception_handler);
}

void somewhere_else_in_the_app()
{
  cplusplus->call_python_code_directly_but_looks_like_cplusplus();
}

Hope that helps.

comment:2 by loonycyborg, 13 years ago

Cc: loonycyborg@… added

comment:3 by rosebk, 5 years ago

Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging…

https://www.besanttechnologies.com/training-courses/python-training-institute-in-bangalore

Note: See TracTickets for help on using tickets.