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:
1 |
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:
https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/qgis/QGIS/tree/master/scripts
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):
1 |
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:
1 2 |
RefactoringTool: Line 31: could not convert: from PyQt4.QtCore import * RefactoringTool: Cannot handle star imports. |
So my plugins line of:
1 |
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:
1 |
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:
1 |
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:
1 |
"%PYTHONHOME%\python" %* |
To:
1 |
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:OSGeo4W64appsPython36python.exe”
It takes a while to update the interpreter.
I only had 2 errors, both for:
QgsMapLayerRegistry.instance().addMapLayer(vl)
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:
1 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
@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:
C:\Users\USERNAME\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins\
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:
Add:
1 |
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.
1 2 3 |
git add -A git commit –m “Updated for QGIS 3” git push |
Zip the plugin up.
Upload to https://plugins.qgis.org/plugins/
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.
Pingback: Updating A Plugin From QGIS 2 to QGIS 3 – GeoNe.ws
Hi thanks or the post, we now released a pip package to help you port QGIS plugins, it would be nice if you could update your article
https://github.com/opengisch/qgis2to3/
Cheers
Marco
Updated. Thanks.
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.
Hi Eric,
You can use the following link to download the script folder as well, you can then run it from the folder you extracted it into:
https://minhaskamal.github.io/DownGit/#/home?url=https://github.com/qgis/QGIS/tree/master/scripts
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?
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