[PyQt] Custom exception when transferring "owned" object

Nyall Dawson nyall.dawson at gmail.com
Mon Nov 4 08:51:04 GMT 2019


On Fri, 29 Mar 2019 at 19:59, Phil Thompson <phil at riverbankcomputing.com> wrote:
>
> 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.
>

(Reposting with the full context -- apologies for resurrecting such an
old thread!)

I noticed that there's now sipIsOwnedByPython in the public API. My
updated code looks like this:

    if ( !sipIsOwnedByPython( ( sipSimpleWrapper * )a0Wrapper ) )
    {
      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;
    }
    else
    {
      bool res = sipCpp->addGeometry( a0 );
      if ( res )
      {
        PyObject *owner = sipConvertFromType( sipCpp,
sipType_QgsAbstractGeometry, NULL );
        sipTransferTo( a0Wrapper,  owner );
        Py_DECREF( owner );
      }
      return PyBool_FromLong( res );

Does this approach look reasonable to you? Is it correctly using the
new sipIsOwnedByPython call?

Nyall


More information about the PyQt mailing list