[PyQt] Custom exception when transferring "owned" object

Phil Thompson phil at riverbankcomputing.com
Fri Mar 29 09:59:44 GMT 2019


On 29 Mar 2019, at 6:32 am, Nyall Dawson <nyall.dawson at gmail.com> wrote:
> 
> Hi list,
> 
> I'm trying to find a way to raise a custom exception if someone
> attempts to call a method which takes ownership with an object which
> is already owned elsewhere (instead of crashing at some future
> stage!).
> 
> Here's what I've got so far:
> 
> .h:
> 
> bool addGeometry( QgsAbstractGeometry *g );
> 
> .sip:
> 
> %MethodCode
>    PyObject *obj = sipConvertFromType( a0, sipType_QgsAbstractGeometry, NULL );
>    if ( !sipIsPyOwned( ( sipSimpleWrapper * )obj ) )
>    {
>      PyErr_SetString( sipException_OwnershipException, "Geometry is
> already owned by another c++ object. Use .clone() to add a deep copy
> of the geometry to this multipoint." );
>      sipIsErr = 1;
>      Py_DECREF( obj );
>    }
>    else
>    {
>      bool res = sipCpp->addGeometry( a0 );
>      if ( res )
>      {
>        PyObject *owner = sipConvertFromType( sipCpp,
> sipType_QgsAbstractGeometry, NULL );
>        sipTransferTo( obj,  owner );
>      }
>      return PyBool_FromLong( res );
>    }
> %End
> 
> It works ok about 50% of the time, the other 50% it crashes. I suspect
> my methodcode isn't correct transferring ownership and the argument
> c++ object is getting deleted when its Python wrapper goes out of
> scope.
> 
> Can anyone see what I'm missing here?

sipConvertFromType() returns a new reference which you aren't dealing with properly.

You don't need the first call to sipConvertFromType(). Use /GetWrapper/ instead.

sipIsPyOwned() is an undocumented internal function and may be removed at any time.

Personally I think trying to add protection in the bindings layer to cover weaknesses in the (current) *implementation* of the C++ API is a mistake (and a never ending task).

Phil


More information about the PyQt mailing list