Сделать плагин QGIS Python для обеих версий 2.x и 3.x?

12

Я нахожусь в процессе миграции плагина QGIS Python из QGIS 2в QGIS 3и просмотра различных ресурсов.

Не ясно, возможно ли иметь плагин, совместимый с обеими версиями, или необходимо две версии для плагинов.

Проблема, с которой я столкнулся, заключается в том, как управлять импортом PyQt (PyQt4 / PyQt5)?

sigeal
источник

Ответы:

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, QtPosition или Enginio.

  • PyQt5 поддерживает только новый стиль сигналов и слотов. Вызовы SIGNAL () или SLOT () больше не поддерживаются. PyQt5 не поддерживает какие-либо части Qt API, которые помечены как устаревшие или устаревшие в Qt v5.0.

источник: ( http://zetcode.com/gui/pyqt5/introduction/ )

Вот несколько примеров изменений в вашем утверждении from / import:

Помните , с PyQt4 вы должны были смотреть на документ в API,:
для Exemple
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 module
PyQt5 QtGui module

так что становитесь

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.

А PyQt5 поддерживает только новый стиль сигналов и слотов! Посмотрите на эту страницу, чтобы понять, как использовать pyqtSignal, connectи eобъект события вместо использования SIGNAL.

Сделайте это совместимым

Так что с совместимостью между PyQt4 / PyQt5 (и QGIS2 / QGIS3 также) вы должны попробовать / исключить импорт, прежде чем использовать библиотеку pyQt5.

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 / исключением или if.

Уго Руссаффа - GeoDatup
источник
2
Великий ответ, что - то , что будет в значительной степени помощи в первую заменить любого from PyQt4.QtCore import *с from PyQt4.QtCore import QSomething, QWhatever, QElse, это не сделает сценарий миграции сделать последний шаг надлежащим образом ( в том числе необходимых корректировок , где измененные модули), поэтому нет примерочного , кроме импорта необходимы.
Матиас Кун
Вы правы, я использовал *, чтобы сделать это простым, но я изменю это, спасибо за ваш отзыв
Хьюго Руссаффа - GeoDatup
эта тема - идеальное место, чтобы сказать людям не использовать * -импорты, потому что здесь это действительно имеет значение
Матиас Кун,
@Hugo: Действительно очень подробный ответ, он очень помог начать. Я добавлю плагин qgis2compat к уже упомянутым многочисленным полезным ресурсам.
sigeal
Это отличная идея. Вы можете редактировать ответ, как вы хотите. Спасибо за отзыв
Уго Руссаффа - 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, а затем откройте консоль Python внутри QGIS -> Весь QGIS мгновенно потерпит крах!

После некоторого тестирования я узнал, что причиной было это небольшое изменение в resources.pyнаписанном выше. Я не эксперт в библиотеках QGIS Python, но мое объяснение таково:

Когда я открываю QGIS, мой плагин инициализируется. Попытка выполнения from PyQt5 import QtCoreвызывает некоторые изменения в «рабочем процессе» QGIS, прежде чем неправильная версия PyQt вызовет исключение (это было 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 без проблем.

AleksMat
источник