Czy zrobić wtyczkę python QGIS dla obu wersji 2.xi 3.x?


12

Jestem w procesie migracji wtyczki QGIS Python od QGIS 2celu QGIS 3i przeglądania różnych zasobów.

Nie jest jasne, czy możliwe jest kompatybilność wtyczki z obiema wersjami, czy też konieczne są dwa uchwyty do wersji wtyczki.

Problem, na który natrafiłem do tej pory, to jak zarządzać importem PyQt (PyQt4 / PyQt5)?

Odpowiedzi:


18

Dokumentacja

Tutaj możesz znaleźć, co nowego, a co psuje się w interfejsie API PyQGIS .
Aby uzyskać szczegółowe informacje na temat sposobu przenoszenia Python2 na Python3, przejdź tam

Szczegółowe informacje na temat testowania z QGIS2 na QGIS3 można znaleźć w tym pytaniu: Pisanie automatycznych testów wtyczek QGIS?

Znajdziesz tu interesujący artykuł OpenGis.ch na temat narzędzi do migracji.

Co zmieni się w mój kod

W rzeczywistości musisz zmienić kod wtyczki, która nie jest przygotowana do przejścia przez nową wersję.

Otrzymasz qgis.utils.QGis.QGIS_VERSION_INT funkcję, która jest wykonana w celu sprawdzenia wersji QGIS. Jest to przydatne, gdy funkcja jest przestarzała. Na przykład setSelectedFeaturesod 2.16.

Na przykład za pomocą ifinstrukcji:

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 ] )

To samo dotyczy PyQtobiektu importowanego w ramach modułu. Jeśli potrzebujesz kompatybilności, cena polega na napisaniu większej liczby linii kodu (kod z funkcją QGIS2 i kod z funkcjami QGIS3 ORAZ także kod do sprawdzenia wersji i możliwości importowania nowych bibliotek).

O bibliotekach PyQt

PyQt5 nie jest wstecznie kompatybilny z PyQt4; istnieje kilka istotnych zmian w PyQt5. Jednak dostosowanie starszego kodu do nowej biblioteki nie jest trudne. Różnice są między innymi następujące:

  • Moduły Python zostały zreorganizowane. Niektóre moduły zostały usunięte (QtScript), inne zostały podzielone na submoduły (QtGui, QtWebKit).

  • Wprowadzono nowe moduły, w tym QtBluetooth, QtPositioning lub Enginio.

  • PyQt5 obsługuje tylko obsługę sygnałów i gniazd w nowym stylu. Wywołania SIGNAL () lub SLOT () nie są już obsługiwane. PyQt5 nie obsługuje żadnych części interfejsu API Qt, które są oznaczone jako przestarzałe lub nieaktualne w Qt v5.0.

źródło: ( http://zetcode.com/gui/pyqt5/introduction/ )

Oto kilka przykładów zmian w wyciągu z / import:

Pamiętaj, że z PyQt4 musiałeś przejrzeć dokumentację API:
na przykład
moduł
PyQT4 QtCore moduł PyQT4 QtGui

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

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

A z PyQt5 musisz teraz zapoznać się z dokumentacją API:
PyQt5 Moduł QtCore Moduł
PyQt5 QtGui

aby stały się:

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

Uwaga:

Moduł QtGui został podzielony na submoduły. Moduł QtGui zawiera klasy integracji systemu okienkowego, obsługi zdarzeń, grafiki 2D, podstawowego obrazowania, czcionek i tekstu. Zawiera także pełny zestaw powiązań OpenGL i OpenGL ES (zobacz Obsługa OpenGL ). Twórcy aplikacji zwykle używają tego z interfejsami API wyższego poziomu, takimi jak te zawarte w module QtWidgets.

PyQt5 obsługuje tylko obsługę sygnałów i gniazd w nowym stylu! zajrzyj na tę stronę, aby dowiedzieć się, jak używać pyqtSignal, connecti eobiektu zdarzenia zamiast używać SIGNAL.

Zrób to kompatybilne

Tak więc z kompatybilnością między PyQt4 / PyQt5 (a także QGIS2 / QGIS3) musisz spróbować / oprócz importu przed użyciem biblioteki 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

I nie zapominaj, że musisz zmienić także określoną funkcję w swoim kodzie, dodając instrukcję try / else lub if.


2
Świetna odpowiedź, coś, co w znacznym stopniu pomaga to najpierw wymienić każdy from PyQt4.QtCore import *z from PyQt4.QtCore import QSomething, QWhatever, QElsebędzie to zrobić skrypt migracji zrobić ostatni krok poprawnie (w tym wymaganych korekt gdzie moduły zmienione), więc nie spróbować z wyjątkiem importu są potrzebne.
— Matthias Kuhn

masz rację, użyłem * dla uproszczenia, ale zmienię to, dziękuję za twoją opinię
— Hugo Roussaffa - GeoDatup

ten temat jest idealnym miejscem, aby powiedzieć ludziom, aby nie używali * -importów, ponieważ tutaj to naprawdę robi różnicę
— Matthias Kuhn

@ Hugo: Rzeczywiście bardzo szczegółowa odpowiedź, bardzo pomogła na początku. Będę dodać qgis2compat plugin do wielu użytecznych zasobów już cytowanych.
— sigeal

To świetny pomysł. Możesz edytować odpowiedź, jak chcesz. Dzięki za opinie
— Hugo Roussaffa - GeoDatup

2

Wypróbuj coś takiego:

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

Może to działać w przypadku niektórych odizolowanych rzeczy, ale często nie będzie działać jako ogólne rozwiązanie.
— Matthias Kuhn

1

Właśnie zakończyłem portowanie wtyczki QGIS Python, dzięki czemu obsługuje teraz zarówno wersje QGIS 2.x, jak i 3.x. Oto moje doświadczenie:

Głównie starałem się polegać na wersji QGIS. Ale nawet klasa posiadająca wersję została nieco zmieniona. Więc najpierw to zrobiłem

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

a następnie sprawdź

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

Po wdrożeniu ostatecznej wersji zauważyłem, że plik, resources.pyktóry jest tworzony automatycznie, pyrcc5również musi zostać przeniesiony. W przeciwnym razie wtyczka będzie się rozkładać w wersji 2.x. Więc zmieniłem jego linię

from PyQt5 import QtCore

do

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

Wyglądało na to, że zadziałało. Wydałem oficjalne wydanie i pomyślałem, że o to chodzi. Dopiero wtedy odkryłem tę sekwencję:

Zainstaluj moją wtyczkę w QGIS 2.18, zamknij QGIS, otwórz agan QGIS, a następnie otwórz konsolę Python w QGIS -> Cały QGIS natychmiast się zawiesi!

Po kilku testach dowiedziałem się, że przyczyną była ta niewielka zmiana w resources.pypiśmie powyżej. Nie jestem ekspertem od bibliotek QGIS Python, ale moje wyjaśnienie jest następujące:

Kiedy otwieram QGIS, moja wtyczka zostaje zainicjowana. Próba wykonania from PyQt5 import QtCorepowoduje pewne zmiany w „przepływie pracy” QGIS, zanim niewłaściwa wersja PyQt zgłosi wyjątek (było to a RuntimeError). Kiedy uruchamiam konsolę Python, zmiany te powodują awarię QGIS.

Na koniec zdecydowałem się na inne rozwiązanie. Ponieważ QGIS 2 używa Python 2.7, a QGIS 3 używa Python 3, po prostu zawsze sprawdzam wersję Python .

from sys import version_info

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

Pozwala to uniknąć wszystkich potencjalnie szkodliwych prób importowania. Moja wtyczka działa teraz w obu wersjach QGIS bez żadnych problemów.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.