2016-12-22 50 views
1

我需要在問題之前給出一些背景。請多多包涵。使用boost :: python我向Python公開了一些異常類型,比如MyExceptionType。我有一個boomTest,我暴露給Python來檢查它的工作原理。 Python調用boomTest,它正確處理MyExceptionType,到目前爲止這麼好。這是事物的C++方面:如何防止Python拋出C++ boost :: python :: error_already_set?

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]) 

現在事情變得有點毛茸茸的,因爲在實際的使用情況下,我有一個回調到Python從一個C++升壓(非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++回調觸發器在future.get()調用拋出MyExceptionType用於Python來處理異常時收到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(); 
    } 
} 

回答

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