mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
this adds support to imports from the qgis.PyQt packages like from qgis.PyQt.QtGui import (QCheckBox, QIcon) this kind of imports are already used by some plugins without having the PyQt5 structure of packages (i.e. they use from qgis.PyQt.QtGui import (QCheckBox, QIcon) instead of from qgis.PyQt.QtGui import (QIcon) from qgis.PyQt.QtWidgets import (QCheckBox)
593 lines
18 KiB
Python
593 lines
18 KiB
Python
"""Migrate imports of PyQt4 to PyQt wrapper
|
|
"""
|
|
# Author: Juergen E. Fischer
|
|
# Adapted from fix_urllib
|
|
|
|
# Local imports
|
|
from lib2to3.fixes.fix_imports import alternates, FixImports
|
|
from lib2to3 import fixer_base
|
|
from lib2to3.fixer_util import (Name, Comma, FromImport, Newline,
|
|
find_indentation, Node, syms, Leaf)
|
|
|
|
MAPPING = {
|
|
"PyQt4.QtGui": [
|
|
("qgis.PyQt.QtGui", [
|
|
"QIcon",
|
|
"QCursor",
|
|
"QColor",
|
|
"QDesktopServices",
|
|
"QFont",
|
|
"QFontMetrics",
|
|
"QKeySequence",
|
|
"QStandardItemModel",
|
|
"QStandardItem",
|
|
"QClipboard",
|
|
"QPixmap",
|
|
"QDoubleValidator",
|
|
"QPainter",
|
|
"QPen",
|
|
"QBrush",
|
|
"QPalette",
|
|
"QPainterPath",
|
|
"QImage",
|
|
"QPolygonF",
|
|
"QFontMetricsF",
|
|
"QGradient",
|
|
"QIntValidator",
|
|
]),
|
|
("qgis.PyQt.QtWidgets", [
|
|
"QAbstractButton",
|
|
"QAbstractGraphicsShapeItem",
|
|
"QAbstractItemDelegate",
|
|
"QAbstractItemView",
|
|
"QAbstractScrollArea",
|
|
"QAbstractSlider",
|
|
"QAbstractSpinBox",
|
|
"QAbstractTableModel",
|
|
"QAction",
|
|
"QActionGroup",
|
|
"QApplication",
|
|
"QBoxLayout",
|
|
"QButtonGroup",
|
|
"QCalendarWidget",
|
|
"QCheckBox",
|
|
"QColorDialog",
|
|
"QColumnView",
|
|
"QComboBox",
|
|
"QCommandLinkButton",
|
|
"QCommonStyle",
|
|
"QCompleter",
|
|
"QDataWidgetMapper",
|
|
"QDateEdit",
|
|
"QDateTimeEdit",
|
|
"QDesktopWidget",
|
|
"QDial",
|
|
"QDialog",
|
|
"QDialogButtonBox",
|
|
"QDirModel",
|
|
"QDockWidget",
|
|
"QDoubleSpinBox",
|
|
"QErrorMessage",
|
|
"QFileDialog",
|
|
"QFileIconProvider",
|
|
"QFileSystemModel",
|
|
"QFocusFrame",
|
|
"QFontComboBox",
|
|
"QFontDialog",
|
|
"QFormLayout",
|
|
"QFrame",
|
|
"QGesture",
|
|
"QGestureEvent",
|
|
"QGestureRecognizer",
|
|
"QGraphicsAnchor",
|
|
"QGraphicsAnchorLayout",
|
|
"QGraphicsBlurEffect",
|
|
"QGraphicsColorizeEffect",
|
|
"QGraphicsDropShadowEffect",
|
|
"QGraphicsEffect",
|
|
"QGraphicsEllipseItem",
|
|
"QGraphicsGridLayout",
|
|
"QGraphicsItem",
|
|
"QGraphicsItemGroup",
|
|
"QGraphicsLayout",
|
|
"QGraphicsLayoutItem",
|
|
"QGraphicsLineItem",
|
|
"QGraphicsLinearLayout",
|
|
"QGraphicsObject",
|
|
"QGraphicsOpacityEffect",
|
|
"QGraphicsPathItem",
|
|
"QGraphicsPixmapItem",
|
|
"QGraphicsPolygonItem",
|
|
"QGraphicsProxyWidget",
|
|
"QGraphicsRectItem",
|
|
"QGraphicsRotation",
|
|
"QGraphicsScale",
|
|
"QGraphicsScene",
|
|
"QGraphicsSceneContextMenuEvent",
|
|
"QGraphicsSceneDragDropEvent",
|
|
"QGraphicsSceneEvent",
|
|
"QGraphicsSceneHelpEvent",
|
|
"QGraphicsSceneHoverEvent",
|
|
"QGraphicsSceneMouseEvent",
|
|
"QGraphicsSceneMoveEvent",
|
|
"QGraphicsSceneResizeEvent",
|
|
"QGraphicsSceneWheelEvent",
|
|
"QGraphicsSimpleTextItem",
|
|
"QGraphicsTextItem",
|
|
"QGraphicsTransform",
|
|
"QGraphicsView",
|
|
"QGraphicsWidget",
|
|
"QGridLayout",
|
|
"QGroupBox",
|
|
"QHBoxLayout",
|
|
"QHeaderView",
|
|
"QInputDialog",
|
|
"QItemDelegate",
|
|
"QItemEditorCreatorBase",
|
|
"QItemEditorFactory",
|
|
"QKeyEventTransition",
|
|
"QLCDNumber",
|
|
"QLabel",
|
|
"QLayout",
|
|
"QLayoutItem",
|
|
"QLineEdit",
|
|
"QListView",
|
|
"QListWidget",
|
|
"QListWidgetItem",
|
|
"QMainWindow",
|
|
"QMdiArea",
|
|
"QMdiSubWindow",
|
|
"QMenu",
|
|
"QMenuBar",
|
|
"QMessageBox",
|
|
"QMouseEventTransition",
|
|
"QPanGesture",
|
|
"QPinchGesture",
|
|
"QPlainTextDocumentLayout",
|
|
"QPlainTextEdit",
|
|
"QProgressBar",
|
|
"QProgressDialog",
|
|
"QPushButton",
|
|
"QRadioButton",
|
|
"QRubberBand",
|
|
"QScrollArea",
|
|
"QScrollBar",
|
|
"QShortcut",
|
|
"QSizeGrip",
|
|
"QSizePolicy",
|
|
"QSlider",
|
|
"QSpacerItem",
|
|
"QSpinBox",
|
|
"QSplashScreen",
|
|
"QSplitter",
|
|
"QSplitterHandle",
|
|
"QStackedLayout",
|
|
"QStackedWidget",
|
|
"QStatusBar",
|
|
"QStyle",
|
|
"QStyleFactory",
|
|
"QStyleHintReturn",
|
|
"QStyleHintReturnMask",
|
|
"QStyleHintReturnVariant",
|
|
"QStyleOption",
|
|
"QStyleOptionButton",
|
|
"QStyleOptionComboBox",
|
|
"QStyleOptionComplex",
|
|
"QStyleOptionDockWidget",
|
|
"QStyleOptionFocusRect",
|
|
"QStyleOptionFrame",
|
|
"QStyleOptionGraphicsItem",
|
|
"QStyleOptionGroupBox",
|
|
"QStyleOptionHeader",
|
|
"QStyleOptionMenuItem",
|
|
"QStyleOptionProgressBar",
|
|
"QStyleOptionRubberBand",
|
|
"QStyleOptionSizeGrip",
|
|
"QStyleOptionSlider",
|
|
"QStyleOptionSpinBox",
|
|
"QStyleOptionTab",
|
|
"QStyleOptionTabBarBase",
|
|
"QStyleOptionTabWidgetFrame",
|
|
"QStyleOptionTitleBar",
|
|
"QStyleOptionToolBar",
|
|
"QStyleOptionToolBox",
|
|
"QStyleOptionToolButton",
|
|
"QStyleOptionViewItem",
|
|
"QStylePainter",
|
|
"QStyledItemDelegate",
|
|
"QSwipeGesture",
|
|
"QSystemTrayIcon",
|
|
"QTabBar",
|
|
"QTabWidget",
|
|
"QTableView",
|
|
"QTableWidget",
|
|
"QTableWidgetItem",
|
|
"QTableWidgetSelectionRange",
|
|
"QTapAndHoldGesture",
|
|
"QTapGesture",
|
|
"QTextBrowser",
|
|
"QTextEdit",
|
|
"QTimeEdit",
|
|
"QToolBar",
|
|
"QToolBox",
|
|
"QToolButton",
|
|
"QToolTip",
|
|
"QTreeView",
|
|
"QTreeWidget",
|
|
"QTreeWidgetItem",
|
|
"QTreeWidgetItemIterator",
|
|
"QUndoCommand",
|
|
"QUndoGroup",
|
|
"QUndoStack",
|
|
"QUndoView",
|
|
"QVBoxLayout",
|
|
"QWhatsThis",
|
|
"QWidget",
|
|
"QWidgetAction",
|
|
"QWidgetItem",
|
|
"QWizard",
|
|
"QWizardPage",
|
|
"qApp",
|
|
"qDrawBorderPixmap",
|
|
"qDrawPlainRect",
|
|
"qDrawShadeLine",
|
|
"qDrawShadePanel",
|
|
"qDrawShadeRect",
|
|
"qDrawWinButton",
|
|
"qDrawWinPanel",
|
|
]),
|
|
("qgis.PyQt.QtPrintSupport", [
|
|
"QPrinter",
|
|
"QAbstractPrintDialog",
|
|
"QPageSetupDialog",
|
|
"QPrintDialog",
|
|
"QPrintEngine",
|
|
"QPrintPreviewDialog",
|
|
"QPrintPreviewWidget",
|
|
"QPrinterInfo",
|
|
]),
|
|
("qgis.PyQt.QtCore", [
|
|
"QItemSelectionModel",
|
|
"QSortFilterProxyModel",
|
|
]),
|
|
],
|
|
"PyQt4.QtCore": [
|
|
("qgis.PyQt.QtCore", [
|
|
"QAbstractItemModel",
|
|
"QAbstractTableModel",
|
|
"QByteArray",
|
|
"QCoreApplication",
|
|
"QDataStream",
|
|
"QDir",
|
|
"QEvent",
|
|
"QFile",
|
|
"QFileInfo",
|
|
"QIODevice",
|
|
"QLocale",
|
|
"QMimeData",
|
|
"QModelIndex",
|
|
"QMutex",
|
|
"QObject",
|
|
"QProcess",
|
|
"QSettings",
|
|
"QSize",
|
|
"QSizeF",
|
|
"QTextCodec",
|
|
"QThread",
|
|
"QThreadPool",
|
|
"QTimer",
|
|
"QTranslator",
|
|
"QUrl",
|
|
"Qt",
|
|
"pyqtProperty",
|
|
"pyqtWrapperType",
|
|
"pyqtSignal",
|
|
"pyqtSlot",
|
|
"qDebug",
|
|
"qWarning",
|
|
"qVersion",
|
|
"QDate",
|
|
"QTime",
|
|
"QDateTime",
|
|
"QRegExp",
|
|
"QTemporaryFile",
|
|
"QTextStream",
|
|
"QVariant",
|
|
"QPyNullVariant",
|
|
"QRect",
|
|
"QRectF",
|
|
"QMetaObject",
|
|
"QPoint",
|
|
"QPointF",
|
|
"QDirIterator",
|
|
"QEventLoop",
|
|
"NULL",
|
|
]),
|
|
(None, [
|
|
"SIGNAL",
|
|
"SLOT",
|
|
]),
|
|
],
|
|
"PyQt4.QtNetwork": [
|
|
("qgis.PyQt.QtNetwork", [
|
|
"QNetworkReply",
|
|
"QNetworkRequest",
|
|
"QSslCertificate",
|
|
"QSslKey",
|
|
"QSsl"
|
|
])
|
|
],
|
|
"PyQt4.QtXml": [
|
|
("qgis.PyQt.QtXml", [
|
|
"QDomDocument"
|
|
]),
|
|
],
|
|
"PyQt4.Qsci": [
|
|
("qgis.PyQt.Qsci", [
|
|
"QsciAPIs",
|
|
"QsciLexerCustom",
|
|
"QsciLexerPython",
|
|
"QsciScintilla",
|
|
"QsciLexerSQL",
|
|
"QsciStyle",
|
|
]),
|
|
],
|
|
"PyQt4.QtWebKit": [
|
|
("qgis.PyQt.QtWebKitWidgets", [
|
|
"QGraphicsWebView",
|
|
"QWebFrame",
|
|
"QWebHitTestResult",
|
|
"QWebInspector",
|
|
"QWebPage",
|
|
"QWebView",
|
|
]),
|
|
],
|
|
"PyQt4.QtTest": [
|
|
("qgis.PyQt.QtTest", [
|
|
"QTest",
|
|
]),
|
|
],
|
|
"PyQt4.QtSvg": [
|
|
("qgis.PyQt.QtSvg", [
|
|
"QSvgRenderer",
|
|
"QSvgGenerator"
|
|
]),
|
|
],
|
|
"PyQt4.QtSql": [
|
|
("qgis.PyQt.QtSql", [
|
|
"QSqlDatabase",
|
|
"QSqlQuery",
|
|
"QSqlField"
|
|
]),
|
|
],
|
|
"PyQt4.uic": [
|
|
("qgis.PyQt.uic", [
|
|
"loadUiType",
|
|
"loadUi",
|
|
]),
|
|
],
|
|
"PyQt4": [
|
|
("qgis.PyQt", [
|
|
"QtCore",
|
|
"QtGui",
|
|
"QtNetwork",
|
|
"QtXml",
|
|
"QtWebkit",
|
|
"QtSql",
|
|
"QtSvg",
|
|
"Qsci",
|
|
"uic",
|
|
])
|
|
],
|
|
}
|
|
|
|
|
|
new_mappings = {}
|
|
for key, value in MAPPING.items():
|
|
match_str = key.replace('PyQt4', '')
|
|
match_str = '{}{}'.format('qgis.PyQt', match_str)
|
|
new_mappings[match_str] = value
|
|
|
|
MAPPING.update(new_mappings)
|
|
|
|
|
|
def build_pattern():
|
|
bare = set()
|
|
for old_module, changes in list(MAPPING.items()):
|
|
for change in changes:
|
|
new_module, members = change
|
|
members = alternates(members)
|
|
|
|
if '.' not in old_module:
|
|
from_name = "%r" % old_module
|
|
|
|
else:
|
|
dotted = old_module.split('.')
|
|
if len(dotted) == 3:
|
|
from_name = "dotted_name<%r '.' %r '.' %r>" % (dotted[0], dotted[1], dotted[2])
|
|
else:
|
|
assert len(dotted) == 2
|
|
from_name = "dotted_name<%r '.' %r>" % (dotted[0], dotted[1])
|
|
|
|
yield """import_name< 'import' (module=%s
|
|
| dotted_as_names< any* module=%s any* >) >
|
|
""" % (from_name, from_name)
|
|
yield """import_from< 'from' mod_member=%s 'import'
|
|
( member=%s | import_as_name< member=%s 'as' any > |
|
|
import_as_names< members=any* >) >
|
|
""" % (from_name, members, members)
|
|
yield """import_from< 'from' mod_member=%s 'import' '('
|
|
( member=%s | import_as_name< member=%s 'as' any > |
|
|
import_as_names< members=any* >) ')' >
|
|
""" % (from_name, members, members)
|
|
yield """import_from< 'from' module_star=%s 'import' star='*' >
|
|
""" % from_name
|
|
yield """import_name< 'import'
|
|
dotted_as_name< module_as=%s 'as' any > >
|
|
""" % from_name
|
|
# bare_with_attr has a special significance for FixImports.match().
|
|
yield """power< bare_with_attr=%s trailer< '.' member=%s > any* >
|
|
""" % (from_name, members)
|
|
|
|
|
|
class FixPyqt(FixImports):
|
|
|
|
def build_pattern(self):
|
|
return "|".join(build_pattern())
|
|
|
|
# def match(self, node):
|
|
# res = super(FixImports, self).match( node )
|
|
# print repr(node)
|
|
# return res
|
|
|
|
def transform_import(self, node, results):
|
|
"""Transform for the basic import case. Replaces the old
|
|
import name with a comma separated list of its
|
|
replacements.
|
|
"""
|
|
import_mod = results.get("module")
|
|
pref = import_mod.prefix
|
|
|
|
names = []
|
|
|
|
if isinstance(import_mod, Leaf):
|
|
# create a Node list of the replacement modules
|
|
for name in MAPPING[import_mod.value][:-1]:
|
|
names.extend([Name(name[0], prefix=pref), Comma()])
|
|
names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref))
|
|
import_mod.replace(names)
|
|
else:
|
|
self.cannot_convert(node, "imports like PyQt4.QtGui or import qgis.PyQt.QtGui are not supported")
|
|
|
|
def transform_member(self, node, results):
|
|
"""Transform for imports of specific module elements. Replaces
|
|
the module to be imported from with the appropriate new
|
|
module.
|
|
"""
|
|
mod_member = results.get("mod_member")
|
|
if isinstance(mod_member, Node):
|
|
module = ""
|
|
for l in mod_member.leaves():
|
|
module += l.value
|
|
mod_member.value = module
|
|
pref = mod_member.prefix
|
|
member = results.get("member")
|
|
|
|
missing = False
|
|
|
|
# Simple case with only a single member being imported
|
|
if member:
|
|
# this may be a list of length one, or just a node
|
|
if isinstance(member, list):
|
|
member = member[0]
|
|
new_name = ''
|
|
for change in MAPPING[mod_member.value]:
|
|
if member.value in change[1]:
|
|
new_name = change[0]
|
|
break
|
|
if new_name:
|
|
mod_member.replace(Name(new_name, prefix=pref))
|
|
elif new_name == '':
|
|
self.cannot_convert(node, "This is an invalid module element")
|
|
else:
|
|
node.remove()
|
|
|
|
# Multiple members being imported
|
|
else:
|
|
# a dictionary for replacements, order matters
|
|
modules = []
|
|
mod_dict = {}
|
|
members = results["members"]
|
|
for member in members:
|
|
# we only care about the actual members
|
|
if member.type == syms.import_as_name:
|
|
as_name = member.children[2].value
|
|
member_name = member.children[0].value
|
|
else:
|
|
member_name = member.value
|
|
as_name = None
|
|
if member_name != u",":
|
|
found = False
|
|
for change in MAPPING[mod_member.value]:
|
|
if member_name in change[1]:
|
|
if change[0] is not None:
|
|
if change[0] not in mod_dict:
|
|
modules.append(change[0])
|
|
mod_dict.setdefault(change[0], []).append(member)
|
|
found = True
|
|
if not found:
|
|
f = open("/tmp/missing", "a+")
|
|
f.write("member %s of %s not found\n" % (member_name, mod_member.value))
|
|
f.close()
|
|
missing = True
|
|
|
|
new_nodes = []
|
|
indentation = find_indentation(node)
|
|
first = True
|
|
|
|
def handle_name(name, prefix):
|
|
if name.type == syms.import_as_name:
|
|
kids = [Name(name.children[0].value, prefix=prefix),
|
|
name.children[1].clone(),
|
|
name.children[2].clone()]
|
|
return [Node(syms.import_as_name, kids)]
|
|
return [Name(name.value, prefix=prefix)]
|
|
|
|
for module in modules:
|
|
elts = mod_dict[module]
|
|
names = []
|
|
for elt in elts[:-1]:
|
|
names.extend(handle_name(elt, pref))
|
|
names.append(Comma())
|
|
names.extend(handle_name(elts[-1], pref))
|
|
new = FromImport(module, names)
|
|
if not first or node.parent.prefix.endswith(indentation):
|
|
new.prefix = indentation
|
|
new_nodes.append(new)
|
|
first = False
|
|
|
|
if new_nodes:
|
|
nodes = []
|
|
for new_node in new_nodes[:-1]:
|
|
nodes.extend([new_node, Newline()])
|
|
nodes.append(new_nodes[-1])
|
|
|
|
if node.prefix:
|
|
nodes[0].prefix = node.prefix
|
|
|
|
node.replace(nodes)
|
|
elif missing:
|
|
self.cannot_convert(node, "All module elements are invalid")
|
|
else:
|
|
node.remove()
|
|
|
|
def transform_dot(self, node, results):
|
|
"""Transform for calls to module members in code."""
|
|
module_dot = results.get("bare_with_attr")
|
|
member = results.get("member")
|
|
new_name = None
|
|
if isinstance(member, list):
|
|
member = member[0]
|
|
for change in MAPPING[module_dot.value]:
|
|
if member.value in change[1]:
|
|
new_name = change[0]
|
|
break
|
|
if new_name:
|
|
module_dot.replace(Name(new_name,
|
|
prefix=module_dot.prefix))
|
|
else:
|
|
self.cannot_convert(node, "This is an invalid module element")
|
|
|
|
def transform(self, node, results):
|
|
if results.get("module"):
|
|
self.transform_import(node, results)
|
|
elif results.get("mod_member"):
|
|
self.transform_member(node, results)
|
|
elif results.get("bare_with_attr"):
|
|
self.transform_dot(node, results)
|
|
# Renaming and star imports are not supported for these modules.
|
|
elif results.get("module_star"):
|
|
self.cannot_convert(node, "Cannot handle star imports.")
|
|
elif results.get("module_as"):
|
|
self.cannot_convert(node, "This module is now multiple modules")
|