1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
# -----------------------------------------------------------------------------
# Copyright © 2023- The Spyder Development Team
#
# Released under the terms of the MIT License
# (see LICENSE.txt for details)
# -----------------------------------------------------------------------------
"""Provides utility functions for use by QtPy itself."""
from functools import wraps
from typing import TYPE_CHECKING
import qtpy
if TYPE_CHECKING:
from qtpy.QtWidgets import QAction
def _wrap_missing_optional_dep_error(
attr_error,
*,
import_error,
wrapper=qtpy.QtModuleNotInstalledError,
**wrapper_kwargs,
):
"""Create a __cause__-chained wrapper error for a missing optional dep."""
qtpy_error = wrapper(**wrapper_kwargs)
import_error.__cause__ = attr_error
qtpy_error.__cause__ = import_error
return qtpy_error
def getattr_missing_optional_dep(name, module_name, optional_names):
"""Wrap AttributeError in a special error if it matches."""
attr_error = AttributeError(
f"module {module_name!r} has no attribute {name!r}",
)
if name in optional_names:
return _wrap_missing_optional_dep_error(
attr_error,
**optional_names[name],
)
return attr_error
def possibly_static_exec(cls, *args, **kwargs):
"""Call `self.exec` when `self` is given or a static method otherwise."""
if not args and not kwargs:
# A special case (`cls.exec_()`) to avoid the function resolving error
return cls.exec()
if isinstance(args[0], cls):
if len(args) == 1 and not kwargs:
# A special case (`self.exec_()`) to avoid the function resolving error
return args[0].exec()
return args[0].exec(*args[1:], **kwargs)
return cls.exec(*args, **kwargs)
def possibly_static_exec_(cls, *args, **kwargs):
"""Call `self.exec` when `self` is given or a static method otherwise."""
if not args and not kwargs:
# A special case (`cls.exec()`) to avoid the function resolving error
return cls.exec_()
if isinstance(args[0], cls):
if len(args) == 1 and not kwargs:
# A special case (`self.exec()`) to avoid the function resolving error
return args[0].exec_()
return args[0].exec_(*args[1:], **kwargs)
return cls.exec_(*args, **kwargs)
def set_shortcut(self, shortcut, old_set_shortcut):
"""Ensure that the type of `shortcut` is compatible to `QAction.setShortcut`."""
from qtpy.QtCore import Qt
from qtpy.QtGui import QKeySequence
if isinstance(shortcut, (QKeySequence.StandardKey, Qt.Key, int)):
shortcut = QKeySequence(shortcut)
old_set_shortcut(self, shortcut)
def set_shortcuts(self, shortcuts, old_set_shortcuts):
"""Ensure that the type of `shortcuts` is compatible to `QAction.setShortcuts`."""
from qtpy.QtCore import Qt
from qtpy.QtGui import QKeySequence
if isinstance(
shortcuts,
(QKeySequence, QKeySequence.StandardKey, Qt.Key, int, str),
):
shortcuts = (shortcuts,)
shortcuts = tuple(
(
QKeySequence(shortcut)
if isinstance(shortcut, (QKeySequence.StandardKey, Qt.Key, int))
else shortcut
)
for shortcut in shortcuts
)
old_set_shortcuts(self, shortcuts)
def add_action(self, *args, old_add_action):
"""Re-order arguments of `addAction` to backport compatibility with Qt>=6.3."""
from qtpy.QtCore import QObject, Qt
from qtpy.QtGui import QIcon, QKeySequence
action: QAction
icon: QIcon
text: str
shortcut: QKeySequence | QKeySequence.StandardKey | Qt.Key | str | int
receiver: QObject
member: bytes
if all(
isinstance(arg, t)
for arg, t in zip(
args,
[
str,
(QKeySequence, QKeySequence.StandardKey, Qt.Key, str, int),
QObject,
bytes,
],
)
):
if len(args) == 2:
text, shortcut = args
action = old_add_action(self, text)
action.setShortcut(shortcut)
elif len(args) == 3:
text, shortcut, receiver = args
action = old_add_action(self, text, receiver)
action.setShortcut(shortcut)
elif len(args) == 4:
text, shortcut, receiver, member = args
action = old_add_action(self, text, receiver, member, shortcut)
else:
action = old_add_action(self, *args)
elif all(
isinstance(arg, t)
for arg, t in zip(
args,
[
QIcon,
str,
(QKeySequence, QKeySequence.StandardKey, Qt.Key, str, int),
QObject,
bytes,
],
)
):
if len(args) == 3:
icon, text, shortcut = args
action = old_add_action(self, icon, text)
action.setShortcut(shortcut)
elif len(args) == 4:
icon, text, shortcut, receiver = args
action = old_add_action(self, icon, text, receiver)
action.setShortcut(shortcut)
elif len(args) == 5:
icon, text, shortcut, receiver, member = args
action = old_add_action(
self,
icon,
text,
receiver,
member,
shortcut,
)
else:
action = old_add_action(self, *args)
else:
action = old_add_action(self, *args)
return action
def static_method_kwargs_wrapper(func, from_kwarg_name, to_kwarg_name):
"""
Helper function to manage `from_kwarg_name` to `to_kwarg_name` kwargs name changes in static methods.
Makes static methods accept the `from_kwarg_name` kwarg as `to_kwarg_name`.
"""
@staticmethod
@wraps(func)
def _from_kwarg_name_to_kwarg_name_(*args, **kwargs):
if from_kwarg_name in kwargs:
kwargs[to_kwarg_name] = kwargs.pop(from_kwarg_name)
return func(*args, **kwargs)
return _from_kwarg_name_to_kwarg_name_
|