Skip to content

Contains fixes to common PyQGIS 2 to 3 plugin migration issues, collated whilst migrating a QGIS 2.18 plugin to QGIS 3.2 (and then to 3.4). Also provides some recommendations on the migration process.

License

Notifications You must be signed in to change notification settings

JonathanWillitts/common-qgis-2-to-3-plugin-fixes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 

Repository files navigation

Fixes to common problems when migrating QGIS plugins from v2.18 to v3.x

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.

Table of contents

Error messages and fixes

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).


Attribute errors:

AttributeError: type object 'Qgis' has no attribute 'Line'

AttributeError: type object 'Qgis' has no attribute 'WKBPoint'

AttributeError: type object 'Qgis' has no attribute 'WKBPolygon'

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


AttributeError: type object 'QgsGeometry' has no attribute 'fromMultiPolyline'

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


AttributeError: type object 'QgsMessageBar' has no attribute 'INFO'

AttributeError: type object 'QgsMessageBar' has no attribute 'WARNING'

AttributeError: type object 'QgsMessageBar' has no attribute 'CRITICAL'

AttributeError: type object 'QgsMessageBar' has no attribute 'SUCCESS'

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


AttributeError: type object 'QgsSymbolLayerRegistry' has no attribute 'instance'

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


AttributeError: 'QgisInterface' object has no attribute 'legendInterface'

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


AttributeError: 'QgsLayerTree' object has no attribute 'selectedLayers'

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


AttributeError: type object 'QgsGeometry' has no attribute 'fromPoint'

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


AttributeError: 'QgsGeometry' object has no attribute 'exportToWkt'

To fix: replace .exportToWkt() with .asWkt()

See also: QGIS Python API (PyQGIS) doc for qgis.core.QgsGeometry.asWkt()

and QGIS breaking changes for QgsGeometry


AttributeError: 'QgsPalLayerSettings' object has no attribute 'readFromLayer'

To fix: refer to this GIS Stack Exchange answer

and QGIS breaking changes for QgsPalLayerSettings


AttributeError: 'QgsVectorLayer' object has no attribute 'setDisplayField'

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


AttributeError: 'QgsVectorLayer' object has no attribute 'setLayerTransparency'

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


AttributeError: 'QgsVectorLayer' object has no attribute 'rendererV2'

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


AttributeError: 'QgsVectorLayer' object has no attribute 'setRendererV2'

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()


Name errors:

NameError: name 'QGis' is not defined

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


Type errors:

TypeError: QgsCoordinateTransform(): arguments did not match any overloaded call:

  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


TypeError: QgisInterface.newProject(): 'thePromptToSaveFlag' is not a valid keyword argument

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()


TypeError: QgsProject.read(): arguments did not match any overloaded call:

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


TypeError: QgsRectangle(): arguments did not match any overloaded call:

  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


TypeError: QgsRubberBand.addPoint(): argument 1 has unexpected type 'QgsPoint'

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

See also:

If the message you are getting when trying to migrate your plugin is not on this page, you can refer to:

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:

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.

License:

Creative Commons License
common-qgis-2-to-3-plugin-fixes is licensed under a Creative Commons Attribution 4.0 International License.

About

Contains fixes to common PyQGIS 2 to 3 plugin migration issues, collated whilst migrating a QGIS 2.18 plugin to QGIS 3.2 (and then to 3.4). Also provides some recommendations on the migration process.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published