Tạo plugin python QGIS cho cả hai phiên bản 2.x và 3.x?


12

Tôi đang trong quá trình di chuyển một plugin QGIS python từ QGIS 2đến QGIS 3, và duyệt các nguồn lực khác nhau.

Không rõ liệu plugin có thể tương thích với cả hai phiên bản hay không, nếu cần hai phiên bản xử lý cho các phiên bản plugin.

Vấn đề tôi gặp phải cho đến nay là làm thế nào để quản lý nhập PyQt (PyQt4 / PyQt5)?

Câu trả lời:


18

Tài liệu

Tại đây bạn có thể tìm thấy những gì mới và những gì vi phạm trong API PyQGIS .
Để biết chi tiết về cách chuyển Python2 sang Python3, hãy truy cập vào đó

Bạn có thể tìm thấy một số chi tiết về thử nghiệm từ QGIS2 đến QGIS3 cho câu hỏi này: Viết thử nghiệm tự động cho các plugin QGIS?

Và bạn sẽ tìm thấy một bài báo thú vị của OpenGis.ch ở đây về các công cụ di chuyển.

Điều gì sẽ thay đổi vào mã của tôi

Trên thực tế, bạn cần thay đổi mã của plugin chưa được chuẩn bị để chuyển qua phiên bản mới.

Bạn nhận được hàm qgis.utils.QGis.QGIS_VERSION_INT được thực hiện để kiểm tra phiên bản QGIS. Điều này là hữu ích khi một chức năng không được chấp nhận. Ví dụ setSelectedFeaturestừ 2.16.

Bằng cách sử dụng ifcâu lệnh:

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

Nó giống nhau về PyQtđối tượng bạn nhập theo mô-đun của bạn. Nếu bạn cần khả năng tương thích, giá là để viết thêm dòng mã (mã có chức năng QGIS2 và mã có chức năng QGIS3 VÀ cũng là mã để kiểm tra phiên bản và khả năng nhập thư viện mới).

Giới thiệu về thư viện PyQt

PyQt5 không tương thích ngược với PyQt4; có một số thay đổi đáng kể trong PyQt5. Tuy nhiên, không khó để điều chỉnh mã cũ sang thư viện mới. Sự khác biệt là, trong số những người khác, như sau:

  • Các mô-đun Python đã được tổ chức lại. Một số mô-đun đã bị loại bỏ (QtScript), một số mô-đun khác đã được chia thành các mô hình con (QtGui, QtWebKit).

  • Các mô-đun mới đã được giới thiệu, bao gồm QtBluetooth, QtP vị trí hoặc Enginio.

  • PyQt5 chỉ hỗ trợ tín hiệu kiểu mới và handlig. Các cuộc gọi đến TÍN HIỆU () hoặc SLOT () không còn được hỗ trợ. PyQt5 không hỗ trợ bất kỳ phần nào của API Qt được đánh dấu là không dùng nữa hoặc lỗi thời trong Qt v5.0.

nguồn: ( http://zetcode.com/gui/pyqt5/int sinhtion / )

Dưới đây là một số ví dụ về các thay đổi trong câu lệnh from / import của bạn:

Hãy nhớ với PyQt4, bạn phải xem tài liệu của API:
ví dụ
mô-đun PyQT4 QtCore mô-đun
PyQT4 QtGui

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

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

Và với PyQt5, bây giờ bạn có thể xem tài liệu của các API đó:
mô-đun PyQt5 QtCore Mô-đun
PyQt5 QtGui

vì vậy mà trở thành:

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

Lưu ý rằng:

Mô-đun QtGui đã được chia thành các mô hình con. Mô-đun QtGui chứa các lớp để tích hợp hệ thống cửa sổ, xử lý sự kiện, đồ họa 2D, hình ảnh cơ bản, phông chữ và văn bản. Nó cũng chứa một bộ hoàn chỉnh các ràng buộc OpenGL và OpenGL ES (xem Hỗ trợ cho OpenGL ). Các nhà phát triển ứng dụng thường sử dụng điều này với các API cấp cao hơn, chẳng hạn như các API có trong mô-đun QtWidgets.

Và PyQt5 chỉ hỗ trợ tín hiệu kiểu mới và khe cắm handlig! có một cái nhìn trang này để hiểu làm thế nào để sử dụng pyqtSignal, connecteđối tượng sự kiện thay vì sử dụng SIGNAL.

Làm cho nó tương thích

Vì vậy, với khả năng tương thích giữa PyQt4 / PyQt5 (và cả QGIS2 / QGIS3), bạn cần thử / ngoại trừ việc nhập trước khi sử dụng 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

Và đừng quên rằng bạn cũng cần thay đổi một số chức năng cụ thể theo mã của mình bằng cách thêm câu lệnh try / trừ hoặc if.


2
Câu trả lời tuyệt vời, một điều sẽ giúp ích rất nhiều là trước tiên thay thế bất kỳ from PyQt4.QtCore import *bằng from PyQt4.QtCore import QSomething, QWhatever, QElse, điều này sẽ làm cho tập lệnh di chuyển thực hiện bước cuối cùng một cách chính xác (bao gồm các điều chỉnh cần thiết khi các mô-đun thay đổi), do đó không cần thử ngoại trừ nhập.
Matthias Kuhn

bạn đã đúng Tôi đã sử dụng * để giữ cho nó đơn giản, nhưng tôi sẽ thay đổi điều đó, cảm ơn phản hồi của bạn
Hugo Roussaffa - GeoDatup

chủ đề này là nơi hoàn hảo để nói với mọi người không sử dụng * -imports, bởi vì ở đây nó thực sự tạo ra sự khác biệt
Matthias Kuhn

@Hugo: Câu trả lời rất chi tiết thực sự, nó đã giúp rất nhiều để bắt đầu. Tôi sẽ thêm plugin qgis2compat vào nhiều tài nguyên hữu ích đã được trích dẫn.
sigeal

Đó là một ý kiến ​​tuyệt vời. Bạn có thể chỉnh sửa câu trả lời như bạn muốn. Cảm ơn phản hồi
Hugo Roussaffa - GeoDatup

2

Hãy thử một cái gì đó như thế:

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

Điều này có thể làm việc cho một số thứ bị cô lập nhưng thường sẽ không hoạt động như một giải pháp chung.
Matthias Kuhn

1

Tôi vừa hoàn thành việc chuyển một plugin QGIS Python để bây giờ nó hỗ trợ cả hai phiên bản QGIS 2.x và 3.x. Đây là kinh nghiệm của tôi:

Chủ yếu là tôi đã cố gắng dựa vào phiên bản QGIS. Nhưng ngay cả lớp giữ phiên bản cũng được đổi tên một chút. Vì vậy, lần đầu tiên tôi đã làm

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

và sau đó thực hiện kiểm tra

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

Sau khi triển khai phiên bản cuối cùng, tôi nhận thấy rằng một tệp resources.pyđược tạo tự động pyrcc5cũng cần phải được chuyển. Nếu không, plugin sẽ tiếp tục bị hỏng trong 2.x. Vì vậy, tôi đã thay đổi dòng của nó

from PyQt5 import QtCore

đến

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

Nó trông giống như nó làm việc. Tôi đã phát hành chính thức và nghĩ rằng đó là nó. Chỉ sau đó tôi mới phát hiện ra trình tự này:

Cài đặt plugin của tôi trong QGIS 2.18, đóng QGIS, mở agan QGIS và sau đó mở Python Console bên trong QGIS -> Toàn bộ QGIS sẽ bị sập ngay lập tức!

Sau một số thử nghiệm tôi đã tìm ra lý do là sự thay đổi nhỏ trong resources.pyvăn bản ở trên. Tôi không phải là chuyên gia trong các thư viện Python của QGIS nhưng lời giải thích của tôi là như sau:

Khi tôi mở QGIS, plugin của tôi sẽ được khởi tạo. Việc cố gắng thực hiện from PyQt5 import QtCoregây ra một số thay đổi trong "quy trình làm việc" của QGIS trước khi phiên bản PyQt sai gây ra ngoại lệ (đó là một RuntimeError). Khi tôi khởi động Bảng điều khiển Python, những thay đổi đó làm cho QGIS bị sập.

Cuối cùng, tôi quyết định cho một giải pháp khác. Vì QGIS 2 sử dụng Python 2.7 và QGIS 3 sử dụng Python 3 nên tôi chỉ đơn giản là luôn kiểm tra phiên bản Python .

from sys import version_info

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

Điều này tránh tất cả các nỗ lực nhập khẩu có hại. Plugin của tôi hiện hoạt động trên cả hai phiên bản QGIS mà không gặp vấn đề gì.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.