2009-09-13 4 views
38

내 C++ 응용 프로그램에 파이썬을 포함시키고 싶습니다. Boost 라이브러리 - 훌륭한 도구를 사용하고 있습니다. 하지만 한 가지 문제가 있습니다.파이썬 예외 텍스트를 얻는 방법

파이썬 함수가 예외를 throw하는 경우, 나는 그것을 잡아 내 응용 프로그램에서 오류를 인쇄하거나 python 스크립트에서 오류를 일으킨 줄 번호와 같은 자세한 정보를 얻고 싶습니다.

어떻게 할 수 있습니까? 파이썬 API 나 부스트에서 상세한 예외 정보를 얻기위한 함수를 찾을 수 없습니다.

try { 
module=import("MyModule"); //this line will throw excetion if MyModule contains an error 
} catch (error_already_set const &) { 
//Here i can said that i have error, but i cant determine what caused an error 
std::cout << "error!" << std::endl; 
} 

PyErr_Print()가 바로 stderr에 오류 텍스트를 인쇄하고 솔루션 파이썬 C API의

답변

41

글쎄, 나는 그것을 어떻게하는지 알았다.

부스트 없음 (단 오류 메시지, 역 추적에서 정보를 추출하는 코드는 여기에 게시 너무 무거운 때문에) :

PyObject *ptype, *pvalue, *ptraceback; 
PyErr_Fetch(&ptype, &pvalue, &ptraceback); 
//pvalue contains error message 
//ptraceback contains stack snapshot and many other information 
//(see python traceback structure) 

//Get error message 
char *pStrErrorMessage = PyString_AsString(pvalue); 

그리고 BOOST 버전

try{ 
//some code that throws an error 
}catch(error_already_set &){ 

    PyObject *ptype, *pvalue, *ptraceback; 
    PyErr_Fetch(&ptype, &pvalue, &ptraceback); 

    handle<> hType(ptype); 
    object extype(hType); 
    handle<> hTraceback(ptraceback); 
    object traceback(hTraceback); 

    //Extract error message 
    string strErrorMessage = extract<string>(pvalue); 

    //Extract line number (top entry of call stack) 
    // if you want to extract another levels of call stack 
    // also process traceback.attr("tb_next") recurently 
    long lineno = extract<long> (traceback.attr("tb_lineno")); 
    string filename = extract<string>(traceback.attr("tb_frame").attr("f_code").attr("co_filename")); 
    string funcname = extract<string>(traceback.attr("tb_frame").attr("f_code").attr("co_name")); 
... //cleanup here 
+1

신난다, 이것은 내가 찾고 있었던 정확하게 것이다. .. 잘 작동한다. –

+0

좋습니다. 내가 어떤 경우에 발견했다 (나를 위해 부스트; : 파이썬 :: 내 PYTHONPATH에없는 것의 import) ptraceback은 0이 될 것이므로 0이면 ptraceback의 사용으로부터 보호 할 것이다. 우리가 extype으로 할 수있는 것에 대해 논평 해주십시오. 나는 파이썬 예외 유형의 텍스트를 인쇄하는 것이의 L가 있다고 가정합니다. 어떻게해야합니까? –

+2

또 하나의 질문 : 위에 메모리가 누출되지 않았습니까? PyErr_Fetch가 반환 한 객체를 해제하는 방법은 무엇입니까? (나는 CPython과 boost :: pythoon의 경우 모두에 대해 확신하지 못한다.) – elmo

4

할 수 없도록 오류를 지우고, PyObject_Str 문자열 양식 파이썬 문자열 객체에 대한 새로운 참조를 반환 Python 코드에서 str(o)처럼 인수로 전달하는 Python 객체의 예외 객체에는 "회선 번호와 같은 정보"가 없습니다. 즉, 추적 코드 객체에 있습니다 (PyErr_Fetch을 사용하면 예외 객체와 추적 객체를 모두 얻을 수 있습니다). Boost가 이러한 특정 C API 함수를 사용하기 쉽게하기 위해 무엇을 제공하는지는 모르지만 최악의 경우 C API 자체에서 제공되는 것처럼 항상 이러한 함수에 의지 할 수 있습니다.

+0

고마워, Alex. 나는 PyAPI를 직접 호출하지 않고 그것을 만들 수있는 방법을 찾고 있었다. 나는 Boost가 예외를 처리 할 수 ​​있지만, Boost는 할 수 없다. ( –

+2

@Anton, 나는 도움이 되었기 때문에 기꺼이 도와 주었다. 이 대답에 대한 upvotes 수 아래의 체크 표시 아이콘 (현재 0 ;-). –

18

를이 가장 강력한 방법이다 나는 지금까지 올 수 있었다 :

try { 
     ... 
    } 
    catch (bp::error_already_set) { 
     if (PyErr_Occurred()) { 
      msg = handle_pyerror(); 
     } 
     py_exception = true; 
     bp::handle_exception(); 
     PyErr_Clear(); 
    } 
    if (py_exception) 
    .... 


// decode a Python exception into a string 
std::string handle_pyerror() 
{ 
    using namespace boost::python; 
    using namespace boost; 

    PyObject *exc,*val,*tb; 
    object formatted_list, formatted; 
    PyErr_Fetch(&exc,&val,&tb); 
    handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb)); 
    object traceback(import("traceback")); 
    if (!tb) { 
     object format_exception_only(traceback.attr("format_exception_only")); 
     formatted_list = format_exception_only(hexc,hval); 
    } else { 
     object format_exception(traceback.attr("format_exception")); 
     formatted_list = format_exception(hexc,hval,htb); 
    } 
    formatted = str("\n").join(formatted_list); 
    return extract<std::string>(formatted); 
} 
+1

빈 핸들을'format_exception'에 건네 주면 분명히'! tb'는 필요 없습니다. – uckelman

+1

이 해결 방법은 훌륭합니다. PyErr_NormalizeException (& exc, & val, &tb);)을 호출해야합니다. [이 답변] (http://stackoverflow.com/a/16806477/3524982)과 같이 말합니다. – DJMcMayhem