# Updating A Plugin From QGIS 2 to QGIS 3

I have two plugins in the QGIS plugin repository, and with the release of QGIS 3 looming it was time to upgrade them for QGIS 3.

There is a short guide by the QGIS dev team that is a good starting point at:
https://github.com/qgis/QGIS/wiki/Plugin-migration-to-QGIS-3

But I had not done any development on these plugins for a while so a more step by step guide was useful, so hopefully, write the guide for the first plugin and follow it step by step for the second.

I am working on Windows, with OSGeo4W.

Before we start we will need to insure a couple of extras are installed through the OSGeo4w Installer:
Desktop:
qgis-dev
Libs:
python-future

Assuming GitHUB is the repo.
In git shell:

git clone https://github.com/HeikkiVesanto/QGIS_Multi_Ring_Buffer.git

There is a conversion script for QGIS plugins provided by the QGIS devs in the main repo.

UPDATE:
The qgis2to3 packages can be found on pip now:

https://github.com/opengisch/qgis2to3/

We can download just the scripts folder using the following link:

Extract that into a location of your choice.

Then we can run the 2to3 script from the OSGeo4W console (cd to the folder you extracted the script to):

python 2to3 C:\path_to_plugin\QGIS_Multi_Ring_Buffer

This will print out changes that need to be made to convert from QGIS2 to QGIS3.

My first run resulted in many lines of:

RefactoringTool: Line 31: could not convert: from PyQt4.QtCore import *
RefactoringTool: Cannot handle star imports.

So my plugins line of:

from PyQt4.QtCore import *

Was impossible to convert with the tool, since I was not 100% sure what I needed from the QtCore library (I was young when I wrote the plugin). I commented out the line for the plugin in QGIS 2.8, booted up QGIS 2.8 and tried running the plugin.

So python errors:
NameError: global name ‘QVariant’ is not defined
NameError: global name ‘Qt’ is not defined
Later. I ended up expanding my other import from QtCore to:

from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication, QVariant, Qt

Running the 2to3 script again looked ok, with a number of changes required. These changes can be applied with –w flag:

python 2to3 C:\path_to_plugin\QGIS_Multi_Ring_Buffer -w

For the next step I booted up my favourite IDE PyCharm. I created a bat file that launched PyCharm with the QGIS dev environmental variables. So copying the “python-qgis-dev.bat” file from:

I changed the final line of:

"%PYTHONHOME%\python" %*

To:

start /d "C:\Program Files\JetBrains\PyCharm Community Edition 2017.2.1\bin\" pycharm64.exe

Then from File> Settings> Project:> Project Interpreter> Set to “C:\OSGeo4W64\apps\Python36\python.exe”

It takes a while to update the interpreter.

I only had 2 errors, both for:

There is a list of API breaks between QGIS 2 and QGIS 3 at:
https://qgis.org/api/api_break.html

Looks like QgsMapLayerRegistry was moved to QgsProject. So I edit it to:

QgsProject.instance().addMapLayer(vl)

Then we can edit the metadata.txt to QGIS 3:
qgisMinimumVersion=3.0

And increase the version number.

Then we need to recompile the icon and ui for Python3 and QT5.

I was struggling a bit with the environmental variables to get it working, and ended up using a great batch script form StackExchange:
https://gis.stackexchange.com/questions/260743/how-to-compile-qtdesigner-user-interface-ui-and-resource-qrc-files-with-qg

@ECHO OFF

set OSGEO4W_ROOT=C:\OSGeo4W64

set PATH=%OSGEO4W_ROOT%\bin;%PATH%
set PATH=%PATH%;%OSGEO4W_ROOT%\apps\qgis\bin

@echo off
call "%OSGEO4W_ROOT%\bin\o4w_env.bat"
call "%OSGEO4W_ROOT%\bin\qt5_env.bat"
call "%OSGEO4W_ROOT%\bin\py3_env.bat"
@echo off
path %OSGEO4W_ROOT%\apps\qgis-dev\bin;%OSGEO4W_ROOT%\apps\grass\grass-7.2.2\lib;%OSGEO4W_ROOT%\apps\grass\grass-7.2.2\bin;%PATH%

cd /d %~dp0

@ECHO ON
::Ui Compilation
call pyuic5 multi_ring_buffer_dialog_base.ui -o multi_ring_buffer_dialog_base.py

::Resources
call pyrcc5 resources.qrc -o resources_rc.py

@ECHO OFF
GOTO END

:ERROR
echo "Failed!"
set ERRORLEVEL=%ERRORLEVEL%
pause

:END
@ECHO ON

So create the .bat file and run it in the folder of you plugin (editing where needed). Note: Your resources_rc may be called resource_rc or something slightly different.

Move the plugin folder to:

Boot up QGIS2.99/3.

I had a few more issues.

It seems QGIS 3 deals with the icon slightly differently.

icon_rc.py is no longer needed, and it seems was not used on my other plugin either.

So I removed the reference to it in the main python script:
from . import icon_rc

I still had some errors.

AttributeError: module ‘qgis.PyQt.QtGui’ has no attribute ‘QDialog’

It seems QDialog has moved to PyQt.QtWidgets.

So in my multi_ring_buffer_dialog.py file I needed to change some lines:

from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox

Change:
QtGui.QDialog
to:
QDialog
In the two instances in that file.

Working plugin!

Commit the changes back to the repo. Cd to the directory in git shell.

git add -A
git commit –m “Updated for QGIS 3”
git push

Zip the plugin up.

Second plugin:
Same issue with import *
1 error with QgsMapLayerRegistry
My resources_rc file was called resource_rc so the batch script needed to be edited to:
call pyrcc5 resources.qrc -o resource_rc.py
Same issues with QtGui.QDialog

Now time for some improvements.

## 7 thoughts on “Updating A Plugin From QGIS 2 to QGIS 3”

1. Eric

I just tried running through this and pip installed qgis2to3 (using the osgeo shell of course that comes with QGIS 3), but at the same osgeo shell, if I type qgis2to3, it tells me it’s not a recognized program. If I type python (or python3) qgis2to3, it says python: can’t open file ‘qgis2to3’: no such file or directory.

2. Marco

Hi Heikki,

1. I had to set env on py3 in order to pip qgis2to3.
2. I had to cd C:\OSGeo4W64\apps\Python36\Scripts in order to make the script working.
3. to launch the script I type:

py qgis2to3 path\to\my\plugin

4. After the first run I get a bunch of lines reporting:

RefactoringTool: Line 3: could not convert: from PyQt4.QtCore import *
RefactoringTool: Cannot handle star imports.
RefactoringTool: Line 4: could not convert: from PyQt4.QtGui import *
RefactoringTool: Cannot handle star imports.

5. I have included the following line in the script as you mentioned:
from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication, QVariant, Qt

6. Now the script doesn’t show any error (what about the PyQt4.QtGui import *) I have included only the PyQt4.QtCore.

7.from now on I am stuck…

– how do you create a bat file that launch PyCharm with the QGIS dev environmental variables?
– where do you find the “python-qgis-dev.bat” file?

1. Heikki Vesanto Post author

Hi Marco,

For the QtGui you will need at least QIcon:
from qgis.PyQt.QtGui import QIcon

But you can also remove the PyQt4.QtGui import *, and start up QGIS with the plugin installed, you will get an error that will say what imports are missing.

For example my error message was:

NameError: name 'QIcon' is not defined

The bat files are for windows, and will be found in the QGIS bat folder. Not sure about Linux. The instructions are at: Setting up PyCharm for PyQGIS and Qt