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