{"id":2127,"date":"2016-09-19T16:01:39","date_gmt":"2016-09-19T14:01:39","guid":{"rendered":"https:\/\/www.opengis.ch\/?p=2127"},"modified":"2020-04-29T16:05:13","modified_gmt":"2020-04-29T14:05:13","slug":"qgis2-compatibility-plugin","status":"publish","type":"post","link":"https:\/\/www.opengis.ch\/it\/2016\/09\/19\/qgis2-compatibility-plugin\/","title":{"rendered":"QGIS2 compatibility plugin"},"content":{"rendered":"<p>Lately I&#8217;ve been spending time porting a bigger plugin from QGIS 2.8 to 3 while maintaining 2.8 compatibility.<br \/>\nYou can find it at <a href=\"https:\/\/github.com\/opengisch\/qgis2compat\/\">https:\/\/github.com\/opengisch\/qgis2compat\/<\/a><br \/>\nand <a href=\"https:\/\/plugins.qgis.org\/plugins\/qgis2compat\/\">https:\/\/plugins.qgis.org\/plugins\/qgis2compat\/<\/a><br \/>\nOne code to rule them all.<br \/>\nMy target was to have to edit the source code as little as possible to simulate a lazy or busy coder that has to upgrade his\/her plugins.<br \/>\nLots of work has already gone into 2.14 to support PyQt 4 and 5 with the same code (Kudos to jef-n and mkuhn).<\/p>\n<pre><code class=\"Python\"># QGIS before 2.14\nfrom PyQt4\n# QGIS 2.14 and after\nfrom qgis.PyQt\n<\/code><\/pre>\n<p>The qgis python package will then use the appropriate PyQt for you. But not all can be fixed in QGIS itself and this is why QGIS2compat can help you.<\/p>\n<h1>Use cases<\/h1>\n<p>QGIS2compat targets two main use cases.<\/p>\n<h2>PyQt compat<\/h2>\n<p>If you still need to rely on QGIS &lt; 2.14 writing <code>from qgis.PyQt<\/code> will not work for you as the qgis.PyQt package is simply not there. And this is one of the two use case where QGIS2compat can help you. This feature is complete.<\/p>\n<h2>QGIS 2-3 API compatibility<\/h2>\n<p>The other use case of QGIS2compat plugin is the availability of a QGIS API compatibility layer which lets you write your code for QGIS 3 API and it will take care of adapting it to the QGIS 2 API. This feature is an ongoing work in progress since we are in the middle of API breakage period. So we do need your help to keeping adding new apicompat fixes (see below).<\/p>\n<h1>Usage<\/h1>\n<p>In your plugin&#8217;s <code>__init__.py<\/code> you should put something like the example<br \/>\nbelow. This will pick the QGIS PyQt compatibility layer which is<br \/>\navailable since QGIS 2.14 or fall back to qgis2compat.<br \/>\nAlso if you are in QGIS >= 2.14 and QGIS &lt; 3 it will run the apicompat<br \/>\npackage which will take care of the Python api changes between QGIS 2<br \/>\nand QGIS 3.<\/p>\n<pre><code class=\"Python\">import os\nimport qgis.utils\n# noinspection PyPep8Naming\ndef classFactory(iface):  # pylint: disable=invalid-name\n    \"\"\"Load MyPlugin class from file MyPlugin.\n    :param iface: A QGIS interface instance.\n    :type iface: QgsInterface\n    \"\"\"\n    plugin_name = os.path.dirname(__file__).split(os.path.sep)[-1]\n    plugin_name = qgis.utils.pluginMetadata(plugin_name, 'name')\n    try:\n        # qgis.PyQt is available in QGIS &gt;=2.14\n        from qgis.PyQt.QtCore import qVersion\n        # qgis.utils.QGis is available in QGIS &lt; 3\n        if hasattr(qgis.utils, 'QGis'):\n            import qgis2compat.apicompat\n            qgis2compat.log('apicompat used in %s' % plugin_name)\n    except ImportError:\n        try:\n            # we are in QGIS &lt; 2.14\n            import qgis2compat\n            import qgis2compat.apicompat\n            qgis2compat.log('PyQt and apicompat used in %s' % plugin_name)\n        except ImportError:\n            import traceback\n            message = ('The Plugin %s uses the QGIS2compat plugin. '\n                       'Please install it with the plugin manager it and '\n                       'restart QGIS. For more information read '\n                       'https:\/\/opengis.ch\/qgis2compat' %\n                       plugin_name)\n            traceback.print_exc()\n            raise ImportError(message)\n    from .myplugin import MyPlugin\n    return MyPlugin(iface)\n<\/code><\/pre>\n<p>in each module where you do PyQt imports you should use the following<br \/>\nstructure.<\/p>\n<pre><code class=\"Python\">from qgis.PyQt.QtCore import QFileDialog\n<\/code><\/pre>\n<p>This will guarantee that the imports come from the most appropriate and<br \/>\nup-to-date place and gives you PyQt4 and PyQt5 support for QGIS >= 2.8.<\/p>\n<h2>Updating your plugin<\/h2>\n<p>This can be done automatically by the 2to3 tool included in QGIS sourcecode.<br \/>\nPlease note that it is not the plain 2to3 python tool and can be found<br \/>\nat <a href=\"https:\/\/github.com\/qgis\/QGIS\/blob\/master\/scripts\/2to3\">https:\/\/github.com\/qgis\/QGIS\/blob\/master\/scripts\/2to3<\/a><br \/>\nThis tool will fix many (probably not all) issues with your code and make it<br \/>\ncompatible with Python 3.<br \/>\nAfter running 2to3, update your <code>__init__.py<\/code> as explained above.<br \/>\nonce done, it is time to run your tests (which you of course have written<br \/>\nbefore migrating) and fix the minor glitches that might have appeared.<\/p>\n<h2>Adding new apicompat fixes<\/h2>\n<p>To add a new api compatibility fix, just create (or add to an existing one) a<br \/>\nnew module in apicompat and import it in <code>__init__.py__<\/code> like it is done for<br \/>\nthe <a href=\"https:\/\/github.com\/opengisch\/qgis2compat\/blob\/master\/apicompat\/qgsvectorlayer.py\">qgsvectorlayer.py<\/a><br \/>\nAs QGIS2compat works on a fairly low level, we <strong>require<\/strong> unit tests for each<br \/>\nfix to be included in each pull request.<\/p>\n<h2>Need professional help?<\/h2>\n<p>OPENGIS.ch can help you updating all your plugins and with any QGIS related problem you have. <a href=\"\/contact\">Contact us<\/a> for a quote<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lately I&#8217;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 [&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":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[37,15,16],"tags":[125],"class_list":["post-2127","post","type-post","status-publish","format-standard","hentry","category-pyqt","category-qgis","category-qgis-plugins","tag-qgis-org"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":2115,"url":"https:\/\/www.opengis.ch\/it\/2016\/09\/11\/updating-pyqt-signals-that-use-lambda-in-qgis-with-2to3\/","url_meta":{"origin":2127,"position":0},"title":"Updating PyQt signals that use lambda in QGIS with 2to3","author":"Marco Bernasocchi","date":"11 Settembre 2016","format":false,"excerpt":"Just for the sake of documenting things, when running qgis 2to3 on a plugin I encountered a tricky situation regarding signals. MYQGISDIR\/scripts\/2to3 -f signals -w my\/plugin\/path The original code: extra_arg = \"my test argument\" QObject.connect( action, SIGNAL( \"triggered()\"), lambda extra_arg=my_arg: show_extra_arg(extra_arg)) def do_load_project(extra_arg): print extra_arg # \"my test argument\" The\u2026","rel":"","context":"In &quot;PyQt&quot;","block_context":{"text":"PyQt","link":"https:\/\/www.opengis.ch\/it\/category\/programming\/python\/pyqt\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3691,"url":"https:\/\/www.opengis.ch\/it\/2018\/04\/13\/porting-qgis-plugins-to-api-v3-strategy-and-tools\/","url_meta":{"origin":2127,"position":1},"title":"Porting QGIS plugins to API v3 &#8211; Strategy and tools","author":"Marco Bernasocchi","date":"13 Aprile 2018","format":false,"excerpt":"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\u2026","rel":"","context":"In &quot;Featured&quot;","block_context":{"text":"Featured","link":"https:\/\/www.opengis.ch\/it\/category\/featured\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3314,"url":"https:\/\/www.opengis.ch\/fr\/2017\/10\/03\/cours-pyqgis-13-11-14-11-2017-a-neuchatel\/","url_meta":{"origin":2127,"position":2},"title":"Cours PyQGIS 13.11.\/14.11.2017 \u00e0 Neuch\u00e2tel","author":"Matthias Kuhn","date":"3 Ottobre 2017","format":false,"excerpt":"Le cours est complet. Le cours est destin\u00e9 aux utilisateurs avanc\u00e9s de QGIS qui souhaitent accro\u00eetre leurs possibilit\u00e9s gr\u00e2ce \u00e0 l\u2019utilisation de python dans QGIS. Lors de cette formation, nous aborderons diff\u00e9rentes possibilit\u00e9s d\u2019interaction avec l\u2019API QGIS ainsi que la cr\u00e9ation d\u2019interfaces graphiques simples avec PyQt. Les th\u00e8mes suivants seront\u2026","rel":"","context":"In &quot;QGIS&quot;","block_context":{"text":"QGIS","link":"https:\/\/www.opengis.ch\/fr\/category\/gis-fr\/qgis-fr\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":7545,"url":"https:\/\/www.opengis.ch\/fr\/2019\/09\/16\/cours-pyqgis-23-1-30-1-2020-a-lausanne\/","url_meta":{"origin":2127,"position":3},"title":"Cours PyQGIS 23.1.\/30.1.2020 \u00e0 Lausanne","author":"Matthias Kuhn","date":"16 Settembre 2019","format":false,"excerpt":"Le cours est destin\u00e9 aux utilisateurs avanc\u00e9s de QGIS qui souhaitent accro\u00eetre leurs possibilit\u00e9s gr\u00e2ce \u00e0 l\u2019utilisation de python dans QGIS. Lors de cette formation, nous aborderons diff\u00e9rentes possibilit\u00e9s d\u2019interaction avec l\u2019API QGIS ainsi que la cr\u00e9ation d\u2019interfaces graphiques simples avec PyQt.Les th\u00e8mes suivants seront trait\u00e9s: Utilisation de la console\u2026","rel":"","context":"In &quot;Non classifi\u00e9(e)&quot;","block_context":{"text":"Non classifi\u00e9(e)","link":"https:\/\/www.opengis.ch\/fr\/category\/non-classifiee\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2074,"url":"https:\/\/www.opengis.ch\/it\/2016\/05\/04\/qgis-qt5-and-python3-migration-current-state\/","url_meta":{"origin":2127,"position":4},"title":"QGIS: Qt5 and Python3 migration, current state","author":"Matthias Kuhn","date":"4 Maggio 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\/it\/category\/programming\/cpp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1668,"url":"https:\/\/www.opengis.ch\/it\/2016\/09\/07\/using-threads-in-qgis-python-plugins\/","url_meta":{"origin":2127,"position":5},"title":"Using threads in QGIS python plugins","author":"Marco Bernasocchi","date":"7 Settembre 2016","format":false,"excerpt":"Here an example on how to work with threads in a consistent and clean manner in QGIS python plugins","rel":"","context":"In &quot;Python&quot;","block_context":{"text":"Python","link":"https:\/\/www.opengis.ch\/it\/category\/programming\/python\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_shortlink":"https:\/\/wp.me\/pbdBtI-yj","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts\/2127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/comments?post=2127"}],"version-history":[{"count":1,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts\/2127\/revisions"}],"predecessor-version":[{"id":11140,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/posts\/2127\/revisions\/11140"}],"wp:attachment":[{"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/media?parent=2127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/categories?post=2127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.opengis.ch\/it\/wp-json\/wp\/v2\/tags?post=2127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}