如何防止 Python 返回到 C++ boost::python::error_already_set?
How to prevent Python from throwing back to C++ boost::python::error_already_set?
我需要在问题之前提供一些背景信息。请多多包涵。使用 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:
当 future.get()
调用抛出 MyExceptionType
供 Python 处理时,为什么我的 C++ 回调触发器会收到 boost::python::error_already_set
异常?我怀疑这种行为是由于异常是在 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();
}
}
我验证了我关于 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
我需要在问题之前提供一些背景信息。请多多包涵。使用 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:
当 future.get()
调用抛出 MyExceptionType
供 Python 处理时,为什么我的 C++ 回调触发器会收到 boost::python::error_already_set
异常?我怀疑这种行为是由于异常是在 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();
}
}
我验证了我关于 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