{"id":3691,"date":"2018-04-13T11:20:43","date_gmt":"2018-04-13T09:20:43","guid":{"rendered":"https:\/\/www.opengis.ch\/?p=3691"},"modified":"2020-04-29T16:05:12","modified_gmt":"2020-04-29T14:05:12","slug":"porting-qgis-plugins-to-api-v3-strategy-and-tools","status":"publish","type":"post","link":"https:\/\/www.opengis.ch\/de\/2018\/04\/13\/porting-qgis-plugins-to-api-v3-strategy-and-tools\/","title":{"rendered":"Porting QGIS plugins to API v3 &#8211; Strategy and tools"},"content":{"rendered":"<p>The Release of QGIS 3.0 was a great success and with the first LTR (3.4) scheduled for release this fall, it is now the perfect time to port your plugins to the new API.<br \/>\nQGIS 3.0 is the first major release since September 2013 when QGIS 2.0 was released. During the release cycles of all 2.x releases, the QGIS Python API remained stable. This means that a plugin or script meant to be used in QGIS 2.0 is still working in QGIS 2.18.<br \/>\nThe need for a new major release was principally motivated by the update to newer core libraries such as Qt 5 and Python 3. But it also offered a unique opportunity to the development team to tackle long-standing issues and limitations which could not be fixed during the 2.x life cycle. Inevitably, this introduced multiple backward incompatibilities making scripts and plugins unusable in QGIS 3.<br \/>\nIn this post, I&#8217;d like to share some notes from my latest ports. Obviously, if you need professional help for porting your plugins, don&#8217;t hesitate <a href=\"https:\/\/www.opengis.ch\/contact\/\">to contact us<\/a>.<\/p>\n<h1>Step 0 &#8211; Unit tests<\/h1>\n<p>You should already have your code covered by unit tests, but I know, the world is not perfect and at times we have to cut edges and, unfortunately, often unit tests are the ones getting cut.<br \/>\nPorting to a new API version is a great moment to go write unit tests helping to make sure that your plugin will keep on working as before the port.<\/p>\n<h1>Step 1 &#8211; fix * imports<\/h1>\n<p>Before going on, please go and remove all your * imports (like from PyQt4.QtGui import *). They are bad and qgis2to3 cannot handle them. There is no need to already change them to the PyQ5 version, just remove them and add the propper PyQt4 imports. We&#8217;ll handle moving to PyQt5 in a later step.<\/p>\n<blockquote><p>From PEP8: Wildcard imports (from <module> import *) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools.<\/module><\/p><\/blockquote>\n<h1>Step 2 &#8211; Versioning strategy<\/h1>\n<p>Since having a source code repository is a mandatory requirement for publishing a plugin on <a href=\"https:\/\/plugins.qgis.org\/plugins\/\" target=\"_blank\" rel=\"noopener noreferrer\">plugins.qgis.org<\/a>, I assume you already know what code versioning is and <a href=\"https:\/\/www.git-tower.com\/learn\/git\/ebook\/en\/desktop-gui\/basics\/why-use-version-control\" target=\"_blank\" rel=\"noopener noreferrer\">why you absolutely should be using it<\/a>.<\/p>\n<h2>APIv2 branch<\/h2>\n<p>Unless you absolutely want to make your code run on both API 2 and 3 (which <em>might<\/em> be possible) I strongly suggest to create a branch or your current version called qgis2, API2 or legacy or whatever you want to call it. From now on this branch will be responsible for all your future (probably mainly bugfixes) releases for the 2.x series of QGIS. Remember to edit the metadata.txt file and add your minimum and maximum version (not mandatory but nice for clarity):<\/p>\n<pre><code>qgisMinimumVersion=2.14\nqgisMaximumVersion=2.18\n<\/code><\/pre>\n<h2>Master branch<\/h2>\n<p>From now on your master branch will be where all your future development for the 3.x series will happen. Remember to edit the metadata.txt file and add your minimum version:<\/p>\n<pre><code>qgisMinimumVersion=3.0\n<\/code><\/pre>\n<h1>Step 3 &#8211; install the helpers<\/h1>\n<p>We created a repository with two dedicated tools to help you migrate your QGIS 2 plugins to QGIS 3: <code>qgis2to3<\/code> and <code>qgis2apifinder<\/code>. Both tools are distributed as a single Python package installable via<\/p>\n<pre><code>pip install qgis2to3\n<\/code><\/pre>\n<p>Please note that often for system-wide installation you need sudo.<br \/>\nAll the sources and more information can be found at\u00a0<a href=\"https:\/\/github.com\/opengisch\/qgis_2to3\">https:\/\/github.com\/opengisch\/qgis_2to3<\/a><\/p>\n<h1>Step 4 &#8211; Python 2 to Python 3 and PyQt4 to PyQt5<\/h1>\n<p>The <code>qgis2to3<\/code> tool is a copy of the files found in <a href=\"https:\/\/github.com\/qgis\/QGIS\/tree\/master\/scripts\" target=\"_blank\" rel=\"noopener noreferrer\">QGIS scripts<\/a> to allow for quick downloading and simple installation without the need of downloading the whole QGIS repository. This is a set of fixers for the python <code>2to3<\/code> command that will update your Python 2 code to Python 3. The additional fixers will also take care of the PyQt4 to PyQt5 porting as well as some other things.<br \/>\nRunning the <code>qgis2to3<\/code> command will show a number of changes required. These changes can be applied with <code>-w<\/code> flag<\/p>\n<pre><code>qgis2to3 -w \/path\/to\/your\/plugin\n<\/code><\/pre>\n<h1>Step 5 &#8211; Check for API v2 usages<\/h1>\n<p>The <code>qgisapi2finder<\/code> tool helps you find usages of the QGIS API version 2 and gives hints about potential required changes for API version 3.<br \/>\nIt is based on a machine parsing of <a href=\"https:\/\/qgis.org\/api\/api_break.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/qgis.org\/api\/api_break.html<\/a> so the results are as good as the information there.<br \/>\nAlso, being a simple text parser, it just gives a hint where to look at. It is by no means a complete tool to find all the possible API incompatibility.<br \/>\nMethods are matched using only their names and not their classes, so there might be various false positives. Also, if the same keyword has been edited in various classes, <code>qgisapi2finder<\/code> will show you all the available suggestions for that keyword.<br \/>\nYou can run <code>qgis2apifinder<\/code> to get hints on the existence of obsolete code requiring manual porting and suggestions on how to actually deal with it. Please note that <code>qgis2apifinder<\/code> does hide some very frequent words like [&#8218;layout&#8216;, &#8218;layer&#8216;, &#8218;fields&#8216;] from the analysis. You can show those with the <code>--all<\/code> flag.<\/p>\n<pre><code>qgis2apifinder --all \/path\/to\/plugin\nqgis2apifinder --all \/path\/to\/plugin\/file.py\n<\/code><\/pre>\n<h1>Step 6 &#8211; update your code<\/h1>\n<p>From here on it is all looking at each hint, updating the code and rerunning your tests. A properly configured IDE (stay tuned) could also help in the process.<br \/>\nSome more information can be found at <a href=\"https:\/\/github.com\/qgis\/QGIS\/wiki\/Plugin-migration-to-QGIS-3\" target=\"_blank\" rel=\"noopener noreferrer\">github.com\/qgis\/QGIS\/wiki\/Plugin-migration-to-QGIS-3<\/a><br \/>\nAlso, take a look at the PyQGIS API documentation now online at <a href=\"https:\/\/python.qgis.org\/master\" target=\"_blank\" rel=\"noopener noreferrer\">python.qgis.org\/master<\/a>.<br \/>\nI hope this post and tool can help you porting your plugins to QGIS3 and again if you need professional help for porting your plugins, don&#8217;t hesitate <a href=\"https:\/\/www.opengis.ch\/contact\/\">to contact us<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Release of QGIS 3.0 was a great success and with the first LTR (3.4) scheduled for release this fall, it is now the perfect time to port your plugins to the new API. QGIS 3.0 is the first major release since September 2013 when QGIS 2.0 was released. During [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_themeisle_gutenberg_block_has_review":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[5,37,14,15],"tags":[125],"class_list":["post-3691","post","type-post","status-publish","format-standard","hentry","category-featured","category-pyqt","category-python","category-qgis","tag-qgis-org"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":2127,"url":"https:\/\/www.opengis.ch\/de\/2016\/09\/19\/qgis2-compatibility-plugin\/","url_meta":{"origin":3691,"position":0},"title":"QGIS2 compatibility plugin","author":"Marco Bernasocchi","date":"19. September 2016","format":false,"excerpt":"Lately I've been spending time porting a bigger plugin from QGIS 2.8 to 3 while maintaining 2.8 compatibility. You can find it at https:\/\/github.com\/opengisch\/qgis2compat\/ and https:\/\/plugins.qgis.org\/plugins\/qgis2compat\/ One code to rule them all. My target was to have to edit the source code as little as possible to simulate a lazy\u2026","rel":"","context":"In &quot;PyQt&quot;","block_context":{"text":"PyQt","link":"https:\/\/www.opengis.ch\/de\/category\/programming\/python\/pyqt\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2074,"url":"https:\/\/www.opengis.ch\/de\/2016\/05\/04\/qgis-qt5-and-python3-migration-current-state\/","url_meta":{"origin":3691,"position":1},"title":"QGIS: Qt5 and Python3 migration, current state","author":"Matthias Kuhn","date":"4. Mai 2016","format":false,"excerpt":"Behind the scenes a lot has happened to get ready for Qt5 and Python3. On the same codebase that is becoming the next release QGIS 2.16. This is really a great thing since we can focus work on a single master branch and I'm very happy that we got so\u2026","rel":"","context":"In &quot;C++&quot;","block_context":{"text":"C++","link":"https:\/\/www.opengis.ch\/de\/category\/programming\/cpp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2059,"url":"https:\/\/www.opengis.ch\/de\/2016\/03\/23\/prepare-your-plugins-for-qgis-3\/","url_meta":{"origin":3691,"position":2},"title":"Prepare your plugins for QGIS 3","author":"Matthias Kuhn","date":"23. M\u00e4rz 2016","format":false,"excerpt":"QGIS 3 is not yet there and there is still plenty of time to prepare and migrate. But I thought I would give some advice about things that you can keep in mind while working on your plugins to make your life easier when you will have to actually do\u2026","rel":"","context":"In &quot;Uncategorised&quot;","block_context":{"text":"Uncategorised","link":"https:\/\/www.opengis.ch\/de\/category\/uncategorised\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":154,"url":"https:\/\/www.opengis.ch\/de\/2010\/12\/06\/qgis-plugins-starter-plugin\/","url_meta":{"origin":3691,"position":3},"title":"Qgis plugins starter plugin","author":"Marco Bernasocchi","date":"6. Dezember 2010","format":false,"excerpt":"Today I published my first QGis Python plugin. It does allow to configure a list of available plugins actions to execute in one click. It is published in pyqgis contributed repository and the source is developed on My GitHub Cheers Marco","rel":"","context":"In &quot;GIS&quot;","block_context":{"text":"GIS","link":"https:\/\/www.opengis.ch\/de\/category\/gis\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":15596,"url":"https:\/\/www.opengis.ch\/de\/2025\/05\/28\/qgis-industry-solutions-developer\/","url_meta":{"origin":3691,"position":4},"title":"QGIS &amp; Industry Solutions Developer\u00a0| 80 \u2013 100% (Remote)","author":"Marco Bernasocchi","date":"28. Mai 2025","format":false,"excerpt":"\ud83d\udda5\ufe0f\ud83d\ude80 Join OPENGIS.ch as a QGIS & Industry Solutions Developer! We\u2019re seeking a skilled C++ and Python developer to contribute to QGIS core, build plugins, and deliver custom geospatial solutions. Work remotely with a dynamic, open-source-focused team. Apply now to help shape the future of geospatial technology!","rel":"","context":"In &quot;Job Postings Archive&quot;","block_context":{"text":"Job Postings Archive","link":"https:\/\/www.opengis.ch\/de\/category\/jobs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2025\/03\/image.png?fit=1200%2C1167&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2025\/03\/image.png?fit=1200%2C1167&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2025\/03\/image.png?fit=1200%2C1167&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2025\/03\/image.png?fit=1200%2C1167&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/www.opengis.ch\/wp-content\/uploads\/2025\/03\/image.png?fit=1200%2C1167&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":147,"url":"https:\/\/www.opengis.ch\/de\/2010\/12\/01\/qgis-globe-plugin-installer-script\/","url_meta":{"origin":3691,"position":5},"title":"QGis Globe Plugin installer script","author":"Marco Bernasocchi","date":"1. Dezember 2010","format":false,"excerpt":"Lately, thanks to ma Master Thesis, I've been co-working on the Globe Plugin for QGis here my install script for a threaded version of QGis with the Globe Plugin. By now the Globe has stereo 3D support, keyboard navigation (try all the num key), mouse navigation, a gui to control\u2026","rel":"","context":"In &quot;C++&quot;","block_context":{"text":"C++","link":"https:\/\/www.opengis.ch\/de\/category\/programming\/cpp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_shortlink":"https:\/\/wp.me\/pbdBtI-Xx","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/posts\/3691","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/comments?post=3691"}],"version-history":[{"count":1,"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/posts\/3691\/revisions"}],"predecessor-version":[{"id":11136,"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/posts\/3691\/revisions\/11136"}],"wp:attachment":[{"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/media?parent=3691"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/categories?post=3691"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.opengis.ch\/de\/wp-json\/wp\/v2\/tags?post=3691"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}