[PyQt] Conversion to wrong SubClass

Phil Thompson phil at riverbankcomputing.com
Fri Jan 18 11:38:11 GMT 2019


On 18 Jan 2019, at 11:22 am, Matthias Kuhn <matthias at opengis.ch> wrote:
> 
> Hi
> 
> In QGIS we are facing an issue, where in some cases a wrong subclass
> mapping is used in the python bindings.
> 
> The code looks like this:
> 
>  * There is a parent class QgsAbstractGeometry
> 
>  * There are various child classes, among them QgsPoint and QgsMultiPolygon
> 
> 
> After heavy operation it can happen, that the python bindings indicate,
> that an object is of type QgsPoint, whereas the underlying object is
> actually a QgsMultiPolygon (verified that when an overwritten method is
> called on the object, the one from QgsMultiPolygon is executed).
> 
> It looks like objects which are created subsequently have exactly the
> same memory address (see below) and I suspect sip caches type
> information with memory addresses somewhere (based on "When SIP needs to
> wrap a C++ class instance it first checks to make sure it hasn’t already
> done so. " /
> http://pyqt.sourceforge.net/Docs/sip4/directives.html?highlight=subclass#directive-%ConvertToSubClassCode)
> 
> Does sip invalidate this cache information somehow (when the python
> wrapper is garbage collected or something else)? Is it possible to
> proactively trigger cache invalidation from a destructor? Are there
> other ideas what could go wrong and how to deal with that?
> 
> 
> ** Insights from debugging:
> 
> Unconditional debug print statements have been added to
> 
>  * QgsAbstractGeometry::QgsAbstractGeometry() (Constructor)
>  * QgsAbstractGeometry::~QgsAbstractGeometry() (Destructor)
>  * %SipConvertToSubClassCode
> 
> grepping the log for the memory address of an affected geometry reveals,
> that the constructor is called twice with the object on the same
> address, but the SipConvertToSubClassCode is only called once
> 
> ----------
> 
> Constructor: 0x8b1cbd0
> SipConvertToSubClassCode - Type QgsPoint: 0x8b1cbd0
> Destructor: 0x8b1cbd0
> Constructor: 0x8b1cbd0
> Destructor: 0x8b1cbd0
> 
> ---------
> 
> Any hints would be much appreciated

The cache entry will be invalidated when sip knows the C++ instance has been destroyed. This is easy enough when the instance has been created from Python and has virtual dtors - but you can have C++ APIs which make this all but impossible.. You could look at sip.setdeleted() and similar.

Phil


More information about the PyQt mailing list