Skip to content

Commit 2f6f1b1

Browse files
committed
pyqt5to6: raise warnings on fragile addAction calls
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
1 parent dbc621e commit 2f6f1b1

File tree

4 files changed

+147
-60
lines changed

4 files changed

+147
-60
lines changed

python/console/console_editor.py

+87-36
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from qgis.PyQt.QtGui import QKeySequence
3838
from qgis.PyQt.QtNetwork import QNetworkRequest
3939
from qgis.PyQt.QtWidgets import (
40+
QAction,
4041
QApplication,
4142
QFileDialog,
4243
QFrame,
@@ -104,46 +105,96 @@ def contextMenuEvent(self, e):
104105
menu.addAction(
105106
QCoreApplication.translate("PythonConsole", "Hide Editor"),
106107
self.hideEditor)
107-
menu.addSeparator() # ------------------------------
108-
syntaxCheckAction = menu.addAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"),
109-
QCoreApplication.translate("PythonConsole", "Check Syntax"),
110-
self.syntaxCheck, 'Ctrl+4')
111-
runSelected = menu.addAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok
112-
QCoreApplication.translate("PythonConsole", "Run Selected"),
113-
self.runSelectedCode, 'Ctrl+E') # spellok
114-
pyQGISHelpAction = menu.addAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
115-
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
116-
self.searchSelectedTextInPyQGISDocs)
117-
menu.addAction(QgsApplication.getThemeIcon("mActionStart.svg"),
118-
QCoreApplication.translate("PythonConsole", "Run Script"),
119-
self.runScriptCode, 'Ctrl+Shift+E')
120108
menu.addSeparator()
121-
undoAction = menu.addAction(QgsApplication.getThemeIcon("mActionUndo.svg"),
122-
QCoreApplication.translate("PythonConsole", "Undo"),
123-
self.undo, QKeySequence.StandardKey.Undo)
124-
redoAction = menu.addAction(QgsApplication.getThemeIcon("mActionRedo.svg"),
125-
QCoreApplication.translate("PythonConsole", "Redo"),
126-
self.redo, 'Ctrl+Shift+Z')
109+
110+
syntaxCheckAction = QAction(QgsApplication.getThemeIcon("console/iconSyntaxErrorConsole.svg"),
111+
QCoreApplication.translate("PythonConsole", "Check Syntax"),
112+
menu)
113+
syntaxCheckAction.triggered.connect(self.syntaxCheck)
114+
syntaxCheckAction.setShortcut('Ctrl+4')
115+
menu.addAction(syntaxCheckAction)
116+
117+
runSelected = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"), # spellok
118+
QCoreApplication.translate("PythonConsole", "Run Selected"),
119+
menu)
120+
runSelected.triggered.connect(self.runSelectedCode) # spellok
121+
runSelected.setShortcut('Ctrl+E') # spellok
122+
menu.addAction(runSelected) # spellok
123+
124+
pyQGISHelpAction = QAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
125+
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
126+
menu)
127+
pyQGISHelpAction.triggered.connect(self.searchSelectedTextInPyQGISDocs)
128+
menu.addAction(pyQGISHelpAction)
129+
130+
start_action = QAction(QgsApplication.getThemeIcon("mActionStart.svg"),
131+
QCoreApplication.translate("PythonConsole", "Run Script"),
132+
menu)
133+
start_action.triggered.connect(self.runScriptCode)
134+
start_action.setShortcut('Ctrl+Shift+E')
135+
menu.addAction(start_action)
136+
137+
menu.addSeparator()
138+
undoAction = QAction(QgsApplication.getThemeIcon("mActionUndo.svg"),
139+
QCoreApplication.translate("PythonConsole", "Undo"),
140+
menu)
141+
undoAction.triggered.connect(self.undo)
142+
undoAction.setShortcut(QKeySequence.StandardKey.Undo)
143+
menu.addAction(undoAction)
144+
145+
redoAction = QAction(QgsApplication.getThemeIcon("mActionRedo.svg"),
146+
QCoreApplication.translate("PythonConsole", "Redo"),
147+
menu)
148+
redoAction.triggered.connect(self.redo)
149+
redoAction.setShortcut('Ctrl+Shift+Z')
150+
menu.addAction(redoAction)
151+
127152
menu.addSeparator()
128-
menu.addAction(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"),
129-
QCoreApplication.translate("PythonConsole", "Find Text"),
130-
self.openFindWidget)
131-
cutAction = menu.addAction(QgsApplication.getThemeIcon("mActionEditCut.svg"),
132-
QCoreApplication.translate("PythonConsole", "Cut"),
133-
self.cut, QKeySequence.StandardKey.Cut)
134-
copyAction = menu.addAction(QgsApplication.getThemeIcon("mActionEditCopy.svg"),
135-
QCoreApplication.translate("PythonConsole", "Copy"),
136-
self.copy, QKeySequence.StandardKey.Copy)
137-
pasteAction = menu.addAction(QgsApplication.getThemeIcon("mActionEditPaste.svg"),
138-
QCoreApplication.translate("PythonConsole", "Paste"),
139-
self.paste, QKeySequence.StandardKey.Paste)
140-
selectAllAction = menu.addAction(
153+
find_action = QAction(
154+
QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg"),
155+
QCoreApplication.translate("PythonConsole", "Find Text"),
156+
menu)
157+
find_action.triggered.connect(self.openFindWidget)
158+
menu.addAction(find_action)
159+
160+
cutAction = QAction(
161+
QgsApplication.getThemeIcon("mActionEditCut.svg"),
162+
QCoreApplication.translate("PythonConsole", "Cut"),
163+
menu)
164+
cutAction.triggered.connect(self.cut)
165+
cutAction.setShortcut(QKeySequence.StandardKey.Cut)
166+
menu.addAction(cutAction)
167+
168+
copyAction = QAction(QgsApplication.getThemeIcon("mActionEditCopy.svg"),
169+
QCoreApplication.translate("PythonConsole", "Copy"),
170+
menu)
171+
copyAction.triggered.connect(self.copy)
172+
copyAction.setShortcut(QKeySequence.StandardKey.Copy)
173+
menu.addAction(copyAction)
174+
175+
pasteAction = QAction(QgsApplication.getThemeIcon("mActionEditPaste.svg"),
176+
QCoreApplication.translate("PythonConsole", "Paste"),
177+
menu)
178+
pasteAction.triggered.connect(self.paste)
179+
pasteAction.setShortcut(QKeySequence.StandardKey.Paste)
180+
menu.addAction(pasteAction)
181+
182+
selectAllAction = QAction(
141183
QCoreApplication.translate("PythonConsole", "Select All"),
142-
self.selectAll, QKeySequence.StandardKey.SelectAll)
184+
menu)
185+
selectAllAction.triggered.connect(self.selectAll)
186+
selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll)
187+
menu.addAction(selectAllAction)
188+
143189
menu.addSeparator()
144-
menu.addAction(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"),
145-
QCoreApplication.translate("PythonConsole", "Toggle Comment"),
146-
self.toggleComment, 'Ctrl+:')
190+
toggle_comment_action = QAction(
191+
QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"),
192+
QCoreApplication.translate("PythonConsole", "Toggle Comment"),
193+
menu)
194+
toggle_comment_action.triggered.connect(self.toggleComment)
195+
toggle_comment_action.setShortcut('Ctrl+:')
196+
menu.addAction(toggle_comment_action)
197+
147198
menu.addSeparator()
148199
gist_menu = QMenu(self)
149200
gist_menu.setTitle(QCoreApplication.translate("PythonConsole", "Share on GitHub"))

python/console/console_output.py

+38-18
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from qgis.PyQt import sip
2323
from qgis.PyQt.QtCore import Qt, QCoreApplication, QThread, QMetaObject, Q_ARG, QObject, pyqtSlot
2424
from qgis.PyQt.QtGui import QColor, QKeySequence
25-
from qgis.PyQt.QtWidgets import QGridLayout, QSpacerItem, QSizePolicy, QShortcut, QMenu, QApplication
25+
from qgis.PyQt.QtWidgets import QAction, QGridLayout, QSpacerItem, QSizePolicy, QShortcut, QMenu, QApplication
2626
from qgis.PyQt.Qsci import QsciScintilla
2727
from qgis.core import Qgis, QgsApplication, QgsSettings
2828
from qgis.gui import QgsMessageBar, QgsCodeEditorPython
@@ -217,28 +217,48 @@ def contextMenuEvent(self, e):
217217
QCoreApplication.translate("PythonConsole", "Show Editor"),
218218
self.showEditor)
219219
menu.addSeparator()
220-
runAction = menu.addAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"),
221-
QCoreApplication.translate("PythonConsole", "Enter Selected"),
222-
self.enteredSelected,
223-
QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E))
224-
clearAction = menu.addAction(QgsApplication.getThemeIcon("console/iconClearConsole.svg"),
225-
QCoreApplication.translate("PythonConsole", "Clear Console"),
226-
self.clearConsole)
227-
pyQGISHelpAction = menu.addAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
228-
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
229-
self.searchSelectedTextInPyQGISDocs)
220+
runAction = QAction(QgsApplication.getThemeIcon("console/mIconRunConsole.svg"),
221+
QCoreApplication.translate("PythonConsole", "Enter Selected"),
222+
menu)
223+
runAction.triggered.connect(self.enteredSelected)
224+
runAction.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_E))
225+
menu.addAction(runAction)
226+
227+
clearAction = QAction(QgsApplication.getThemeIcon("console/iconClearConsole.svg"),
228+
QCoreApplication.translate("PythonConsole", "Clear Console"),
229+
menu)
230+
clearAction.triggered.connect(self.clearConsole)
231+
menu.addAction(clearAction)
232+
233+
pyQGISHelpAction = QAction(QgsApplication.getThemeIcon("console/iconHelpConsole.svg"),
234+
QCoreApplication.translate("PythonConsole", "Search Selection in PyQGIS Documentation"),
235+
menu)
236+
pyQGISHelpAction.triggered.connect(self.searchSelectedTextInPyQGISDocs)
237+
menu.addAction(pyQGISHelpAction)
238+
230239
menu.addSeparator()
231-
copyAction = menu.addAction(
240+
copyAction = QAction(
232241
QgsApplication.getThemeIcon("mActionEditCopy.svg"),
233242
QCoreApplication.translate("PythonConsole", "Copy"),
234-
self.copy, QKeySequence.StandardKey.Copy)
235-
selectAllAction = menu.addAction(
243+
menu)
244+
copyAction.triggered.connect(self.copy)
245+
copyAction.setShortcut(QKeySequence.StandardKey.Copy)
246+
menu.addAction(copyAction)
247+
248+
selectAllAction = QAction(
236249
QCoreApplication.translate("PythonConsole", "Select All"),
237-
self.selectAll, QKeySequence.StandardKey.SelectAll)
250+
menu)
251+
selectAllAction.triggered.connect(self.selectAll)
252+
selectAllAction.setShortcut(QKeySequence.StandardKey.SelectAll)
253+
menu.addAction(selectAllAction)
254+
238255
menu.addSeparator()
239-
menu.addAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
240-
QCoreApplication.translate("PythonConsole", "Options…"),
241-
self.parent.openSettings)
256+
settings_action = QAction(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"),
257+
QCoreApplication.translate("PythonConsole", "Options…"),
258+
menu)
259+
settings_action.triggered.connect(self.parent.openSettings)
260+
menu.addAction(settings_action)
261+
242262
runAction.setEnabled(False)
243263
clearAction.setEnabled(False)
244264
copyAction.setEnabled(False)

python/plugins/db_manager/db_manager.py

+18-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import functools
2424

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

2929
from qgis.gui import QgsMessageBar
@@ -451,12 +451,24 @@ def setupUi(self):
451451
sep.setObjectName("DB_Manager_DbMenu_placeholder")
452452
sep.setVisible(False)
453453

454-
self.actionRefresh = self.menuDb.addAction(QgsApplication.getThemeIcon("/mActionRefresh.svg"), self.tr("&Refresh"),
455-
self.refreshActionSlot, QKeySequence("F5"))
456-
self.actionSqlWindow = self.menuDb.addAction(QIcon(":/db_manager/actions/sql_window"), self.tr("&SQL Window"),
457-
self.runSqlWindow, QKeySequence("F2"))
454+
self.actionRefresh = QAction(QgsApplication.getThemeIcon("/mActionRefresh.svg"), self.tr("&Refresh"),
455+
self.menuDb)
456+
self.actionRefresh.triggered.connect(self.refreshActionSlot)
457+
self.actionRefresh.setShortcut(QKeySequence("F5"))
458+
self.menuDb.addAction(self.actionRefresh)
459+
460+
self.actionSqlWindow = QAction(QIcon(":/db_manager/actions/sql_window"), self.tr("&SQL Window"),
461+
self.menuDb)
462+
self.actionSqlWindow.triggered.connect(self.runSqlWindow)
463+
self.actionSqlWindow.setShortcut(QKeySequence("F2"))
464+
self.menuDb.addAction(self.actionSqlWindow)
465+
458466
self.menuDb.addSeparator()
459-
self.actionClose = self.menuDb.addAction(QIcon(), self.tr("&Exit"), self.close, QKeySequence("CTRL+Q"))
467+
468+
self.actionClose = QAction(QIcon(), self.tr("&Exit"), self.menuDb)
469+
self.actionClose.triggered.connect(self.close)
470+
self.actionClose.setShortcut(QKeySequence("CTRL+Q"))
471+
self.menuDb.addAction(self.actionClose)
460472

461473
# menu SCHEMA
462474
sep = self.menuSchema.addSeparator()

scripts/pyqt5_to_pyqt6/pyqt5_to_pyqt6.py

+4
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ def visit_call(_node: ast.Call, _parent):
203203
Offset(_node.func.lineno, attr_node.end_col_offset - len(
204204
_node.func.attr) - 1)] = rename_function_attributes[
205205
_node.func.attr]
206+
if _node.func.attr == 'addAction':
207+
if len(_node.args) >= 4:
208+
sys.stderr.write(
209+
f'{filename}:{_node.lineno}:{_node.col_offset} WARNING: fragile call to addAction. Use my_action = QAction(...), obj.addAction(my_action) instead.\n')
206210

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

0 commit comments

Comments
 (0)