diff options
Diffstat (limited to 'qutebrowser/utils/debug.py')
-rw-r--r-- | qutebrowser/utils/debug.py | 108 |
1 files changed, 73 insertions, 35 deletions
diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py index 0fa74f4e7..47cbebb35 100644 --- a/qutebrowser/utils/debug.py +++ b/qutebrowser/utils/debug.py @@ -20,6 +20,7 @@ """Utilities used for debugging.""" import re +import enum import inspect import logging import functools @@ -28,7 +29,7 @@ import types from typing import ( Any, Callable, List, Mapping, MutableSequence, Optional, Sequence, Type, Union) -from PyQt5.QtCore import Qt, QEvent, QMetaMethod, QObject, pyqtBoundSignal +from qutebrowser.qt.core import Qt, QEvent, QMetaMethod, QObject, pyqtBoundSignal from qutebrowser.utils import log, utils, qtutils, objreg from qutebrowser.misc import objects @@ -42,8 +43,10 @@ def log_events(klass: Type[QObject]) -> Type[QObject]: @functools.wraps(old_event) def new_event(self: Any, e: QEvent) -> bool: """Wrapper for event() which logs events.""" - log.misc.debug("Event in {}: {}".format(utils.qualname(klass), - qenum_key(QEvent, e.type()))) + # Passing klass as a WORKAROUND because with PyQt6, QEvent.type() returns int: + # https://www.riverbankcomputing.com/pipermail/pyqt/2022-April/044583.html + log.misc.debug("Event in {}: {}".format( + utils.qualname(klass), qenum_key(QEvent, e.type(), klass=QEvent.Type))) return old_event(self, e) klass.event = new_event # type: ignore[assignment] @@ -70,7 +73,7 @@ def log_signals(obj: QObject) -> QObject: for i in range(metaobj.methodCount()): meta_method = metaobj.method(i) qtutils.ensure_valid(meta_method) - if meta_method.methodType() == QMetaMethod.Signal: + if meta_method.methodType() == QMetaMethod.MethodType.Signal: name = meta_method.name().data().decode('ascii') if name != 'destroyed': signal = getattr(obj, name) @@ -99,16 +102,62 @@ def log_signals(obj: QObject) -> QObject: _EnumValueType = Union[sip.simplewrapper, int] -def qenum_key(base: Type[_EnumValueType], - value: _EnumValueType, - add_base: bool = False, - klass: Type[_EnumValueType] = None) -> str: +def _qenum_key_python( + value: _EnumValueType, + klass: Type[_EnumValueType], +) -> Optional[str]: + """New-style PyQt6: Try getting value from Python enum.""" + if isinstance(value, enum.Enum) and value.name: + return value.name + + # We got an int with klass passed: Try asking Python enum for member + if issubclass(klass, enum.Enum): + try: + assert isinstance(value, int) + name = klass(value).name + if name is not None and name != str(value): + return name + except ValueError: + pass + + return None + + +def _qenum_key_qt( + base: Type[_EnumValueType], + value: _EnumValueType, + klass: Type[_EnumValueType], +) -> Optional[str]: + # On PyQt5, or PyQt6 with int passed: Try to ask Qt's introspection. + # However, not every Qt enum value has a staticMetaObject + try: + meta_obj = base.staticMetaObject # type: ignore[union-attr] + idx = meta_obj.indexOfEnumerator(klass.__name__) + meta_enum = meta_obj.enumerator(idx) + key = meta_enum.valueToKey(int(value)) # type: ignore[arg-type] + if key is not None: + return key + except AttributeError: + pass + + # PyQt5: Try finding value match in class + for name, obj in vars(base).items(): + if isinstance(obj, klass) and obj == value: + return name + + return None + + +def qenum_key( + base: Type[_EnumValueType], + value: _EnumValueType, + klass: Type[_EnumValueType] = None, +) -> str: """Convert a Qt Enum value to its key as a string. Args: base: The object the enum is in, e.g. QFrame. value: The value to get. - add_base: Whether the base should be added to the printed name. klass: The enum class the value belongs to. If None, the class will be auto-guessed. @@ -120,44 +169,33 @@ def qenum_key(base: Type[_EnumValueType], klass = value.__class__ if klass == int: raise TypeError("Can't guess enum class of an int!") + assert klass is not None - try: - meta_obj = base.staticMetaObject # type: ignore[union-attr] - idx = meta_obj.indexOfEnumerator(klass.__name__) - meta_enum = meta_obj.enumerator(idx) - ret = meta_enum.valueToKey(int(value)) # type: ignore[arg-type] - except AttributeError: - ret = None + name = _qenum_key_python(value=value, klass=klass) + if name is not None: + return name - if ret is None: - for name, obj in vars(base).items(): - if isinstance(obj, klass) and obj == value: - ret = name - break - else: - ret = '0x{:04x}'.format(int(value)) # type: ignore[arg-type] + name = _qenum_key_qt(base=base, value=value, klass=klass) + if name is not None: + return name - if add_base and hasattr(base, '__name__'): - return '.'.join([base.__name__, ret]) - else: - return ret + # Last resort fallback: Hex value + return '0x{:04x}'.format(int(value)) # type: ignore[arg-type] def qflags_key(base: Type[_EnumValueType], value: _EnumValueType, - add_base: bool = False, klass: Type[_EnumValueType] = None) -> str: """Convert a Qt QFlags value to its keys as string. - Note: Passing a combined value (such as Qt.AlignCenter) will get the names - for the individual bits (e.g. Qt.AlignVCenter | Qt.AlignHCenter). FIXME + Note: Passing a combined value (such as Qt.AlignmentFlag.AlignCenter) will get the names + for the individual bits (e.g. Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignHCenter). FIXME https://github.com/qutebrowser/qutebrowser/issues/42 Args: base: The object the flags are in, e.g. QtCore.Qt value: The value to get. - add_base: Whether the base should be added to the printed names. klass: The flags class the value belongs to. If None, the class will be auto-guessed. @@ -173,12 +211,12 @@ def qflags_key(base: Type[_EnumValueType], raise TypeError("Can't guess enum class of an int!") if not value: - return qenum_key(base, value, add_base, klass) + return qenum_key(base, value, klass) bits = [] names = [] mask = 0x01 - value = int(value) # type: ignore[arg-type] + value = qtutils.extract_enum_val(value) while mask <= value: if value & mask: bits.append(mask) @@ -187,7 +225,7 @@ def qflags_key(base: Type[_EnumValueType], # We have to re-convert to an enum type here or we'll sometimes get an # empty string back. enum_value = klass(bit) # type: ignore[call-arg] - names.append(qenum_key(base, enum_value, add_base)) + names.append(qenum_key(base, enum_value, klass)) return '|'.join(names) @@ -327,7 +365,7 @@ def _get_pyqt_objects(lines: MutableSequence[str], obj: QObject, depth: int = 0) -> None: """Recursive method for get_all_objects to get Qt objects.""" - for kid in obj.findChildren(QObject, '', Qt.FindDirectChildrenOnly): + for kid in obj.findChildren(QObject, '', Qt.FindChildOption.FindDirectChildrenOnly): lines.append(' ' * depth + repr(kid)) _get_pyqt_objects(lines, kid, depth + 1) |