Below is a list of fixes to common PyQGIS migration issues I collated whilst migrating a QGIS 2.18 plugin to QGIS 3.2 (and then to 3.4). I documented each error message and fix to make things easier if I came across the same issue again, and subsequently figured it may be of user to others who were migrating their plugins too.
- Error messages and fixes
- See also (other hints/tips for plugin migration and associated troubleshooting)
- Contributions
- License
Details of error messages are documented as sub-headings, with fixes and examples for each listed underneath. Where possible I've included links back to relevant documentation too.
Error messages are listed alphabetically, and as such are organised by error type (AttributeError
, NameError
, TypeError
).
To fix: replace Qgis.<Old Type>
with QgsWkbTypes.<New Type>
e.g.
QGis.Line
# becomes
QgsWkbTypes.LineGeometry
Qgis.WKBPolygon
# becomes
QgsWkbTypes.Polygon
Qgis.WKBPoint
# becomes
QgsWkbTypes.Point
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsWkbTypes
and QGIS breaking changes 'General changes' section
To fix: replace .fromMultiPolyline([qgs_point_list])
with .fromMultiPolylineXY([qgs_pointXY_list])
e.g.
QgsGeometry.fromMultiPolyline(qgs_point_list)
# becomes
QgsGeometry.fromMultiPolylineXY(qgs_point_xy_list)
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsGeometry.fromMultiPolylineXY()
and QGIS breaking changes for QgsGeometry
To fix: replace QgsMessageBar.<MessageLevel>
with Qgis.<MessageLevel>
e.g.
QgsMessageBar.INFO
# becomes
Qgis.Info
QgsMessageBar.WARNING
# becomes
Qgis.Warning
QgsMessageBar.CRITICAL
# becomes
Qgis.Critical
QgsMessageBar.SUCCESS
# becomes
Qgis.Success
See also: QGIS API doc for Qgis.MessageLevel
and QGIS breaking changes for QgsMessageLevel
To fix: replace QgsSymbolLayerRegistry.instance()
with QgsApplication.symbolLayerRegistry()
e.g.
QgsSymbolLayerRegistry.instance()
# becomes
QgsApplication.symbolLayerRegistry()
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsApplication.symbolLayerRegistry()
and QGIS breaking changes for QgsSymbolLayerRegistry
To fix: reference the layer (by id
) within the layerTreeRoot
, and set visibility there.
e.g.
iface.legendInterface().setLayerVisible(layer, False)
# becomes
QgsProject.instance().layerTreeRoot().findLayer(layer.id()).setItemVisibilityChecked(False)
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsLayerTreeNode.setItemVisibilityChecked()
and QGIS breaking changes 'Removed Classes' section
and this GIS Stack Exchange answer
To fix: replace .legendInterface()
with .layerTreeView()
e.g.
iface.legendInterface().selectedLayers()
# becomes
iface.layerTreeView().selectedLayers()
See also: QGIS Python API (PyQGIS) doc for qgis.gui.QgsLayerTreeView.selectedLayers()
and QGIS breaking changes for QgsGeometry
To fix: replace .fromPoint()
with .fromPointXY()
e.g.
QgsGeometry.fromPoint(qgs_point)
# becomes
QgsGeometry.fromPointXY(qgs_point_xy)
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsGeometry.fromPointXY()
and QGIS breaking changes for QgsGeometry
To fix: replace .exportToWkt()
with .asWkt()
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsGeometry.asWkt()
and QGIS breaking changes for QgsGeometry
To fix: refer to this GIS Stack Exchange answer
and QGIS breaking changes for QgsPalLayerSettings
To fix: replace .setDisplayField(html)
with .setMapTipTemplate(html)
e.g.
layer.setDisplayField(html)
# becomes
layer.setMapTipTemplate(html)
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsVectorLayer.setMapTipTemplate()
and QGIS breaking changes for QgsVectorLayer
To fix: replace .setLayerTransparancy(percentage)
with .setOpacity(percentage / 100)
e.g.
layer.setLayerTransparency(60)
# becomes
layer.setOpacity(0.6)
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsVectorLayer.setOpacity()
and QGIS breaking changes for QgsVectorLayer
To fix: replace .rendererV2().symbols()
with .renderer().symbol()
and access the symbol directly
e.g.
symbols = layer.rendererV2().symbols()
symbol = symbols[0]
# becomes
symbol = layer.renderer().symbol()
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsSingleSymbolRenderer.symbol()
and QGIS Python API (PyQGIS) doc for qgis.core.QgsVectorLayer.setRenderer()
and QGIS breaking changes 'Renamed Methods' section
To fix: replace .setRendererV2(renderer)
with .setRenderer(renderer)
e.g.
layer.setRendererV2(renderer)
# becomes
layer.setRenderer(renderer)
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsVectorLayer.setRenderer()
To fix: replace QGis.xxx
with Qgis.xxx
(note change in case from QG
to Qg
)
e.g.
from qgis.core import QGis
QGis.xxx
# becomes
from qgis.core import Qgis
Qgis.xxx
See also: QGIS API doc for Qgis
and QGIS breaking changes for Qgis
overload 1: too many arguments
overload 2: not enough arguments
overload 3: not enough arguments
overload 4: not enough arguments
overload 5: argument 1 has unexpected type 'QgsCoordinateReferenceSystem'
To fix: add QgsProject.instance()
to QgsCoordinateTransform()
call
e.g.
xform = QgsCoordinateTransform(src_crs, dest_crs)
# becomes
xform = QgsCoordinateTransform(src_crs, dest_crs, QgsProject.instance())
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsCoordinateTransform
and QGIS breaking changes for QgsCoordinateTransform
To fix: replace thePromptToSaveFlag
with promptToSaveFlag
e.g.
iface.newProject(thePromptToSaveFlag=False)
# becomes
iface.newProject(promptToSaveFlag=False)
See also: QGIS Python API (PyQGIS) doc for qgis.gui.QgisInterface.newProject()
overload 1: argument 1 has unexpected type 'QFileInfo'
overload 2: too many arguments
To fix: remove QFileInfo
and just pass string to QgsProject.read()
e.g.
project.read(QFileInfo(project_file))
# becomes
project.read(project_file)
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsProject.read()
and QGIS breaking changes for QgsProject
overload 1: too many arguments
overload 2: argument 1 has unexpected type 'QgsPoint'
overload 3: argument 1 has unexpected type 'QgsPoint'
overload 4: argument 1 has unexpected type 'QgsPoint'
overload 5: argument 1 has unexpected type 'QgsPoint'
To fix: replace instances of QgsPoint
with QgsPointXY
e.g.
QgsRectangle(QgsPoint(x_min, y_min), QgsPoint(x_max, y_max)))
# becomes
QgsRectangle(QgsPointXY(x_min, y_min), QgsPointXY(x_max, y_max)))
See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsRectangle
and QGIS breaking changes 'Renamed Classes' section
To fix: replace instances of QgsPoint
with QgsPointXY
e.g.
QgsPoint(..., ...)
# becomes
QgsPointXY(..., ...)
See also: QGIS Python API (PyQGIS) doc for qgis.gui.QgsRubberBand.addPoint()
and QGIS breaking changes 'Renamed Classes' section
If the message you are getting when trying to migrate your plugin is not on this page, you can refer to:
- The QGIS API 'Backwards Incompatible Changes' (a.k.a. API Break) page
- The QGIS 'Plugin migration to QGIS 3' page
- GIS for Thought's useful walk-through on 'Updating A Plugin From QGIS 2 to QGIS 3'
- Stack Exchange's essential 'Geographical Information Systems' Q&A site
I also found the First Aid QGIS plugin quite useful throughout the process, see:
First Aid's GitHub page and their blog post introducing it for more details.
Contributions to improve this document are welcome, whether in the form or corrections, changes, additional entries, or anything else you see fit. Please submit a pull request.
common-qgis-2-to-3-plugin-fixes is licensed under a Creative Commons Attribution 4.0 International License.