QGIS2と3に対応するプラグイン開発のTips

この記事は1年以上前に書かれました。
内容が古くなっている可能性がありますのでご注意下さい。


QGIS2からQGIS3へのバージョンアップに伴い、以下のような大きな変更がありました。

  • PyQt4 → PyQt5 へアップデート
  • Python 2.7 → Python 3 へアップデート

QGISプラグイン開発に使用されるPlugin Builderプラグインも、QGIS3向けにPlugin Builder 3が用意されています。
今後はQGIS3が主流になると思いますが、今のところ長期リリース版は2.18であることから、QGIS2を使い続けている現場も多いようです。
そこで、QGIS2と3の両方に対応するプラグイン開発のTipsを簡単にまとめておきます。

metadata.txtの修正
QGIS2向けのPlugin Builderプラグインが生成したmetadata.txtファイルでは、

qgisMinimumVersion=2.0

のように最低バージョンが指定されています。このままですと、最高バージョンは2.99となり、QGIS3には対応しません。

qgisMaximumVersion=3.99

という記述を追加すると、QGIS2と3の両方に対応させることができます。

qgis.PyQtのインポート
QGIS2用に開発したプラグインでは、

from PyQt4.QtCore import *
from PyQt4.QtGui import *

のように、PyQt4のモジュールをインポートしています。これを

from qgis.PyQt.QtCore import *
from qgis.PyQt.QtGui import *

のように書き換えると、QGISのバージョンによってPyQt4とPyQt5のどちらかから適切なモジュールがインポートされます。しかし、

from PyQt4.QtGui import QAction

のようにクラス名を記述している場合、

from qgis.PyQt.QtGui import QAction

ではエラーになってしまいます。PyQt5では、QActionはQtWidgetsモジュールに含まれるためです。


QGISのバージョン判定

qgis.coreモジュールに含まれるQGisクラス(QGIS2の場合)またはQgisクラス(QGIS3の場合)に含まれるバージョン情報を用いて、インポートを振り分けることもできます。
まず、QGISのバージョンによらずQGisという名前でインポートします。

from qgis import core
if hasattr(core, "QGis"):
    from qgis.core import QGis
else:
    from qgis.core import Qgis as QGis

つぎに、QGisクラスのQGIS_VERSION_INTを用いてバージョンを判定します。

QG3 = QGis.QGIS_VERSION_INT >= 30000

QG3の真偽によってインポートを振り分けます。

if QG3 :
    from PyQt5.QtWidgets import QAction
else:
    from PyQt4.QtGui import QAction

インポートだけではなく、処理も同様に振り分けることができます。

if QG3:
    QgsProject.instance().addMapLayer(newLayer)
else:
    QgsMapLayerRegistry.instance().addMapLayer(newLayer)


Pythonのバージョン判定

Pythonのバージョンはsysモジュールのversion_infoを用いて判定することができます。

import sys
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

インポートや処理の振り分けに使用します。

if PY2:
    from urllib2 import urlopen, URLError
else:
    from urllib.request import urlopen, URLError
QGISプラグインの開発 12345