Buat plugin python QGIS untuk kedua versi 2.x dan 3.x?


12

Saya sedang dalam proses migrasi plugin python QGIS dari QGIS 2ke QGIS 3, dan menjelajahi berbagai sumber.

Tidak jelas apakah mungkin untuk memiliki plugin yang kompatibel dengan kedua versi atau jika perlu dua pegangan untuk versi plugin.

Masalah yang saya bahas sejauh ini adalah bagaimana mengelola impor PyQt (PyQt4 / PyQt5)?

Jawaban:


18

Dokumentasi

Di sini Anda dapat menemukan apa yang baru dan yang rusak di bawah API PyQGIS .
Untuk mendapatkan rincian tentang cara port Python2 ke Python3 pergi ke sana

Anda dapat menemukan beberapa detail tentang pengujian dari QGIS2 ke QGIS3 pada pertanyaan ini: Menulis tes otomatis untuk plugin QGIS?

Dan Anda akan menemukan makalah OpenGis.ch yang menarik di sini tentang alat migrasi.

Apa yang akan berubah menjadi kode saya

Bahkan, Anda perlu mengubah kode plugin yang tidak siap untuk melewati versi baru.

Anda mendapatkan fungsi qgis.utils.QGis.QGIS_VERSION_INT yang dibuat untuk memeriksa versi QGIS. Ini berguna ketika suatu fungsi tidak digunakan lagi. Contohnya setSelectedFeaturessejak 2.16.

Dengan mencontoh penggunaan ifpernyataan:

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

Itu sama tentang PyQtobjek yang Anda impor di bawah modul Anda. Jika Anda memerlukan kompatibilitas, harganya adalah menulis lebih banyak baris kode (kode dengan fungsi QGIS2 dan kode dengan fungsi QGIS3 DAN juga kode untuk memeriksa versi dan kemampuan untuk mengimpor perpustakaan baru).

Tentang pustaka PyQt

PyQt5 tidak kompatibel dengan PyQt4; ada beberapa perubahan signifikan pada PyQt5. Namun, tidak terlalu sulit untuk menyesuaikan kode lama ke perpustakaan baru. Perbedaannya antara lain sebagai berikut:

  • Modul python telah ditata ulang. Beberapa modul telah dijatuhkan (QtScript), yang lain telah dibagi menjadi submodula (QtGui, QtWebKit).

  • Modul baru telah diperkenalkan, termasuk QtBluetooth, QtPositioning, atau Enginio.

  • PyQt5 hanya mendukung sinyal dan slot gaya baru. Panggilan ke SIGNAL () atau SLOT () tidak lagi didukung. PyQt5 tidak mendukung bagian apa pun dari Qt API yang ditandai sebagai usang atau usang di Qt v5.0.

sumber: ( http://zetcode.com/gui/pyqt5/introduction/ )

Berikut ini beberapa contoh perubahan dari / dari pernyataan impor Anda:

Ingat dengan PyQt4 Anda harus melihat pada dokumen API:
untuk contoh
modul
PyQT4 QtCore modul PyQT4 QtGui

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

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

Dan dengan PyQt5 Anda sekarang harus melihat pada dokumen API tersebut:
Modul
PyQt5 QtCore Modul PyQt5 QtGui

sehingga menjadi:

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

Perhatikan bahwa:

Modul QtGui telah dipecah menjadi submodul. Modul QtGui berisi kelas-kelas untuk integrasi sistem windowing, penanganan acara, grafik 2D, pencitraan dasar, font dan teks. Ini juga mengandung satu set lengkap OpenGL dan OpenGL ES binding (lihat Dukungan untuk OpenGL ). Pengembang aplikasi biasanya akan menggunakan ini dengan API tingkat yang lebih tinggi seperti yang terdapat dalam modul QtWidgets.

Dan PyQt5 hanya mendukung sinyal dan slot gaya baru! lihat halaman ini untuk memahami cara menggunakan pyqtSignal, connectdan eobjek acara daripada menggunakan SIGNAL.

Buat itu kompatibel

Jadi dengan kompatibilitas antara PyQt4 / PyQt5 (dan QGIS2 / QGIS3 juga) Anda perlu mencoba / kecuali impor sebelum menggunakan librarie 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

Dan jangan lupa bahwa Anda perlu mengubah juga beberapa fungsi spesifik di bawah kode Anda dengan menambahkan pernyataan try / exception atau if.


2
Jawaban yang bagus, sesuatu yang akan sangat membantu adalah dengan mengganti from PyQt4.QtCore import *dengan from PyQt4.QtCore import QSomething, QWhatever, QElse, dengan ini akan membuat skrip migrasi melakukan langkah terakhir dengan benar (termasuk penyesuaian yang diperlukan ketika modul berubah), jadi tidak perlu dicoba kecuali impor diperlukan.
Matthias Kuhn

Anda benar, saya menggunakan * untuk membuatnya tetap sederhana, tetapi saya akan mengubahnya, terima kasih atas tanggapan Anda
Hugo Roussaffa - GeoDatup

topik ini adalah tempat yang tepat untuk memberi tahu orang-orang untuk tidak menggunakan * -import, karena di sini sebenarnya ada bedanya
Matthias Kuhn

@Hugo: Jawaban yang sangat rinci, sangat membantu untuk memulai. Saya akan menambahkan plugin qgis2compat ke banyak sumber daya bermanfaat yang telah dikutip.
sigeal

Itu ide bagus. Anda dapat mengedit jawabannya seperti yang Anda inginkan. Terima kasih atas umpan baliknya
Hugo Roussaffa - GeoDatup

2

Coba sesuatu seperti itu:

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

Ini mungkin bekerja untuk beberapa hal yang terisolasi tetapi seringkali tidak akan berfungsi sebagai solusi umum.
Matthias Kuhn

1

Saya baru saja selesai porting plugin QGIS Python sehingga sekarang mendukung versi QGIS 2.x dan 3.x. Inilah pengalaman saya:

Sebagian besar saya mencoba mengandalkan versi QGIS. Tetapi bahkan kelas yang memegang versi itu sedikit diganti namanya. Jadi saya pertama kali melakukannya

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

dan kemudian melakukan cek

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

Setelah menyebarkan versi final saya perhatikan bahwa file resources.pyyang dibuat secara otomatis olehpyrcc5 juga perlu porting. Kalau tidak, plugin akan terus mogok di 2.x. Jadi saya mengubah jalurnya

from PyQt5 import QtCore

untuk

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

Sepertinya berhasil. Saya membuat rilis resmi dan berpikir hanya itu. Baru kemudian saya menemukan urutan ini:

Instal plugin saya di QGIS 2.18, tutup QGIS, buka QGIS agan dan kemudian buka Python Console di dalam QGIS -> Seluruh QGIS akan langsung macet!

Setelah beberapa pengujian saya menemukan alasannya adalah perubahan kecil ini resources.pyditulis di atas. Saya bukan ahli dalam pustaka QGIS Python tetapi penjelasan saya adalah sebagai berikut:

Ketika saya membuka QGIS, plugin saya diinisialisasi. Upaya melakukan from PyQt5 import QtCoremenyebabkan beberapa perubahan dalam "alur kerja" QGIS sebelum versi PyQt yang salah memunculkan pengecualian (itu adalah RuntimeError). Ketika saya memulai Python Console, perubahan itu menyebabkan QGIS mogok.

Pada akhirnya saya memutuskan untuk solusi yang berbeda. Karena QGIS 2 menggunakan Python 2.7 dan QGIS 3 menggunakan Python 3, saya selalu memeriksa versi Python .

from sys import version_info

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

Ini menghindari semua upaya impor yang berpotensi berbahaya. Plugin saya sekarang berfungsi pada kedua versi QGIS tanpa masalah.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.