<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">2015-04-21 18:09 GMT+02:00 Phil Thompson <span dir="ltr"><<a href="mailto:phil@riverbankcomputing.com" target="_blank">phil@riverbankcomputing.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div>On 21/04/2015 4:48 pm, Alessandro Pasotti wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
2015-04-21 17:20 GMT+02:00 Phil Thompson <<a href="mailto:phil@riverbankcomputing.com" target="_blank">phil@riverbankcomputing.com</a>>:<br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
On 21/04/2015 4:12 pm, Alessandro Pasotti wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Hi,<br>
<br>
I noticed that if I create a property() alias on a virtual method, the<br>
alias will always call the base class method instead of the concrete<br>
instance method.<br>
<br>
Is this the expected behaviour?<br>
Is it documented somewhere?<br>
<br>
Here using PyQt4 4.8.5 and python 2.7, SIP should be 4.15.5<br>
<br>
</blockquote>
<br>
A simple, complete example that demonstrates the problem would help.<br>
<br>
</blockquote>
<br>
<br>
Hi Phil,<br>
<br>
I know an example would help but a simple one is not possible: I'm working<br>
on a QT app embedded in a python plugin embedded in a 10K sloc C++ app.<br>
<br>
But, I try.<br>
<br>
instance "d" is a QgsPostgresProvider : public QgsVectorDataProvider<br>
<a href="https://github.com/elpaso/QGIS/blob/master/src/providers/postgres/qgspostgresprovider.h" target="_blank">https://github.com/elpaso/QGIS/blob/master/src/providers/postgres/qgspostgresprovider.h</a><br>
which is a subclass of QgsVectorDataProvider<br>
<a href="https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.h" target="_blank">https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.h</a><br>
API Docs: <a href="http://qgis.org/api/qgsvectordataprovider_8h_source.html" target="_blank">http://qgis.org/api/qgsvectordataprovider_8h_source.html</a><br>
<br>
<br>
In [70]: d = l.dataProvider()<br>
<br>
<br>
In [71]: d<br>
<br>
Out[71]: <qgis._core.QgsVectorDataProvider at 0x7f132375fb00><br>
<br>
<br>
In [72]: d.capabilities?<br>
<br>
Docstring: QgsVectorDataProvider.capabilities() -> int<br>
<br>
Type: builtin_function_or_method<br>
<br>
<br>
In [73]: d.capabilities()<br>
<br>
Out[73]: 115615<br>
<br>
<br>
In [74]: d.__class__.capabilities2 = property(d.__class__.capabilities)<br>
<br>
<br>
In [75]: d.capabilities2?<br>
<br>
Type: property<br>
<br>
String form: <property object at 0x7f1322ac6470><br>
<br>
Docstring: QgsVectorDataProvider.capabilities() -> int<br>
<br>
<br>
<br>
In [76]: d.capabilities2<br>
<br>
Out[76]: 0<br>
<br>
<br>
The problem is that instruction 73 calls<br>
QgsPostgresProvider::capabilities() while instruction 76 calls<br>
QgsVectorDataProvider::capabilities()<br>
<a href="https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.cpp#L107" target="_blank">https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.cpp#L107</a><br>
and returns 0 (NO CAPABILITIES).<br>
<br>
Am I doing something wrong?<br>
</blockquote>
<br></div></div>
I have no idea. The firts person to ask is whoever did the Qgs bindings.<span><font color="#888888"><br>
<br>
Phil<br></font></span></blockquote><div><br><br></div><div>I asked to the bindings author,<br><br></div><div>for the records, when the python object represents a pointer to a base class, assigning a property on __class__ will always call the base class method and not the instance's overridden method.<br><br></div><div>In my case, <br><br>
<p style="margin:0px;text-indent:0px">l.p_dataProvider</p>
<p style="margin:0px;text-indent:0px"><span style="color:rgb(139,0,0)">Out[</span><span style="font-weight:600;color:rgb(139,0,0)">6</span><span style="color:rgb(139,0,0)">]:</span> <qgis._core.QgsVectorDataProvider at 0x7f22d15cac30></p><p style="margin:0px;text-indent:0px"></p><p style="margin:0px;text-indent:0px">but "l" is an instance of QgsPostgresProvider.<br></p><br></div><div><br></div><div>This is the answer from Martin Dobias who helped me to solve the problem:<br></div><div><br><div>I think your problem is not specific to PyQGIS. I tried this code:</div><div><br></div><div><div>class C(object):</div><div> def f(self):</div><div> return 0</div><div><br></div><div>class D(C):</div><div> def f(self):</div><div> return 42</div><div><br></div><div>C.g = property(C.f)</div><div><br></div><div>d = D()</div><div>print d.f()</div><div>print d.g</div></div><div><br></div><div>This
is basically equivalent of your code, just with plain Python. It will
print 42 and 0. The reason is that the property is set to always call
base class method C.f() - you would need to use object instance to make
python do the call as one would (e.g. self.f()). With this modification
you can get both print statements return 42:</div><div><br></div><div>C.g = property( lambda self: self.f() )<br></div><div><br></div><div>In this way the method f() is resolved dynamically, because it is called with instance, not class.</div><br></div></div><br>-- <br><div>Alessandro Pasotti<br>w3: <a href="http://www.itopen.it" target="_blank">www.itopen.it</a></div>
</div></div>