Add an :all-objects command and __repr__s

This commit is contained in:
Florian Bruhin 2014-06-17 11:03:42 +02:00
parent fe99cbc331
commit 1fef2d02b9
19 changed files with 104 additions and 28 deletions

View File

@ -29,7 +29,7 @@ from base64 import b64encode
from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
from PyQt5.QtCore import (pyqtSlot, QTimer, QEventLoop, Qt, QStandardPaths, from PyQt5.QtCore import (pyqtSlot, QTimer, QEventLoop, Qt, QStandardPaths,
qInstallMessageHandler) qInstallMessageHandler, QObject)
import qutebrowser import qutebrowser
import qutebrowser.commands.utils as cmdutils import qutebrowser.commands.utils as cmdutils
@ -54,11 +54,11 @@ from qutebrowser.config.iniparsers import ReadWriteConfigParser
from qutebrowser.config.lineparser import LineConfigParser from qutebrowser.config.lineparser import LineConfigParser
from qutebrowser.browser.cookies import CookieJar from qutebrowser.browser.cookies import CookieJar
from qutebrowser.browser.downloads import DownloadManager from qutebrowser.browser.downloads import DownloadManager
from qutebrowser.models.downloadmodel import DownloadModel
from qutebrowser.utils.message import MessageBridge from qutebrowser.utils.message import MessageBridge
from qutebrowser.utils.misc import (get_standard_dir, actute_warning, from qutebrowser.utils.misc import (get_standard_dir, actute_warning,
get_qt_args) get_qt_args)
from qutebrowser.utils.readline import ReadlineBridge from qutebrowser.utils.readline import ReadlineBridge
from qutebrowser.utils.usertypes import Timer
from qutebrowser.utils.debug import set_trace # pylint: disable=unused-import from qutebrowser.utils.debug import set_trace # pylint: disable=unused-import
@ -135,7 +135,6 @@ class Application(QApplication):
self.commandmanager = CommandManager() self.commandmanager = CommandManager()
self.searchmanager = SearchManager(self) self.searchmanager = SearchManager(self)
self.downloadmanager = DownloadManager(self) self.downloadmanager = DownloadManager(self)
self.downloadmodel = DownloadModel(self.downloadmanager)
self.mainwindow = MainWindow() self.mainwindow = MainWindow()
self.modeman.mainwindow = self.mainwindow self.modeman.mainwindow = self.mainwindow
@ -307,7 +306,7 @@ class Application(QApplication):
Python interpreter once all 500ms. Python interpreter once all 500ms.
""" """
signal(SIGINT, lambda *args: self.exit(128 + SIGINT)) signal(SIGINT, lambda *args: self.exit(128 + SIGINT))
timer = QTimer(self) timer = Timer(self, 'python_hacks')
timer.start(500) timer.start(500)
timer.timeout.connect(lambda: None) timer.timeout.connect(lambda: None)
self._timers.append(timer) self._timers.append(timer)
@ -540,7 +539,17 @@ class Application(QApplication):
log.misc.debug("{} widgets".format(len(widgets))) log.misc.debug("{} widgets".format(len(widgets)))
widgets.sort(key=lambda e: repr(e)) widgets.sort(key=lambda e: repr(e))
for w in widgets: for w in widgets:
log.misc.debug(w) log.misc.debug(repr(w))
@cmdutils.register(instance='', debug=True)
def all_objects(self, obj=None, depth=0):
"""Dump all children of an object recursively."""
if obj is None:
obj = self
for kid in obj.findChildren(QObject):
log.misc.debug(' ' * depth + repr(kid))
self.all_objects(kid, depth + 1)
@pyqtSlot() @pyqtSlot()
def shutdown(self): def shutdown(self):

View File

@ -22,13 +22,13 @@ import os.path
from functools import partial from functools import partial
from collections import deque from collections import deque
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QTimer from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
from PyQt5.QtNetwork import QNetworkReply from PyQt5.QtNetwork import QNetworkReply
import qutebrowser.config.config as config import qutebrowser.config.config as config
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
from qutebrowser.utils.log import downloads as logger from qutebrowser.utils.log import downloads as logger
from qutebrowser.utils.usertypes import PromptMode, Question from qutebrowser.utils.usertypes import PromptMode, Question, Timer
from qutebrowser.utils.misc import (interpolate_color, format_seconds, from qutebrowser.utils.misc import (interpolate_color, format_seconds,
format_size) format_size)
@ -99,11 +99,14 @@ class DownloadItem(QObject):
reply.finished.connect(self.on_reply_finished) reply.finished.connect(self.on_reply_finished)
reply.error.connect(self.on_reply_error) reply.error.connect(self.on_reply_error)
reply.readyRead.connect(self.on_ready_read) reply.readyRead.connect(self.on_ready_read)
self.timer = QTimer(self) self.timer = Timer(self, 'speed_refresh')
self.timer.timeout.connect(self.update_speed) self.timer.timeout.connect(self.update_speed)
self.timer.setInterval(self.SPEED_REFRESH_INTERVAL) self.timer.setInterval(self.SPEED_REFRESH_INTERVAL)
self.timer.start() self.timer.start()
def __repr__(self):
return '<{} "{}">'.format(self.__class__.__name__, self.basename)
def __str__(self): def __str__(self):
"""Get the download as a string. """Get the download as a string.
@ -309,6 +312,9 @@ class DownloadManager(QObject):
self.downloads = [] self.downloads = []
self.questions = [] self.questions = []
def __repr__(self):
return '<{}>'.format(self.__class__.__name__)
def _get_filename(self, reply): def _get_filename(self, reply):
"""Get a suitable filename to download a file to. """Get a suitable filename to download a file to.

View File

@ -50,6 +50,9 @@ class SearchManager(QObject):
self._text = None self._text = None
self._flags = 0 self._flags = 0
def __repr__(self):
return '<{} text={}>'.format(self.__class__.__name__, self._text)
def _search(self, text, rev=False): def _search(self, text, rev=False):
"""Search for a text on the current page. """Search for a text on the current page.

View File

@ -80,6 +80,7 @@ class ConfigManager(QObject):
Attributes: Attributes:
sections: The configuration data as an OrderedDict. sections: The configuration data as an OrderedDict.
_fname: The filename to be opened.
_configparser: A ReadConfigParser instance to load the config. _configparser: A ReadConfigParser instance to load the config.
_wrapper_args: A dict with the default kwargs for the config wrappers. _wrapper_args: A dict with the default kwargs for the config wrappers.
_configdir: The dictionary to read the config from and save it in. _configdir: The dictionary to read the config from and save it in.
@ -112,6 +113,7 @@ class ConfigManager(QObject):
'break_on_hyphens': False, 'break_on_hyphens': False,
} }
self._configdir = configdir self._configdir = configdir
self._fname = fname
self._interpolation = ExtendedInterpolation() self._interpolation = ExtendedInterpolation()
self._proxies = {} self._proxies = {}
for sectname in self.sections.keys(): for sectname in self.sections.keys():
@ -122,6 +124,9 @@ class ConfigManager(QObject):
"""Get a section from the config.""" """Get a section from the config."""
return self._proxies[key] return self._proxies[key]
def __repr__(self):
return '<{} {}>'.format(self.__class__.__name__, self._fname)
def __str__(self): def __str__(self):
"""Get the whole config as a string.""" """Get the whole config as a string."""
lines = configdata.FIRST_COMMENT.strip('\n').splitlines() lines = configdata.FIRST_COMMENT.strip('\n').splitlines()
@ -401,7 +406,7 @@ class SectionProxy(MutableMapping):
self._name = name self._name = name
def __repr__(self): def __repr__(self):
return '<Section: {}>'.format(self._name) return '<{} {}>'.format(self.__class__.__name__, self._name)
def __getitem__(self, key): def __getitem__(self, key):
if not self._conf.has_option(self._name, key): if not self._conf.has_option(self._name, key):

View File

@ -21,11 +21,11 @@ import re
import string import string
from functools import partial from functools import partial
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject, QTimer from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject
from PyQt5.QtGui import QKeySequence from PyQt5.QtGui import QKeySequence
import qutebrowser.config.config as config import qutebrowser.config.config as config
from qutebrowser.utils.usertypes import enum from qutebrowser.utils.usertypes import enum, Timer
from qutebrowser.utils.log import keyboard as logger from qutebrowser.utils.log import keyboard as logger
@ -54,7 +54,7 @@ class BaseKeyParser(QObject):
warn_on_keychains: Whether a warning should be logged when binding warn_on_keychains: Whether a warning should be logged when binding
keychains in a section which does not support them. keychains in a section which does not support them.
_keystring: The currently entered key sequence _keystring: The currently entered key sequence
_timer: QTimer for delayed execution. _timer: Timer for delayed execution.
_confsectname: The name of the configsection. _confsectname: The name of the configsection.
_supports_count: Whether count is supported _supports_count: Whether count is supported
_supports_chains: Whether keychains are supported _supports_chains: Whether keychains are supported
@ -83,6 +83,11 @@ class BaseKeyParser(QObject):
self.bindings = {} self.bindings = {}
self.special_bindings = {} self.special_bindings = {}
def __repr__(self):
return '<{} supports_count={}, supports_chains={}>'.format(
self.__class__.__name__, self._supports_count,
self._supports_chains)
def _normalize_keystr(self, keystr): def _normalize_keystr(self, keystr):
"""Normalize a keystring like Ctrl-Q to a keystring like Ctrl+Q. """Normalize a keystring like Ctrl-Q to a keystring like Ctrl+Q.
@ -273,7 +278,7 @@ class BaseKeyParser(QObject):
# execute in `time' ms # execute in `time' ms
logger.debug("Scheduling execution of {} in {}ms".format(binding, logger.debug("Scheduling execution of {} in {}ms".format(binding,
time)) time))
self._timer = QTimer(self) self._timer = Timer(self, 'ambigious_match')
self._timer.setSingleShot(True) self._timer.setSingleShot(True)
self._timer.setInterval(time) self._timer.setInterval(time)
self._timer.timeout.connect(partial(self.delayed_exec, binding, self._timer.timeout.connect(partial(self.delayed_exec, binding,

View File

@ -64,6 +64,9 @@ class PassthroughKeyParser(CommandKeyParser):
"""KeyChainParser which passes through normal keys. """KeyChainParser which passes through normal keys.
Used for insert/passthrough modes. Used for insert/passthrough modes.
Attributes:
_confsect: The config section to use.
""" """
def __init__(self, confsect, parent=None, warn=True): def __init__(self, confsect, parent=None, warn=True):
@ -75,6 +78,10 @@ class PassthroughKeyParser(CommandKeyParser):
warn: Whether to warn if an ignored key was bound. warn: Whether to warn if an ignored key was bound.
""" """
super().__init__(parent, supports_chains=False) super().__init__(parent, supports_chains=False)
if not warn: self.warn_on_keychains = warn
self.warn_on_keychains = False
self.read_config(confsect) self.read_config(confsect)
self._confsect = confsect
def __repr__(self):
return '<{} confsect={}, warn={})'.format(
self.__class__.__name__, self._confsect, self.warn_on_keychains)

View File

@ -90,6 +90,9 @@ class ModeManager(QObject):
self._forward_unbound_keys = config.get('input', self._forward_unbound_keys = config.get('input',
'forward-unbound-keys') 'forward-unbound-keys')
def __repr__(self):
return '<{} mode={}>'.format(self.__class__.__name__, self.mode)
@property @property
def mode(self): def mode(self):
"""Read-only property for the current mode.""" """Read-only property for the current mode."""

View File

@ -42,6 +42,9 @@ class NormalKeyParser(CommandKeyParser):
super().__init__(parent, supports_count=True, supports_chains=True) super().__init__(parent, supports_count=True, supports_chains=True)
self.read_config('keybind') self.read_config('keybind')
def __repr__(self):
return '<{}>'.format(self.__class__.__name__)
def _handle_single_key(self, e): def _handle_single_key(self, e):
"""Override _handle_single_key to abort if the key is a startchar. """Override _handle_single_key to abort if the key is a startchar.
@ -68,6 +71,9 @@ class PromptKeyParser(CommandKeyParser):
# abuse the keybind.prompt section. # abuse the keybind.prompt section.
self.read_config('keybind.prompt') self.read_config('keybind.prompt')
def __repr__(self):
return '<{}>'.format(self.__class__.__name__)
class HintKeyParser(CommandKeyParser): class HintKeyParser(CommandKeyParser):

View File

@ -47,6 +47,9 @@ class DownloadModel(QAbstractListModel):
self.downloadmanager.download_finished.connect(self.endRemoveRows) self.downloadmanager.download_finished.connect(self.endRemoveRows)
self.downloadmanager.data_changed.connect(self.on_data_changed) self.downloadmanager.data_changed.connect(self.on_data_changed)
def __repr__(self):
return '<{}>'.format(self.__class__.__name__)
@pyqtSlot(int) @pyqtSlot(int)
def on_data_changed(self, idx): def on_data_changed(self, idx):
"""Update view when DownloadManager data changed.""" """Update view when DownloadManager data changed."""

View File

@ -149,3 +149,6 @@ class MessageBridge(QObject):
text = pyqtSignal(str) text = pyqtSignal(str)
set_cmd_text = pyqtSignal(str) set_cmd_text = pyqtSignal(str)
question = pyqtSignal(Question, bool) question = pyqtSignal(Question, bool)
def __repr__(self):
return '<{}>'.format(self.__class__.__name__)

View File

@ -24,7 +24,7 @@ Module attributes:
import operator import operator
import collections.abc import collections.abc
from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtCore import pyqtSignal, QObject, QTimer
from qutebrowser.utils.log import misc as logger from qutebrowser.utils.log import misc as logger
@ -281,6 +281,9 @@ class Question(QObject):
self.answer = None self.answer = None
self.is_aborted = False self.is_aborted = False
def __repr__(self):
return '<{} "{}">'.format(self.__class__.__name__, self.text)
def abort(self): def abort(self):
"""Abort the question. """Abort the question.
@ -289,3 +292,23 @@ class Question(QObject):
""" """
self.is_aborted = True self.is_aborted = True
self.aborted.emit() self.aborted.emit()
class Timer(QTimer):
"""A timer which has a name to show in __repr__.
Attributes:
_name: The name of the timer.
"""
def __init__(self, parent=None, name=None):
super().__init__(parent)
if name is None:
self._name = "unnamed"
else:
self.setObjectName(name)
self._name = name
def __repr__(self):
return '<{} {}>'.format(self.__class__.__name__, self._name)

View File

@ -113,7 +113,7 @@ class CompletionView(QTreeView):
# FIXME set elidemode # FIXME set elidemode
def __repr__(self): def __repr__(self):
return '<CompletionView>' return '<{}>'.format(self.__class__.__name__)
def _resize_columns(self): def _resize_columns(self):
"""Resize the completion columns based on COLUMN_WIDTHS.""" """Resize the completion columns based on COLUMN_WIDTHS."""

View File

@ -61,7 +61,7 @@ class DownloadView(QListView):
self.customContextMenuRequested.connect(self.show_context_menu) self.customContextMenuRequested.connect(self.show_context_menu)
def __repr__(self): def __repr__(self):
return '<DownloadView with {} downloads>'.format( return '<{} with {} downloads>'.format(self.__class__.__name__,
self.model().rowCount()) self.model().rowCount())
@pyqtSlot('QPoint') @pyqtSlot('QPoint')

View File

@ -89,7 +89,7 @@ class MainWindow(QWidget):
#QtCore.QMetaObject.connectSlotsByName(MainWindow) #QtCore.QMetaObject.connectSlotsByName(MainWindow)
def __repr__(self): def __repr__(self):
return '<MainWindow>' return '<{}>'.format(self.__class__.__name__)
def _set_default_geometry(self): def _set_default_geometry(self):
"""Set some sensible default geometry.""" """Set some sensible default geometry."""

View File

@ -20,7 +20,7 @@
from collections import deque from collections import deque
from datetime import datetime from datetime import datetime
from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt, QTimer from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy
import qutebrowser.keyinput.modeman as modeman import qutebrowser.keyinput.modeman as modeman
@ -34,6 +34,7 @@ from qutebrowser.widgets.statusbar.percentage import Percentage
from qutebrowser.widgets.statusbar.url import Url from qutebrowser.widgets.statusbar.url import Url
from qutebrowser.widgets.statusbar.prompt import Prompt from qutebrowser.widgets.statusbar.prompt import Prompt
from qutebrowser.config.style import set_register_stylesheet, get_stylesheet from qutebrowser.config.style import set_register_stylesheet, get_stylesheet
from qutebrowser.utils.usertypes import Timer
class StatusBar(QWidget): class StatusBar(QWidget):
@ -54,7 +55,7 @@ class StatusBar(QWidget):
_stack: The QStackedLayout with cmd/txt widgets. _stack: The QStackedLayout with cmd/txt widgets.
_text_queue: A deque of (error, text) tuples to be displayed. _text_queue: A deque of (error, text) tuples to be displayed.
error: True if message is an error, False otherwise error: True if message is an error, False otherwise
_text_pop_timer: A QTimer displaying the error messages. _text_pop_timer: A Timer displaying the error messages.
_last_text_time: The timestamp where a message was last displayed. _last_text_time: The timestamp where a message was last displayed.
_timer_was_active: Whether the _text_pop_timer was active before hiding _timer_was_active: Whether the _text_pop_timer was active before hiding
the command widget. the command widget.
@ -130,7 +131,7 @@ class StatusBar(QWidget):
self._stack.addWidget(self.txt) self._stack.addWidget(self.txt)
self._timer_was_active = False self._timer_was_active = False
self._text_queue = deque() self._text_queue = deque()
self._text_pop_timer = QTimer(self) self._text_pop_timer = Timer(self, 'statusbar_text_pop')
self._text_pop_timer.setInterval(config.get('ui', 'message-timeout')) self._text_pop_timer.setInterval(config.get('ui', 'message-timeout'))
self._text_pop_timer.timeout.connect(self._pop_text) self._text_pop_timer.timeout.connect(self._pop_text)
@ -159,7 +160,7 @@ class StatusBar(QWidget):
self._hbox.addWidget(self.prog) self._hbox.addWidget(self.prog)
def __repr__(self): def __repr__(self):
return '<StatusBar>' return '<{}>'.format(self.__class__.__name__)
@pyqtProperty(bool) @pyqtProperty(bool)
def error(self): def error(self):

View File

@ -54,7 +54,7 @@ class Progress(QProgressBar):
self.hide() self.hide()
def __repr__(self): def __repr__(self):
return '<Progress {}%>'.format(self.value()) return '<{} {}%>'.format(self.__class__.__name__, self.value())
@pyqtSlot() @pyqtSlot()
def on_load_started(self): def on_load_started(self):

View File

@ -64,7 +64,7 @@ class Prompt(QWidget):
self._hbox.addWidget(self._input) self._hbox.addWidget(self._input)
def __repr__(self): def __repr__(self):
return '<Prompt>' return '<{}>'.format(self.__class__.__name__)
def on_mode_left(self, mode): def on_mode_left(self, mode):
"""Clear and reset input when the mode was left.""" """Clear and reset input when the mode was left."""

View File

@ -108,7 +108,8 @@ class TabbedBrowser(TabWidget):
self.setIconSize(QSize(12, 12)) self.setIconSize(QSize(12, 12))
def __repr__(self): def __repr__(self):
return '<TabbedBrowser with {} tabs>'.format(self.count()) return '<{} with {} tabs>'.format(self.__class__.__name__,
self.count())
@property @property
def widgets(self): def widgets(self):

View File

@ -124,7 +124,8 @@ class TabBar(QTabBar):
"""Custom tabbar to close tabs on right click.""" """Custom tabbar to close tabs on right click."""
def __repr__(self): def __repr__(self):
return '<TabBar with {} tabs>'.format(self.count()) return '<{} with {} tabs>'.format(self.__class__.__name__,
self.count())
def mousePressEvent(self, e): def mousePressEvent(self, e):
"""Override mousePressEvent to emit tabCloseRequested on rightclick.""" """Override mousePressEvent to emit tabCloseRequested on rightclick."""