Bug report #8258
QgsVectorDataProvider.uniqueValues returns not None but QPyNullVariant
Status: | Closed | ||
---|---|---|---|
Priority: | Normal | ||
Assignee: | - | ||
Category: | Python plugins | ||
Affected QGIS version: | master | Regression?: | No |
Operating System: | Easy fix?: | No | |
Pull Request or Patch supplied: | No | Resolution: | fixed |
Crashes QGIS or corrupts data: | No | Copied to github as #: | 17062 |
Description
Open polygons.shp (testdata on #8219). The second field of the attribute table is a string type and includes NULL values. Then, in the python console:
>>> layer = iface.activeLayer() >>> provider = layer.dataProvider() >>> provider.uniqueValues(1) [<PyQt4.QtCore.QPyNullVariant object at 0x10CABFB8>, u'pentagon', u'quadrangle', u'triangle'] >>> f = QgsFeature() >>> provider.getFeatures( QgsFeatureRequest().setFilterFid( 0 ) ).nextFeature( f ) True >>> f.attributes() [u'f', None, 10] >>> provider.uniqueValues(1)[0] == None False
QGIS version:
1.9.0-Master Master, 630427f
History
#1
Updated by Matthias Kuhn over 9 years ago
Will now be:
>>> layer = iface.activeLayer() >>> provider = layer.dataProvider() >>> provider.uniqueValues(1) [NULL, u'pentagon', u'quadrangle', u'triangle'] >>> f = provider.getFeatures( QgsFeatureRequest().setFilterFid( 0 ) ).next() True >>> f.attributes() [u'f', NULL, 10] >>> provider.uniqueValues(1)[0] == None False >>> provider.uniqueValues(1)[0] is None False >>> provider.uniqueValues(1)[0].isNull() True >>> if not provider.uniqueValues(1)[0]: >>> 'it is NOT' 'it is NOT'
Now everything returning a NULL attribute returns a QPyNullVariant (by design) but will be represented as "NULL" on the console
#2
Updated by Minoru Akagi over 9 years ago
The evaluation of (None == None) is True. But the evaluation of the following conditional expression is False.
>>> provider.uniqueValues(1)[0] == f.attributes()[1] False
It makes sense to me that (QPyNullVariant == QPyNullVariant) is evaluated as True.
#3
Updated by Nathan Woodrow over 9 years ago
You would think so but it's not the case.
We should be able to fix that by overloading the eq method. Hold tight.
#4
Updated by Nathan Woodrow over 9 years ago
We can just do this:
from types import MethodType
from PyQt4.QtCore import QPyNullVariant
def __nonzero__(self):
return False
def __eq__(self, other):
return True
QPyNullVariant.__nonzero__ = MethodType(__nonzero__, None, QPyNullVariant)
QPyNullVariant.__eq__ = MethodType(__eq__, None, QPyNullVariant)
which will work like so:
>>> n = QPyNullVariant('QString')
>>> n2 = QPyNullVariant('QString')
>>> n == n2
True
Just be aware this doesn't compare the internal type of QPyNullVariant so maybe we should just compare that rather then returning True. In practice should this work?
>>> n = QPyNullVariant('QString')
>>> n2 = QPyNullVariant('int')
>>> n == n2
True
or do we not really care in this case? Because we are just trying to do: NULL == NULL
#5
Updated by Nathan Woodrow over 9 years ago
- Status changed from Open to Closed
- Resolution set to fixed
This is as fixed as we are going to be able to do.
>>> n = QPyNullVariant('QString')
>>> n2 = QPyNullVariant('QString')
>>> n == n2
True
>>> n = QPyNullVariant('QString')
>>> n2 = QPyNullVariant('int')
>>> n == n2
True
>>> n = QPyNullVariant('QString')
>>> n == None
True
>>> n = QPyNullVariant('QString')
>>> n is None
False
>>> n = 100
>>> n2 = QPyNullVariant('int')
>>> n == n2
False
There is also a new shortcut NULL
type in qgis.core
which is a QPyNullVariant
. So you can just do:
>>> from qgis.core import NULL
>>> provider.uniqueValues(1)[0] == NULL
True
#6
Updated by Minoru Akagi over 9 years ago
- Status changed from Closed to Reopened
Great works! Thanks, Matthias and Nathan!!
Now the evaluation of the following conditional expression is True.
>>> provider.uniqueValues(1)[0] == f.attributes()[1] True
However, the following is also True!
>>> provider.uniqueValues(1)[0] != f.attributes()[1] True
Probably, we should override ne method too as below:
def __ne__(self, other): return not self.__eq__(other) QPyNullVariant.__ne__ = MethodType(__ne__, None, QPyNullVariant)
#7
Updated by Nathan Woodrow over 9 years ago
Good catch!
Will fix that now.
#8
Updated by Minoru Akagi over 9 years ago
- % Done changed from 0 to 100
- Status changed from Reopened to Closed