2012-05-21 14 views
6

में कस्टम सी ++ अपवादों को संभालना मुझे साइथन से कॉल करते समय कस्टम सी ++ अपवादों को संभालने में कुछ परेशानी है। मेरी स्थिति निम्न है: मेरे पास एक लाइब्रेरी है जो सभी अपवादों के लिए CustomLibraryException का उपयोग करती है। जो मैं चाहता हूं वह मूल रूप से त्रुटि संदेश प्राप्त करता है और इसके साथ एक पायथन त्रुटि उठाता है।साइथन

user guide में कुछ संकेत हैं लेकिन यह थोड़ा सा विशिष्ट है। पहली संभावना करना है: यह एक ValueError को CustomLibraryException धर्मान्तरित

cdef पूर्णांक बार() + ValueError

छोड़कर, लेकिन त्रुटि संदेश खो देता है।

अन्य संभावना स्पष्ट रूप से उपयोग कर रहा

cdef int raise_py_error() 
cdef int something_dangerous() except +raise_py_error 

मैं वास्तव में इस समाधान understant नहीं है त्रुटि कन्वर्ट करने के लिए है। मुझे समझ में आया कि raise_py_error को एक सी ++ फ़ंक्शन होना चाहिए जो किसी भी तरह से त्रुटि को संभालता है। मुझे यकीन नहीं है कि इसे कैसे संभालना है। फ़ंक्शन को कोई तर्क नहीं मिलता है और C++ में catch ब्लॉक के अंदर बुलाया जाता है।

यदि किसी के पास साइथन में सी ++ अपवाद को संभालने का एक कामकाजी उदाहरण है, तो यह बहुत मददगार होगा।

उत्तर

2

यदि CustomLibraryExceptionstd::runtime_error से प्राप्त होता है (एक अच्छी तरह से व्यवहार किए गए सी ++ अपवाद के रूप में), तो आप जो व्यवहार देख रहे हैं वह साइथन में एक बग है।

यदि ऐसा नहीं होता है, तो ऐसा करने के लिए सबसे आसान काम सी ++ समारोह आप एक सी में कॉल कर रहे हैं ++ सहायक समारोह है कि अपवाद तब्दील रैप करने के लिए है:

double foo(char const *, Bla const &); // this is the one we're wrapping 

double foo_that_throws_runtime_error(char const *str, Bla const &blaref) 
{ 
    try { 
     return foo(str, blaref); 
    } catch (CustomLibraryException const &e) { 
     throw std::runtime_error(e.get_the_message()); 
    } 
} 

यह एक RuntimeError कारण होगा होने के लिए पायथन पक्ष पर उठाया। वैकल्पिक रूप से, throwstd::invalid_argument से raiseValueError, आदि (उस पृष्ठ में तालिका को देखें जो आपने लिंक किया था)।

+0

अपवाद को '' std :: runtime'' से प्राप्त नहीं किया गया है जैसा कि आप उम्मीद करते थे। मदद के लिए धन्यवाद :) हालांकि यह इतना बेहतर नहीं बनाता है, हालांकि। त्रुटि को बढ़ाने वाले फ़ंक्शन सदस्य-कार्य हैं और मैं उनका कोड बदलना नहीं चाहता हूं। यह मेरे [जीको रैपर] (http://peekaboo-vision.blogspot.de/2012/05/graphcuts-for-python-pygco.html) के बारे में है और लाइसेंस मुझे पुनर्वितरण की अनुमति नहीं देता है: -/ –

+1

@ एंड्रियासमुएलर: सदस्य कार्यों को फ्रीस्टैंडिंग कार्यों में आसानी से लपेटा जा सकता है; बस उस ऑब्जेक्ट को पास करें जिसे उन्हें पहले तर्क के रूप में संचालित करना चाहिए: 'शून्य रैपर (ओब्जे और ओ, इंट हैम) {वापसी o.wrapped (हैम); } ' –

+1

हाँ मुझे पता है, मैं अभी तक इसे करने के लिए आलसी था;) बीटीडब्ल्यू, क्या आप जानते थे कि आप एसओ पर शीर्ष 100 वें पोस्टर हैं? –

3

डिफ़ॉल्ट सी ++ Cython में अपवाद संचालक वास्तव में उदाहरण देकर स्पष्ट करना चाहिए पूरा करने के लिए कैसे तुम क्या करने कोशिश कर रहे हैं:

static void __Pyx_CppExn2PyErr() { 
    // Catch a handful of different errors here and turn them into the 
    // equivalent Python errors. 
    try { 
    if (PyErr_Occurred()) 
     ; // let the latest Python exn pass through and ignore the current one 
    else 
     throw; 
    } catch (const std::bad_alloc& exn) { 
    PyErr_SetString(PyExc_MemoryError, exn.what()); 
    } catch (const std::bad_cast& exn) { 
    PyErr_SetString(PyExc_TypeError, exn.what()); 
    } catch (const std::domain_error& exn) { 
    PyErr_SetString(PyExc_ValueError, exn.what()); 
    } catch (const std::invalid_argument& exn) { 
    PyErr_SetString(PyExc_ValueError, exn.what()); 
    } catch (const std::ios_base::failure& exn) { 
    // Unfortunately, in standard C++ we have no way of distinguishing EOF 
    // from other errors here; be careful with the exception mask 
    PyErr_SetString(PyExc_IOError, exn.what()); 
    } catch (const std::out_of_range& exn) { 
    // Change out_of_range to IndexError 
    PyErr_SetString(PyExc_IndexError, exn.what()); 
    } catch (const std::overflow_error& exn) { 
    PyErr_SetString(PyExc_OverflowError, exn.what()); 
    } catch (const std::range_error& exn) { 
    PyErr_SetString(PyExc_ArithmeticError, exn.what()); 
    } catch (const std::underflow_error& exn) { 
    PyErr_SetString(PyExc_ArithmeticError, exn.what()); 
    } catch (const std::exception& exn) { 
    PyErr_SetString(PyExc_RuntimeError, exn.what()); 
    } 
    catch (...) 
    { 
    PyErr_SetString(PyExc_RuntimeError, "Unknown exception"); 
    } 
} 

तो आप या तो एक शामिल ज फ़ाइल में #define __Pyx_CppExn2PyErr your_custom_exn_handler सामान्य व्यवहार को ओवरराइड करने के लिए कर सकते हैं, या उपयोग एक ऑफ-ऑफ कस्टम हैंडलर

cdef extern from "...": 
    void your_exn_throwing_fcn() except +your_custom_exn_handler 
7

दस्तावेज़ पृष्ठ में शब्द से सहमत कुछ वांछित होने के लिए छोड़ देता है। जबकि "साइथन सी ++ अपवाद फेंक नहीं सकता है", यहां एक raise_py_error है जो हम चाहते हैं।

पहले, cython में कस्टम अपवाद वर्ग को परिभाषित करने और फिर अपवाद संचालक (डॉक्स सुपर स्पष्ट इस में लिखा होना चाहिए नहीं कर रहे हैं बारे में "सार्वजनिक" कीवर्ड

from cpython.ref cimport PyObject 

class JMapError(RuntimeError): 
    pass 

cdef public PyObject* jmaperror = <PyObject*>JMapError 

का उपयोग करके उसमें एक हैंडल करना सी ++ और आयातित):

#include "Python.h" 
#include "jmap/cy_utils.H" 
#include "jmap/errors.H" 
#include <exception> 
#include <string> 

using namespace std; 

extern PyObject *jmaperror; 

void raise_py_error() 
{ 
    try { 
    throw; 
    } catch (JMapError& e) { 
    string msg = ::to_string(e.code()) +" "+ e.what(); 
    PyErr_SetString(jmaperror, msg.c_str()); 
    } catch (const std::exception& e) { 
    PyErr_SetString(PyExc_RuntimeError, e.what()); 
    } 
} 

अंत में, एक निर्वासन ब्लॉक के साथ cython में हैंडलर लाने के लिए, और इसका इस्तेमाल करते हैं:

cdef extern from "jmap/cy_utils.H": 
    cdef void raise_py_error() 

void _connect "connect"() except +raise_py_error 

हो गया। अब मैं नया अपवाद देखता हूं, जिसका उद्देश्य त्रुटि कोड के साथ बनाया गया है:

JMapError: 520 timed connect failed: Connection refused 
+0

इंटरस्टेस्टिंग जवाब। क्या आपको पता है कि साइथन संकलन करना संभव है कि सी ++ फ़ाइल सीधे या क्या मुझे मैन्युअल रूप से lib बनाने की आवश्यकता है तो इसके खिलाफ लिंक करें? मुझे इस पर कोई दस्तावेज नहीं मिला ... –

+0

मुझे पता चला। कस्टम अपवाद से संदेश को संरक्षित करते समय त्रुटि प्रबंधन का एक न्यूनतम उदाहरण यहां दिया गया है: https://github.com/SintefRaufossManufacturing/python-hcn/blob/master/hcn/cy_handler.cpp –

+1

क्या आप कृपया बता सकते हैं कि वास्तव में (कौन सा फ़ाइल एक्सटेंशन, कौन सा आवश्यक आयात) आप साइथन कक्षा घोषित करने और इसे 'पायओब्जेक्ट' पर डालने के लिए उपयोग करते हैं? (पहला कोडब्लॉक) PyObject डिफ़ॉल्ट रूप से परिभाषित नहीं किया गया है और इसे "Python.h" से आयात कर रहा है। 'साइथन शिकायत करते हैं कि पायथन वस्तुओं को आदिम प्रकारों में नहीं डाला जा सकता है ... – Silmathoron

संबंधित मुद्दे