使QGIS python插件同时适用于2.x和3.x版本?


12

我正在将QGIS python插件从迁移QGIS 2QGIS 3,并浏览各种资源。

尚不清楚该插件是否可以与两个版本兼容,或者是否需要两个版本的插件。

到目前为止,我遇到的问题是如何管理PyQt导入(PyQt4 / PyQt5)?

Answers:


18

文献资料

在这里,您可以找到PyQGIS API的新功能和新功能
要获取有关如何将Python2移植到Python3的详细信息,请转到此处

您可以在以下问题上找到有关从QGIS2到QGIS3进行测试的详细信息:为QGIS插件编写自动化测试?

您将在这里找到有关迁移工具的有趣的OpenGis.ch论文

什么会变成我的代码

实际上,您需要更改不准备通过新版本的插件的代码。

您将获得qgis.utils.QGis.QGIS_VERSION_INT函数,该函数用于检查QGIS版本。当不建议使用的功能时,此功能很有用。例如setSelectedFeatures从2.16开始。

if语句的使用为例:

if qgis.utils.QGis.QGIS_VERSION_INT < 21600 :
            joinLayer.setSelectedFeatures( [ f.id() for f in request ] )
        else:
            joinLayer.selectByIds(  [ f.id() for f in request ] )

PyQt您在模块下导入的对象是相同的。如果需要兼容性,价格是编写更多代码行(具有QGIS2功能的代码和具有QGIS3功能的代码,以及用于检查版本和导入新库的功能的代码)。

关于PyQt库

PyQt5与PyQt4向后不兼容。PyQt5有一些重大变化。但是,将旧代码调整为新库并不是很困难。除其他外,差异如下:

  • Python模块已重新组织。一些模块已被删除(QtScript),其他模块被拆分为子模块(QtGui,QtWebKit)。

  • 引入了新模块,包括QtBluetooth,QtPositioning或Enginio。

  • PyQt5仅支持新型信号和插槽handlig。不再支持对SIGNAL()或SLOT()的调用。PyQt5不支持Qt v5.0中标记为已弃用或过时的Qt API的任何部分。

来源:(http://zetcode.com/gui/pyqt5/introduction/

以下是对您的from / import语句进行更改的一些示例:

记住使用PyQt4时,您必须查看API的文档:
例如
PyQT4 QtCore模块
PyQT4 QtGui模块

from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication, Qt, QObject, SIGNAL

from PyQt4.QtGui import QAction, QIcon, QDialog, QFormLayout

使用PyQt5,您现在必须查看这些API的文档:
PyQt5 QtCore模块
PyQt5 QtGui模块

这样就变成:

from PyQt5.QtCore import QSettings, QTranslator, QVersionNumber, QCoreApplication, Qt, QObject, pyqtSignal 
from PyQt5.QtGui import QIcon 
from PyQt5.QtWidgets import QAction, QDialog, QFormLayout

注意 :

QtGui模块已拆分为子模块。QtGui模块包含用于窗口系统集成,事件处理,2D图形,基本图像,字体和文本的类。它还包含一套完整的OpenGL和OpenGL ES绑定(请参阅对OpenGL的支持)。应用程序开发人员通常将其与更高级别的API配合使用,例如QtWidgets模块中包含的那些API。

而且PyQt5仅支持新型信号和插槽handlig!看看这个页面来了解如何使用pyqtSignalconnect以及e事件对象而不是使用SIGNAL

使其兼容

因此,为了与PyQt4 / PyQt5(以及QGIS2 / QGIS3)兼容,您需要在使用pyQt5 librarie之前先尝试/除外导入。

try:
    from PyQt5.QtCore import QSettings, QTranslator, QVersionNumber, QCoreApplication, Qt, QObject, pyqtSignal 
    from PyQt5.QtGui import QIcon 
    from PyQt5.QtWidgets import QAction, QDialog, QFormLayout

except:
    from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication, Qt, QObject, SIGNAL
    from PyQt4.QtGui import QAction, QIcon, QDialog, QFormLayout

并且不要忘记,您还需要通过添加try / except或if语句来更改代码下的某些特定功能。


2
伟大的答案,这东西会大大帮助是第一更换任何from PyQt4.QtCore import *from PyQt4.QtCore import QSomething, QWhatever, QElse,这将使迁移脚本做最后一步正确(包括必要的调整,其中模块改变),所以没有尝试-除了需要进口。
马提亚斯·库恩

您是对的,我曾经使用*使其简单,但是我会改变这一点,谢谢您的反馈
Hugo Roussaffa-GeoDatup

这个主题是告诉人们不要使用* -imports的理想场所,因为在这里它确实有所作为
Matthias Kuhn

@Hugo:确实非常详细的答案,它对入门起了很大的作用。我将把qgis2compat插件添加到已经引用的众多有用资源中。
sigeal

那是个好主意。您可以根据需要编辑答案。感谢您的反馈
Hugo Roussaffa-GeoDatup

2

尝试这样的事情:

try:
    # action for QGIS 3/PyQt5
except:
    # action for QGIS 2/PyQt4

这可能适用于某些孤立的事物,但通常不能用作通用解决方案。
马提亚斯·库恩

1

我刚刚完成了QGIS Python插件的移植,因此它现在支持2.x和3.x QGIS版本。这是我的经验:

通常,我试图依靠QGIS版本。但是,即使是拥有该版本的课程也被重命名了。所以我首先做了

try:
    from qgis.utils import Qgis  # for QGIS 3
except ImportError:
    from qgis.utils import QGis as Qgis  #  for QGIS 2

然后进行检查

if Qgis.QGIS_VERSION >= '3.0':
    # something for QGIS 3
else:
    # something for QGIS 2

部署最终版本后,我注意到还需要移植resources.py由它自动创建的文件pyrcc5。否则,插件将在2.x中继续崩溃。所以我改变了路线

from PyQt5 import QtCore

try:
    from PyQt5 import QtCore
except:
    from PyQt4 import QtCore

看起来很有效。我正式发布了版本,并认为就是这样。直到那时我才发现这个序列:

将我的插件安装在QGIS 2.18中,关闭QGIS,打开QGIS agan,然后在QGIS中打开Python控制台->整个QGIS将立即崩溃!

经过一些测试,我发现原因是resources.py上面写的这么小的变化。我不是QGIS Python库的专家,但我的解释如下:

当我打开QGIS时,我的插件被初始化。from PyQt5 import QtCore在错误的PyQt版本引发异常之前,尝试这样做会导致QGIS“工作流程”发生某些变化(这是一个RuntimeError)。当我启动Python Console时,这些更改导致QGIS崩溃。

最后,我决定采用其他解决方案。因为QGIS 2使用Python 2.7,而QGIS 3使用Python 3,所以我总是总是检查Python版本

from sys import version_info

if version_info[0] >= 3:
    # something for QGIS 3
else:
    # something for QGIS 2

这样可以避免所有可能有害的导入尝试。我的插件现在可以在两个QGIS版本上正常使用了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.