Opening a vector layer under Python QGis: the worst case !🔗

Posted by Médéric Ribreux 🗓 In blog/ Qgis/

#qgis

Today I have been stuck by something quite strange under Python environnement of QGis. I just wanted to open an Oracle vector layer and add it to the layer registry.

Here is what I tried (you can try it in the QGis Python Console from Extensions menu):

uri = QgsDataSourceURI()
uri.setConnection("","1521", "geobase", "user", "password")
uri.setDataSource("SCHEMA","TABLE",
v = QgsVectorLayer(uri.uri(), "MY_LAYER", "oracle")
QgsMapRegistry.instance().addMapLayer(v, True)

When launching the addMapLayer method, nothing moves on QGis interface and after a bit of digging in the log messages, I found nothing suspicious…

I tried to grab the state of the layer. You can do it with the isValid method which is inherited from the QgsMapLayer class. With all of the layers I tried to open, v.isValid() always returned False.

I tried to use the error() method which returned a QgsError object to try to find why my layer was invalid. But v.error().message() was always empty.

I remembered that I've got a special layer in my Oracle database. It is the only one which is well declared in Oracle metadata table (ALL_SDO_GEOM_METADATA view). When I tried the above lines code, I was able to open the layer in QGis map dialog. This special layer just have a well declared SRID, a well declared extent and stores only one type of geometry (Polygon).

I immediately struggle in QGis Python Console to find how to force a CRS for a QgsVectorLayer. The only way I found was to use the setCrs() method directly from the QgsVectorLayer class:

uri = QgsDataSourceURI()
uri.setConnection("","1521", "geobase", "user", "password")
uri.setDataSource("SCHEMA","TABLE",
v = QgsVectorLayer(uri.uri(), "MY_LAYER", "oracle")
v.setCrs(QgsCoordinateSystem(u"EPSG:27562")

But declaring the CRS is finally not required: if there is no SRID for the layer, QGis just use the CRS of the project (it depends on what you have configured in your QGis parameters). Furthermore, adding a CRS with the above method does not change the isValid() status…

Actually, the real problem was a wkbType one. All of my unopenable layers were declared with a wkbType to WkbUnknown. After re-reading QGis API documentation, the only way I've find so far to force the wkbType of a layer is to use uri.setWkbType() method. There is no other choice.

To open a layer with multiple geometry types, you have to add a little bit of code to the above snippet:

uri = QgsDataSourceURI()
uri.setConnection("","1521", "geobase", "user", "password")
uri.setDataSource("SCHEMA","TABLE",
uri.setWkbType(QGis.WkbPolygon)
v = QgsVectorLayer(uri.uri(), "MY_LAYER", "oracle")
QgsMapRegistry.instance().addMapLayer(v, True)

It took just 3 hours of work and search to find the solution. Why not make it public ?