星期六, 四月 19, 2008

在 C++ 当中调用 Python 时异常信息的获取

    使用Boost::Ptyhon 可以很方便的将C++当中的对象暴露给 Python 对象,同时也可以通过 虚函数 而后在 Python 当中重写的方式来实现运行时的多态。但是如何在 C++ 当中获取 Python 运行时的错误呢?翻遍了Boost::Python的文档我都没有找到,只是在 Python 的 C API 当中发现了这个方法:


void PyErr_Print( )

Print a standard traceback to sys.stderr and clear the error indicator. Call this function only when the error indicator is set. (Otherwise it will cause a fatal error!)

想当然的就认为和在 C 里面一样,有了 perror 一样,就应该有 strerror 。于是我找啊找啊,就是找不到。没办法了,G了一把之后曲线救国。先在 Python 里面重定向 stderr,然后通过 PyErr_Print 获取异常信息,然后自己再取出来,具体实现如下:

class ErrorCatcher

{//助手类,用来获取python脚本的错误文本

public:

   ErrorCatcher() { clear(); }

   void write( const std::string& str ) { m_text.append(str); }

 

   const std::string& what(void) { return m_text; }

   void clear(void) { m_text.clear(); }

 

private:

   std::string m_text;

};

当然,还是要把这个类导出到 Python 当中:

namespace bp = boost::python;

bp::class_<Base::ErrorCatcher,Base::ErrorCatcherPtr, boost::noncopyable >("ErrorCatcher")

.def( "write", &Base::ErrorCatcher::write )

;

在 Python 脚本的头上这么写:

    #为了配合C++获取异常的错误信息
    import sys
    oldstdcerr = sys.stderr ;
    newstdcerr = core.initalize(...);
    sys.stderr = newstdcerr ;
    #异常处理设置完毕

之后在 C++ 当中调用脚本的时候,可以通过这样的方式来捕获异常:

void processPyException()

{

   const char* desc = NULL;

   if( PyErr_ExceptionMatches(PyExc_ZeroDivisionError) ) {

      desc = "除异常!";

   } // process others errors

 

   PyErr_Print();

   logger.write(desc,gErrorCatcher->what() );

   gErrorCatcher->clear();

}

try{

   ...;//调用脚本

}catch (boost::python::error_already_set& ){

   processPyException();

}

 

在脚本当中发生的异常的输出类似于:

2008-04-19 17:34:23 (2628) [Application] ERROR 执行脚本时发生异常:Traceback (most recent call last):
  File "C:\codes\work\XXXX\debug\StdAlgorithms\XXXXX.py", line 23, in compute
    sonRelationList = mp.getSonRelations();
Boost.Python.ArgumentError: Python argument types in
    MeterPoint.getSonRelations(MeterPoint)
did not match C++ signature:
    getSonRelations(class Core::MeterPoint {lvalue}, class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > relaString)


实在是难以理解为啥 Python 不提供一个直接获取错误字符串描述或者根据错误码获取错误信息的 API。

若有更好的方法,敬请各位看官指教。

#EOF


 

 

没有评论: