2009-09-13 7 views
38

पाने के लिए मैं अपने सी ++ आवेदन में अजगर एम्बेड करना चाहते हैं। मैं बूस्ट लाइब्रेरी का उपयोग कर रहा हूं - महान उपकरण। लेकिन मुझे एक समस्या है। अजगर समारोह एक अपवाद फेंकताकैसे अजगर अपवाद पाठ

हैं, तो मैं इसे और प्रिंट त्रुटि अपने आवेदन में पकड़ने के लिए या कि त्रुटि के कारण अजगर स्क्रिप्ट में लाइन नंबर जैसे कुछ विस्तृत जानकारी प्राप्त करना चाहते हैं।

मैं यह कैसे कर सकते हैं? मुझे पायथन एपीआई या बूस्ट में विस्तृत अपवाद जानकारी प्राप्त करने के लिए कोई फ़ंक्शन नहीं मिल रहा है।

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 करने के लिए त्रुटि पाठ प्रिंट और त्रुटि को साफ करता है तो यह समस्या का समाधान नहीं हो सकता है

उत्तर

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

और बूस्ट संस्करण

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 में) ptraceback 0 हो जाएगा, तो मैं एक ptraceback के उपयोग के खिलाफ की रक्षा करता हूँ अगर यह 0. इसके अलावा है, कर सकते हैं इस बारे में टिप्पणी करें कि हम विस्तार के साथ क्या कर सकते हैं? मुझे लगता है कि पायथन अपवाद प्रकार के पाठ को सार्थक अर्थपूर्ण है। हम यह कैसे करे? –

+2

एक अतिरिक्त प्रश्न: क्या हम उपर्युक्त स्मृति को लीक नहीं कर रहे हैं? PyErr_Fetch द्वारा लौटाई गई वस्तुओं को क्या मुक्त करता है? (मुझे सीपीथॉन और बूस्ट :: पायथन मामलों के बारे में निश्चित नहीं है) – elmo

4

अजगर सी एपीआई में, PyObject_Str स्ट्रिंग फार्म के साथ एक अजगर स्ट्रिंग वस्तु के लिए एक नया संदर्भ देता है पायथन ऑब्जेक्ट का आप तर्क के रूप में गुज़र रहे हैं - जैसे कि पाइथन कोड में str(o) की तरह। ध्यान दें कि अपवाद वस्तु "लाइन नंबर की तरह जानकारी" नहीं है - कि (आप PyErr_Fetch उपयोग कर सकते हैं दोनों अपवाद वस्तु और ट्रैस बैक वस्तु प्राप्त करने के लिए) ट्रैस बैक वस्तु में है। पता नहीं क्या (अगर कुछ भी) बूस्ट इन विशिष्ट सी एपीआई कार्यों को उपयोग करने में आसान बनाता है, लेकिन, सबसे खराब मामला, आप हमेशा इन कार्यों का सहारा ले सकते हैं क्योंकि उन्हें सी एपीआई में ही पेश किया जाता है।

+0

बहुत धन्यवाद, एलेक्स। मैं एक तरह से देख रहा था PyAPI के प्रत्यक्ष बुला बिना इसे बनाने के लिए - मैं thougth बूस्ट अपवाद के साथ सौदा कर सकते हैं, लेकिन बूस्ट –

+2

@Anton :(नहीं कर सकते, खुशी है कि मैं मदद की, तो क्या upvoting और यह उत्तर स्वीकार करने के बारे -) का उपयोग करें इस उत्तर के लिए अपवॉट्स की संख्या के तहत चेकमार्क आइकन (वर्तमान में 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