[PyQt] sip: extend exception support

Mathias.Born at gmx.de Mathias.Born at gmx.de
Sun Aug 26 13:30:32 BST 2012


On 26.08.2012, 16:46:24 Phil Thompson wrote:
> On Wed, 15 Aug 2012 15:54:11 +0200, Mathias.Born at gmx.de wrote:
>> Phil,
>> 
>> sip can already propagate C++ exceptions into Python in cases
>> where Python calls a C++ function which throws an exception.
>> 
>> However, if I extend a C++ class in Python and call a corresponding
>> (Python-)method in C++ via the wrapper, the sip generated
>> wrapper code checks for a Python exception, but doesn't throw an
>> excpetion itself.
>> For example:
>> 
>> ========= <code generated by sip> =======================
>> boost::optional<int> sipVH_ltse_app_0(sip_gilstate_t
> sipGILState,PyObject
>> *sipMethod,const std::string& a0)
>> {
>>     boost::optional<int> sipRes;
>>     PyObject *resObj = sipCallMethod(0,sipMethod,"N",new
>>     std::string(a0),sipType_std_string,NULL);
>> 
>>     if (!resObj ||
>>    
> sipParseResult(0,sipMethod,resObj,"H5",sipType_boost_optional_1800,&sipRes)
>>     < 0)
>>         PyErr_Print();
>> 
>>     Py_XDECREF(resObj);
>>     Py_DECREF(sipMethod);
>> 
>>     SIP_RELEASE_GIL(sipGILState)
>> 
>>     return sipRes;
>> }
>> =========================================================
>> 
>> Here, "PyErr_Print" is called if the Python implementation of
>> the method raises an exception. This is fine for Qt which
>> cannot deal with exceptions, but in general I would find it
>> much more helpful if the wrapper code generated by sip
>> threw a C++ exception itself to signal the problem to the
>> caller.
>> 
>> Just define a class, e.g. "SIPPyException" (derived from
>> std::exception), which becomes part of the API and is always used
>> in such cases.
>> In order not to break existing code, it would only be used in
>> classes or methods which are annotated appropriately.
>> (So an additional annotation is necessary to activate this behavior.)
>> 
>> I believe an extension like this would make sip a lot more useful
>> for embedding Python into a C++ program.
>> 
>> Best Regards,
>> Mathias Born

> Try current hg or tonight's snapshot. See the all_throw_cpp_exception
> %Module argument and the /ThrowsCppException/ and /NoThrowsCppException/
> function annotations.

> Not heavily tested.

That's great!
I tried "sip-4.13.4-snapshot-5f97352e818f.zip".

When buidling sip, my MSVC2010 complains:

sip.h(347) : error C2016: C requires that a struct or union has at least one member

Possible fix: just change

struct SIPPyException {};

to

#ifdef __cplusplus
struct SIPPyException {};
#endif

That should be ok because it's for an exception, a C++ only feature.


The generated code, for example:

========= <code generated by sip> =======================
std::string sipVH_ltse_app_1(sip_gilstate_t sipGILState,PyObject *sipMethod,const std::string& a0)
{
    std::string sipRes;
    PyObject *resObj = sipCallMethod(0,sipMethod,"N",new std::string(a0),sipType_std_string,NULL);

    if (!resObj || sipParseResult(0,sipMethod,resObj,"H5",sipType_std_string,&sipRes) < 0)
        throw SIPPyException();

    Py_XDECREF(resObj);
    Py_DECREF(sipMethod);

    SIP_RELEASE_GIL(sipGILState)

    return sipRes;
}
=========================================================

will leak memory, though. All the

    Py_XDECREF(resObj);
    Py_DECREF(sipMethod);
    SIP_RELEASE_GIL(sipGILState)

won't be executed in case of an exception.


In addition, I get a lot of compilation errors when I try to build PyQt v4.9.4 with this new sip,
for example:

.\sipQtGuiQFontDialog.cpp(3298) : error C2664: 'void QFontDialog::open(QObject *,const char *)' : cannot convert parameter 1 from 'QObject **' to 'QObject *'
        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

That's a show stopper, as my stuff can't do without PyQT ...

Best Regards,
Mathias Born



More information about the PyQt mailing list