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.