Skip to content

Commit 3ba97e3

Browse files
authored
PR: Make QMenu.addAction and QToolBar.addAction compatible with Qt6 arguments' order (#437)
2 parents d44e4cc + 3006195 commit 3ba97e3

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

qtpy/QtWidgets.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
# -----------------------------------------------------------------------------
88

99
"""Provides widget classes and functions."""
10-
from functools import wraps
10+
from functools import partialmethod, wraps
1111

12-
from . import PYQT5, PYQT6, PYSIDE2, PYSIDE6, QtModuleNotInstalledError
13-
from ._utils import possibly_static_exec, getattr_missing_optional_dep
12+
from packaging.version import parse
13+
14+
from . import PYQT5, PYQT6, PYSIDE2, PYSIDE6, QT_VERSION as _qt_version
15+
from ._utils import add_action, possibly_static_exec, getattr_missing_optional_dep
1416

1517

1618
_missing_optional_names = {}
@@ -114,3 +116,8 @@ def _directory_to_dir_(*args, **kwargs):
114116
QFileDialog.getOpenFileName = _dir_to_directory(QFileDialog.getOpenFileName)
115117
QFileDialog.getOpenFileNames = _dir_to_directory(QFileDialog.getOpenFileNames)
116118
QFileDialog.getSaveFileName = _dir_to_directory(QFileDialog.getSaveFileName)
119+
120+
# Make `addAction` compatible with Qt6 >= 6.3
121+
if PYQT5 or PYSIDE2 or parse(_qt_version) < parse('6.3'):
122+
QMenu.addAction = partialmethod(add_action, old_add_action=QMenu.addAction)
123+
QToolBar.addAction = partialmethod(add_action, old_add_action=QToolBar.addAction)

qtpy/_utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,57 @@ def possibly_static_exec_(cls, *args, **kwargs):
5858
return args[0].exec_(*args[1:], **kwargs)
5959
else:
6060
return cls.exec_(*args, **kwargs)
61+
62+
63+
def add_action(self, *args, old_add_action):
64+
"""Re-order arguments of `addAction` to backport compatibility with Qt>=6.3."""
65+
from qtpy.QtCore import QObject
66+
from qtpy.QtGui import QIcon, QKeySequence
67+
from qtpy.QtWidgets import QAction
68+
69+
action: QAction
70+
icon: QIcon
71+
text: str
72+
shortcut: QKeySequence | QKeySequence.StandardKey | str | int
73+
receiver: QObject
74+
member: bytes
75+
if all(isinstance(arg, t)
76+
for arg, t in zip(args, [str,
77+
(QKeySequence, QKeySequence.StandardKey, str, int),
78+
QObject,
79+
bytes])):
80+
if len(args) == 2:
81+
text, shortcut = args
82+
action = old_add_action(self, text)
83+
action.setShortcut(shortcut)
84+
elif len(args) == 3:
85+
text, shortcut, receiver = args
86+
action = old_add_action(self, text, receiver)
87+
action.setShortcut(shortcut)
88+
elif len(args) == 4:
89+
text, shortcut, receiver, member = args
90+
action = old_add_action(self, text, receiver, member, shortcut)
91+
else:
92+
return old_add_action(self, *args)
93+
return action
94+
elif all(isinstance(arg, t)
95+
for arg, t in zip(args, [QIcon,
96+
str,
97+
(QKeySequence, QKeySequence.StandardKey, str, int),
98+
QObject,
99+
bytes])):
100+
if len(args) == 3:
101+
icon, text, shortcut = args
102+
action = old_add_action(self, icon, text)
103+
action.setShortcut(QKeySequence(shortcut))
104+
elif len(args) == 4:
105+
icon, text, shortcut, receiver = args
106+
action = old_add_action(self, icon, text, receiver)
107+
action.setShortcut(QKeySequence(shortcut))
108+
elif len(args) == 5:
109+
icon, text, shortcut, receiver, member = args
110+
action = old_add_action(self, icon, text, receiver, member, QKeySequence(shortcut))
111+
else:
112+
return old_add_action(self, *args)
113+
return action
114+
return old_add_action(self, *args)

qtpy/tests/test_qtwidgets.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ def test_QMenu_functions(qtbot):
100100
window = QtWidgets.QMainWindow()
101101
menu = QtWidgets.QMenu(window)
102102
menu.addAction('QtPy')
103+
menu.addAction('QtPy with a shortcut', QtGui.QKeySequence.UnknownKey)
104+
menu.addAction(QtGui.QIcon(), 'QtPy with an icon and a shortcut', QtGui.QKeySequence.UnknownKey)
103105
window.show()
104106

105107
with qtbot.waitExposed(window):
@@ -115,6 +117,16 @@ def test_QMenu_functions(qtbot):
115117
QtWidgets.QMenu.exec_(menu.actions(), QtCore.QPoint(1, 1))
116118

117119

120+
@pytest.mark.skipif(
121+
sys.platform == 'darwin' and sys.version_info[:2] == (3, 7),
122+
reason="Stalls on macOS CI with Python 3.7")
123+
def test_QToolBar_functions(qtbot):
124+
"""Test `QtWidgets.QToolBar.addAction` compatibility with Qt6 arguments' order."""
125+
toolbar = QtWidgets.QToolBar()
126+
toolbar.addAction('QtPy with a shortcut', QtGui.QKeySequence.UnknownKey)
127+
toolbar.addAction(QtGui.QIcon(), 'QtPy with an icon and a shortcut', QtGui.QKeySequence.UnknownKey)
128+
129+
118130
@pytest.mark.skipif(PYQT5 and PYQT_VERSION.startswith('5.9'),
119131
reason="A specific setup with at least sip 4.9.9 is needed for PyQt5 5.9.*"
120132
"to work with scoped enum access")

0 commit comments

Comments
 (0)