如何防止Python回退到C ++ boost :: python :: error_already_set?

时间:2016-12-22 12:58:52

标签: python c++ exception-handling boost-python

我需要在问题面前给出一些背景信息。请多多包涵。使用boost :: python我向Python公开了一些异常类型,比如MyExceptionType。我有一个boomTest我向Python公开以检查它是否有效。 Python调用boomTest并正确处理MyExceptionType,到目前为止一直很好。这是C ++方面的事情:

static void boomTest() {
    throw MyExceptionType("Smoked too many Cohibas!");
}

static PyObject *myExceptionPtr = NULL;
static void translate(MyExceptionType const &exception) {
    assert(myExceptionPtr != NULL);
    boost::python::object pythonExceptionInstance(exception);
    PyErr_SetObject(myExceptionPtr, pythonExceptionInstance.ptr());
}

BOOST_PYTHON_MODULE(test) {
    class_<MyExceptionType> myException("MyExceptionType", no_init);
    myException.add_property("message", &MyExceptionType::what);
    myExceptionPtr = myException.ptr();
    register_exception_translator<MyExceptionType>(&translate);
}

这是Python的一面:

import sys

import example
reload(example)
from example import MyExceptionType, boomTest

def tryBoomTest():
    try:
        boomTest()

    except MyExceptionType as ex:
        print 'Success! MyExceptionType gracefully handled:' \
            '\n message="%s"' % ex.message
    except:
        print 'Caught unhandled exception: %s "%s"' % (sys.exc_info()[0], sys.exc_info()[1])

现在事情变得有点毛茸茸了,因为在一个真实的用例中,我从C ++ Boost(非Python)线程回调Python,如下所示:

# this is a Python callback invoked from a C++ boost non-Python thread
def handle(future):
    try:
        # future.get() throws MyExceptionType if there was a cluster exception
        "Cluster response received with value: %s" % future.get()

    except MyExceptionType as ex:
        print 'Success! MyExceptionType gracefully handled:' \
            '\n message="%s"' % ex.message

现在OP

为什么我的C ++回调触发器会在boost::python::error_already_set调用抛出future.get()以供Python处理时遇到MyExceptionType异常?我怀疑这种行为是由于在C ++(非Python)线程中引发异常这一事实引起的......

强制Python处理异常需要什么,如开头的示例案例那样?

我已尝试使用C ++的回调触发器执行以下操作:

void callbackTrigger() {
    try {
        pythonHandle_(getFuture());
    }
    // why do I get this???
    catch (boost::python::error_already_set&) {
        // this doesn't help, Python doesn't still handle MyExceptionType
        boost::python::handle_exception();
    }
}

1 个答案:

答案 0 :(得分:1)

我验证了我的Python理论,不喜欢处理抛出的异常(即使在Python代码中),但作为外来C ++线程的一部分执行。因此,我构建了这个纯Python包装器,以便能够处理主Python线程中的回调。

import example
reload(example)
from example import MyExceptionType

condition = threading.Condition()
futures = []

# Actual handle executed by the main Python THREAD
# __after__ submitting all the jobs to the Cluster
# N is the number of jobs that were submitted to the Cluster
def handle(N):
    while (N > 0):
        condition.acquire()
        try:
            # wait for max of a second to prevent this thread waiting indefinitely
            # when it misses notify while being busy processing responses
            condition.wait(1.0)
            for future in futures:
                try:
                    print 'callback received! the response is:\n %s' % future.get()

                except MyExceptionType as ex:
                    print 'MyExceptionType gracefully handled:' \
                          '\n message="%s"' % ex.message
                except:
                    print 'Caught unhandled exception: %s "%s"' % (sys.exc_info()[0], sys.exc_info()[1])
        finally:
            N -= len(futures)
            del(futures[:])
            condition.release()

# callback called from a C++ boost THREAD
def callback(future):
    condition.acquire()
    try:
        # do not consume the future here, rather let the main 
        # Python thread deal with it ...
        futures.append(future)
        condition.notify()
    finally:
        condition.release()

它不理想,但它有效并且输出正确:

registering callback 1 ...
registering callback 2 ...
registering callback 3 ...
registering callback 4 ...
registering callback 5 ...
MyExceptionType gracefully handled:
 message="Smoked too many Cohibas!"
MyExceptionType gracefully handled:
 message="Smoked too many Cohibas!"
MyExceptionType gracefully handled:
 message="Smoked too many Cohibas!"
MyExceptionType gracefully handled:
 message="Smoked too many Cohibas!"
MyExceptionType gracefully handled:
 message="Smoked too many Cohibas!"

Process finished with exit code 0