Skip to content

Commit

Permalink
pyqt5to6: raise warnings on fragile addAction calls
Browse files Browse the repository at this point in the history
The object.addAction variants with multiple arguments have changed
signature in Qt 6. It's safer to explicitly create a QAction first
and then add to an object using:

    my_action=QAction(...)
    obj.addAction(my_action)

It's a considerably less fragile syntax to use in any case!

Fixes errors when trying to show context menu in Python console
on Qt 6 builds
  • Loading branch information
nyalldawson committed Jan 31, 2024
1 parent c95df01 commit 310b917
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 60 deletions.
123 changes: 87 additions & 36 deletions python/console/console_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from qgis.PyQt.QtGui import QKeySequence
from qgis.PyQt.QtNetwork import QNetworkRequest
from qgis.PyQt.QtWidgets import (
QAction,
QApplication,
QFileDialog,
QFrame,
Expand Down Expand Up @@ -104,46 +105,96 @@ def contextMenuEvent(self, e):
menu.addAction(
QCoreApplication.translate("PythonConsole", "Hide Editor"),
self.hideEditor)
menu.addSeparator() # ------------------------------
syntaxCheckAction = menu.addAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Check Syntax"),
self.syntaxCheck, 'Ctrl+4')
runSelected = menu.addAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok
QCoreApplication.translate("PythonConsole", "Run Selected"),
self.runSelectedCode, 'Ctrl+E') # spellok
pyQGISHelpAction = menu.addAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
self.searchSelectedTextInPyQGISDocs)
menu.addAction(QgsApplication.getThemeIcon("mActionStart.svg"),
QCoreApplication.translate("PythonConsole", "Run Script"),
self.runScriptCode, 'Ctrl+Shift+E')
menu.addSeparator()
undoAction = menu.addAction(QgsApplication.getThemeIcon("mActionUndo.svg"),
QCoreApplication.translate("PythonConsole", "Undo"),
self.undo, QKeySequence.StandardKey.Undo)
redoAction = menu.addAction(QgsApplication.getThemeIcon("mActionRedo.svg"),
QCoreApplication.translate("PythonConsole", "Redo"),
self.redo, 'Ctrl+Shift+Z')

syntaxCheckAction = QAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Check Syntax"),
menu)
syntaxCheckAction.triggered.connect(self.syntaxCheck)
syntaxCheckAction.setShortcut('Ctrl+4')
menu.addAction(syntaxCheckAction)

runSelected = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok
QCoreApplication.translate("PythonConsole", "Run Selected"),
menu)
runSelected.triggered.connect(self.runSelectedCode) # spellok
runSelected.setShortcut('Ctrl+E') # spellok
menu.addAction(runSelected) # spellok

pyQGISHelpAction = QAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
menu)
pyQGISHelpAction.triggered.connect(self.searchSelectedTextInPyQGISDocs)
menu.addAction(pyQGISHelpAction)

start_action = QAction(QgsApplication.getThemeIcon("mActionStart.svg"),
QCoreApplication.translate("PythonConsole", "Run Script"),
menu)
start_action.triggered.connect(self.runScriptCode)
start_action.setShortcut('Ctrl+Shift+E')
menu.addAction(start_action)

menu.addSeparator()
undoAction = QAction(QgsApplication.getThemeIcon("mActionUndo.svg"),
QCoreApplication.translate("PythonConsole", "Undo"),
menu)
undoAction.triggered.connect(self.undo)
undoAction.setShortcut(QKeySequence.StandardKey.Undo)
menu.addAction(undoAction)

redoAction = QAction(QgsApplication.getThemeIcon("mActionRedo.svg"),
QCoreApplication.translate("PythonConsole", "Redo"),
menu)
redoAction.triggered.connect(self.redo)
redoAction.setShortcut('Ctrl+Shift+Z')
menu.addAction(redoAction)

menu.addSeparator()
menu.addAction(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Find Text"),
self.openFindWidget)
cutAction = menu.addAction(QgsApplication.getThemeIcon("mActionEditCut.svg"),
QCoreApplication.translate("PythonConsole", "Cut"),
self.cut, QKeySequence.StandardKey.Cut)
copyAction = menu.addAction(QgsApplication.getThemeIcon("mActionEditCopy.svg"),
QCoreApplication.translate("PythonConsole", "Copy"),
self.copy, QKeySequence.StandardKey.Copy)
pasteAction = menu.addAction(QgsApplication.getThemeIcon("mActionEditPaste.svg"),
QCoreApplication.translate("PythonConsole", "Paste"),
self.paste, QKeySequence.StandardKey.Paste)
selectAllAction = menu.addAction(
find_action = QAction(
QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Find Text"),
menu)
find_action.triggered.connect(self.openFindWidget)
menu.addAction(find_action)

cutAction = QAction(
QgsApplication.getThemeIcon("mActionEditCut.svg"),
QCoreApplication.translate("PythonConsole", "Cut"),
menu)
cutAction.triggered.connect(self.cut)
cutAction.setShortcut(QKeySequence.StandardKey.Cut)
menu.addAction(cutAction)

copyAction = QAction(QgsApplication.getThemeIcon("mActionEditCopy.svg"),
QCoreApplication.translate("PythonConsole", "Copy"),
menu)
copyAction.triggered.connect(self.copy)
copyAction.setShortcut(QKeySequence.StandardKey.Copy)
menu.addAction(copyAction)

pasteAction = QAction(QgsApplication.getThemeIcon("mActionEditPaste.svg"),
QCoreApplication.translate("PythonConsole", "Paste"),
menu)
pasteAction.triggered.connect(self.paste)
pasteAction.setShortcut(QKeySequence.StandardKey.Paste)
menu.addAction(pasteAction)

selectAllAction = QAction(
QCoreApplication.translate("PythonConsole", "Select All"),
self.selectAll, QKeySequence.StandardKey.SelectAll)
menu)
selectAllAction.triggered.connect(self.selectAll)
selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll)
menu.addAction(selectAllAction)

menu.addSeparator()
menu.addAction(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Toggle Comment"),
self.toggleComment, 'Ctrl+:')
toggle_comment_action = QAction(
QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"),
QCoreApplication.translate("PythonConsole", "Toggle Comment"),
menu)
toggle_comment_action.triggered.connect(self.toggleComment)
toggle_comment_action.setShortcut('Ctrl+:')
menu.addAction(toggle_comment_action)

menu.addSeparator()
gist_menu = QMenu(self)
gist_menu.setTitle(QCoreApplication.translate("PythonConsole", "Share on GitHub"))
Expand Down
56 changes: 38 additions & 18 deletions python/console/console_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from qgis.PyQt import sip
from qgis.PyQt.QtCore import Qt, QCoreApplication, QThread, QMetaObject, Q_ARG, QObject, pyqtSlot
from qgis.PyQt.QtGui import QColor, QKeySequence
from qgis.PyQt.QtWidgets import QGridLayout, QSpacerItem, QSizePolicy, QShortcut, QMenu, QApplication
from qgis.PyQt.QtWidgets import QAction, QGridLayout, QSpacerItem, QSizePolicy, QShortcut, QMenu, QApplication
from qgis.PyQt.Qsci import QsciScintilla
from qgis.core import Qgis, QgsApplication, QgsSettings
from qgis.gui import QgsMessageBar, QgsCodeEditorPython
Expand Down Expand Up @@ -217,28 +217,48 @@ def contextMenuEvent(self, e):
QCoreApplication.translate("PythonConsole", "Show Editor"),
self.showEditor)
menu.addSeparator()
runAction = menu.addAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"),
QCoreApplication.translate("PythonConsole", "Enter Selected"),
self.enteredSelected,
QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E))
clearAction = menu.addAction(QgsApplication.getThemeIcon("console/iconClearConsole.svg"),
QCoreApplication.translate("PythonConsole", "Clear Console"),
self.clearConsole)
pyQGISHelpAction = menu.addAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
self.searchSelectedTextInPyQGISDocs)
runAction = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"),
QCoreApplication.translate("PythonConsole", "Enter Selected"),
menu)
runAction.triggered.connect(self.enteredSelected)
runAction.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E))
menu.addAction(runAction)

clearAction = QAction(QgsApplication.getThemeIcon("console/iconClearConsole.svg"),
QCoreApplication.translate("PythonConsole", "Clear Console"),
menu)
clearAction.triggered.connect(self.clearConsole)
menu.addAction(clearAction)

pyQGISHelpAction = QAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
menu)
pyQGISHelpAction.triggered.connect(self.searchSelectedTextInPyQGISDocs)
menu.addAction(pyQGISHelpAction)

menu.addSeparator()
copyAction = menu.addAction(
copyAction = QAction(
QgsApplication.getThemeIcon("mActionEditCopy.svg"),
QCoreApplication.translate("PythonConsole", "Copy"),
self.copy, QKeySequence.StandardKey.Copy)
selectAllAction = menu.addAction(
menu)
copyAction.triggered.connect(self.copy)
copyAction.setShortcut(QKeySequence.StandardKey.Copy)
menu.addAction(copyAction)

selectAllAction = QAction(
QCoreApplication.translate("PythonConsole", "Select All"),
self.selectAll, QKeySequence.StandardKey.SelectAll)
menu)
selectAllAction.triggered.connect(self.selectAll)
selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll)
menu.addAction(selectAllAction)

menu.addSeparator()
menu.addAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
QCoreApplication.translate("PythonConsole", "Options…"),
self.parent.openSettings)
settings_action = QAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
QCoreApplication.translate("PythonConsole", "Options…"),
menu)
settings_action.triggered.connect(self.parent.openSettings)
menu.addAction(settings_action)

runAction.setEnabled(False)
clearAction.setEnabled(False)
copyAction.setEnabled(False)
Expand Down
24 changes: 18 additions & 6 deletions python/plugins/db_manager/db_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import functools

from qgis.PyQt.QtCore import Qt, QByteArray, QSize
from qgis.PyQt.QtWidgets import QMainWindow, QApplication, QMenu, QTabWidget, QGridLayout, QSpacerItem, QSizePolicy, QDockWidget, QStatusBar, QMenuBar, QToolBar, QTabBar
from qgis.PyQt.QtWidgets import QAction, QMainWindow, QApplication, QMenu, QTabWidget, QGridLayout, QSpacerItem, QSizePolicy, QDockWidget, QStatusBar, QMenuBar, QToolBar, QTabBar
from qgis.PyQt.QtGui import QIcon, QKeySequence

from qgis.gui import QgsMessageBar
Expand Down Expand Up @@ -451,12 +451,24 @@ def setupUi(self):
sep.setObjectName("DB_Manager_DbMenu_placeholder")
sep.setVisible(False)

self.actionRefresh = self.menuDb.addAction(QgsApplication.getThemeIcon("/mActionRefresh.svg"), self.tr("&Refresh"),
self.refreshActionSlot, QKeySequence("F5"))
self.actionSqlWindow = self.menuDb.addAction(QIcon(":/db_manager/actions/sql_window"), self.tr("&SQL Window"),
self.runSqlWindow, QKeySequence("F2"))
self.actionRefresh = QAction(QgsApplication.getThemeIcon("/mActionRefresh.svg"), self.tr("&Refresh"),
self.menuDb)
self.actionRefresh.triggered.connect(self.refreshActionSlot)
self.actionRefresh.setShortcut(QKeySequence("F5"))
self.menuDb.addAction(self.actionRefresh)

self.actionSqlWindow = QAction(QIcon(":/db_manager/actions/sql_window"), self.tr("&SQL Window"),
self.menuDb)
self.actionSqlWindow.triggered.connect(self.runSqlWindow)
self.actionSqlWindow.setShortcut(QKeySequence("F2"))
self.menuDb.addAction(self.actionSqlWindow)

self.menuDb.addSeparator()
self.actionClose = self.menuDb.addAction(QIcon(), self.tr("&Exit"), self.close, QKeySequence("CTRL+Q"))

self.actionClose = QAction(QIcon(), self.tr("&Exit"), self.menuDb)
self.actionClose.triggered.connect(self.close)
self.actionClose.setShortcut(QKeySequence("CTRL+Q"))
self.menuDb.addAction(self.actionClose)

# menu SCHEMA
sep = self.menuSchema.addSeparator()
Expand Down
4 changes: 4 additions & 0 deletions scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ def visit_call(_node: ast.Call, _parent):
Offset(_node.func.lineno, attr_node.end_col_offset - len(
_node.func.attr) - 1)] = rename_function_attributes[
_node.func.attr]
if _node.func.attr == 'addAction':
if len(_node.args) >= 4:
sys.stderr.write(
f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: fragile call to addAction. Use my_action = QAction(...), obj.addAction(my_action) instead.\n')

if isinstance(_node.func, ast.Name) and _node.func.id == 'QDateTime':
if len(_node.args) == 8:
Expand Down

0 comments on commit 310b917

Please sign in to comment.