跳到主要內容

Exception Translation from C++ to Python with Boost.Python

Exception Translation from C++ to Python with Boost.Python

Scenario

Say we have written a Python binding with Boost.Python. Something like following code.

// some.cpp
#include <stdexcept>
#include <boost/python.hpp>

struct my_exception : std::exception
{
    my_exception(int extra_info): extra_info(extra_info) {}
    char const *what() noexcept(true) { return "My exception"; }
    int const extra_info;
};

void do_throw()
{
   throw my_exception();
}

// Something should be done here ...

BOOST_PYTHON_MODULE(MyLib)
{
   using namespace boost::python;
   def("do_throw", &do_throw);
}

And we wish to catch a Python exception object in Python code, e.g.

import MyLib

try:
    MyLib.do_throw()
except MyLib.MyException as e:
    print e, e.extra_info
    pass

The situation is, we can’t directly pass the exception object, my_exception, to Python. Now the rescue is:

  1. Define a Python MyException class
  2. Create an unique instance of above class in your library
  3. Translate my_exception to MyException

Define MyException Class

PyObject *createExceptionClass(std::string const &module, 
                               std::string const &exception_name, 
                               PyObject *base)
{
    namespace bp = boost::python
    std::string fullname = module + "." + exception_name;
    PyObject* typeObj = PyErr_NewException((char*)fullname.c_str(),
                                            base, 0);
    if (!typeObj) boost::python::throw_error_already_set();

    bp::scope().attr(exception_name.c_str()) =
            // semantically equal to make_shared(typeObj)
            bp::handle<>(bp::borrowed(typeObj));
    return typeObj;
}

Cited from StackOverflow

Create an Exception Instance

// static instance
PyObject *myexception_instanct_ = 0;

BOOST_PYTHON_MODULE(pyvddk)
{
    myexcdption_instance_ = 
        createExceptionClass("pyvddk", "MyException",
                             PyExc_RuntimeError);
}

Translate Exception

// static instance
PyObject *myexception_instanct_ = 0;

void translate(my_excpetion const &e)
{
    namespace bp = boost::python;
    bp::object exc(bp::handle<>(bp::borrowed(myexception_instance_)));
    // copy data from my_exception to MyException
    exc.attr("extra_info") = e.extra_info;
    PyErr_SetString(myexception_instance, e.what());
}

BOOST_PYTHON_MODULE(pyvddk)
{
    using namespace boost:python;
    
    myexcdption_instance_ = 
        createExceptionClass("pyvddk", "MyException",
                             PyExc_RuntimeError);

    register_exception_translator<my_exception>(&translate)
}

Full Code Listing

PyObject *createExceptionClass(std::string const &module, 
                               std::string const &exception_name, 
                               PyObject *base)
{
    namespace bp = boost::python
    std::string fullname = module + "." + exception_name;
    PyObject* typeObj = PyErr_NewException((char*)fullname.c_str(),
                                            base, 0);
    if (!typeObj) boost::python::throw_error_already_set();

    bp::scope().attr(exception_name.c_str()) =
            // semantically equal to make_shared(typeObj)
            bp::handle<>(bp::borrowed(typeObj));
    return typeObj;
}

// static instance
PyObject *myexception_instanct_ = 0;

void translate(my_excpetion const &e)
{
    namespace bp = boost::python;
    bp::object exc(bp::handle<>(bp::borrowed(myexception_instance_)));
    // copy data from my_exception to MyException
    exc.attr("extra_info") = e.extra_info;
    PyErr_SetString(myexception_instance, e.what());
}

BOOST_PYTHON_MODULE(pyvddk)
{
    using namespace boost:python;
    
    myexcdption_instance_ = 
        createExceptionClass("pyvddk", "MyException",
                             PyExc_RuntimeError);

    register_exception_translator<my_exception>(&translate)
}

Written with StackEdit.

留言

這個網誌中的熱門文章

得利油漆色卡編碼方式

得利油漆色卡編碼方式 類似 Munsell 色彩系統 ,編碼方式為 HUE LRV/CHROMA 例如 10GY 61/449 ( 色卡 ) 編碼數值 描述 10GY hue ,色輪上從 Y(ellow) 到 G(reen) 區分為 0 ~ 99 ,數值越小越靠近 Y,越大越靠近 G 61 LRV (Light Reflectance Value) 塗料反射光源的比率,數值從 0% ~ 100% ,越高越亮,反之越暗,也可理解為明度 449 chroma 可理解為彩度,數值沒有上限,越高顏色純度 (濃度) 越高 取決於測量儀器,對應至 RGB 並不保證視覺感受相同。 參考資料: 色卡對照網站 e-paint.co.uk Written with StackEdit .

C++17 新功能 try_emplace

C++17 新功能 try_emplace 回顧 emplace 大家的好朋友 Standard Template Library (STL) 容器提供如 push_back , insert 等介面,讓我們塞東西進去; C++11 之後,新增了 emplace 系列的介面,如 std::vector::emplace_back , std::map::emplace 等,差異在於 emplace 是在容器內 in-place 直接建構新元素,而不像 push_back 在傳遞參數前建構,下面用實例來說明: struct Value { // ctor1 Value ( int size ) : array ( new char [ size ] ) , size ( size ) { printf ( "ctor1: %d\n" , size ) ; } // ctor2 Value ( const Value & v ) : array ( new char [ v . size ] ) , size ( v . size ) { printf ( "ctor2: %d\n" , size ) ; memcpy ( array . get ( ) , v . array . get ( ) , size ) ; } private : std :: unique_ptr < char [ ] > array ; int size = 0 ; } ; struct Value 定義了自訂建構子 (ctor1),以指定大小 size 配置陣列,複製建構子 (ctor2) 則會配置與來源相同大小及內容的陣列,為了方便觀察加了一些 printf 。當我們如下使用 std::vector::push_back 時 std :: vector < Value > v ; v . push_back ( Value ( 2048 ) ) ; 首先 Value 會先呼叫 ctor1,傳給 push_ba...

Notes for C/C++ Programming

Notes for C/C++ Programming Notes for C/C++ Programming Off by One Error Prone # define LEN 128 char buf [ LEN ] = { 0 } ; // -1 for prevent missing NULL terminator // since strncpy doesn't preserve it for us. strncpy ( buf , something , sizeof ( buf ) - 1 ) ; // snprintf does preserve NULL terminator for us // i.e. actual size for placing characters is sizeof(buf) - 1 // but it takes extra time to parsing format snprintf ( buf , sizeof ( buf ) , something ) ; Bad things often happen when we mess with -1 or +1 to pointers point to continuous elements. Absorber # define LEN 128 char buf [ LEN + 1 ] = { 0 } ; // ^^^^ Always preserve 1 byte strncpy ( buf , somethin , sizeof ( buf ) ) ; Constant Correctness (C/C++) Bad void do_something ( char * dest , char * src ) ; struct MyList { void do_something ( std :: string & name ) ; } ; Reason : Will the name be modified by the lookup method? Will stat...