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.QtCore import (pyqtSlot, QTimer, QEventLoop, Qt, QStandardPaths,
qInstallMessageHandler)
qInstallMessageHandler, QObject)
import qutebrowser
import qutebrowser.commands.utils as cmdutils
@ -54,11 +54,11 @@ from qutebrowser.config.iniparsers import ReadWriteConfigParser
from qutebrowser.config.lineparser import LineConfigParser
from qutebrowser.browser.cookies import CookieJar
from qutebrowser.browser.downloads import DownloadManager
from qutebrowser.models.downloadmodel import DownloadModel
from qutebrowser.utils.message import MessageBridge
from qutebrowser.utils.misc import (get_standard_dir, actute_warning,
get_qt_args)
from qutebrowser.utils.readline import ReadlineBridge
from qutebrowser.utils.usertypes import Timer
from qutebrowser.utils.debug import set_trace # pylint: disable=unused-import
@ -135,7 +135,6 @@ class Application(QApplication):
self.commandmanager = CommandManager()
self.searchmanager = SearchManager(self)
self.downloadmanager = DownloadManager(self)
self.downloadmodel = DownloadModel(self.downloadmanager)
self.mainwindow = MainWindow()
self.modeman.mainwindow = self.mainwindow
@ -307,7 +306,7 @@ class Application(QApplication):
Python interpreter once all 500ms.
"""
signal(SIGINT, lambda *args: self.exit(128 + SIGINT))
timer = QTimer(self)
timer = Timer(self, 'python_hacks')
timer.start(500)
timer.timeout.connect(lambda: None)
self._timers.append(timer)
@ -540,7 +539,17 @@ class Application(QApplication):
log.misc.debug("{} widgets".format(len(widgets)))
widgets.sort(key=lambda e: repr(e))
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()
def shutdown(self):

View File

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

View File

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

View File

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

View File

@ -21,11 +21,11 @@ import re
import string
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
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
@ -54,7 +54,7 @@ class BaseKeyParser(QObject):
warn_on_keychains: Whether a warning should be logged when binding
keychains in a section which does not support them.
_keystring: The currently entered key sequence
_timer: QTimer for delayed execution.
_timer: Timer for delayed execution.
_confsectname: The name of the configsection.
_supports_count: Whether count is supported
_supports_chains: Whether keychains are supported
@ -83,6 +83,11 @@ class BaseKeyParser(QObject):
self.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):
"""Normalize a keystring like Ctrl-Q to a keystring like Ctrl+Q.
@ -273,7 +278,7 @@ class BaseKeyParser(QObject):
# execute in `time' ms
logger.debug("Scheduling execution of {} in {}ms".format(binding,
time))
self._timer = QTimer(self)
self._timer = Timer(self, 'ambigious_match')
self._timer.setSingleShot(True)
self._timer.setInterval(time)
self._timer.timeout.connect(partial(self.delayed_exec, binding,

View File

@ -64,6 +64,9 @@ class PassthroughKeyParser(CommandKeyParser):
"""KeyChainParser which passes through normal keys.
Used for insert/passthrough modes.
Attributes:
_confsect: The config section to use.
"""
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.
"""
super().__init__(parent, supports_chains=False)
if not warn:
self.warn_on_keychains = False
self.warn_on_keychains = warn
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',
'forward-unbound-keys')
def __repr__(self):
return '<{} mode={}>'.format(self.__class__.__name__, self.mode)
@property
def mode(self):
"""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)
self.read_config('keybind')
def __repr__(self):
return '<{}>'.format(self.__class__.__name__)
def _handle_single_key(self, e):
"""Override _handle_single_key to abort if the key is a startchar.
@ -68,6 +71,9 @@ class PromptKeyParser(CommandKeyParser):
# abuse the keybind.prompt section.
self.read_config('keybind.prompt')
def __repr__(self):
return '<{}>'.format(self.__class__.__name__)
class HintKeyParser(CommandKeyParser):

View File

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

View File

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

View File

@ -24,7 +24,7 @@ Module attributes:
import operator
import collections.abc
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtCore import pyqtSignal, QObject, QTimer
from qutebrowser.utils.log import misc as logger
@ -281,6 +281,9 @@ class Question(QObject):
self.answer = None
self.is_aborted = False
def __repr__(self):
return '<{} "{}">'.format(self.__class__.__name__, self.text)
def abort(self):
"""Abort the question.
@ -289,3 +292,23 @@ class Question(QObject):
"""
self.is_aborted = True
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
def __repr__(self):
return '<CompletionView>'
return '<{}>'.format(self.__class__.__name__)
def _resize_columns(self):
"""Resize the completion columns based on COLUMN_WIDTHS."""

View File

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

View File

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

View File

@ -20,7 +20,7 @@
from collections import deque
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
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.prompt import Prompt
from qutebrowser.config.style import set_register_stylesheet, get_stylesheet
from qutebrowser.utils.usertypes import Timer
class StatusBar(QWidget):
@ -54,7 +55,7 @@ class StatusBar(QWidget):
_stack: The QStackedLayout with cmd/txt widgets.
_text_queue: A deque of (error, text) tuples to be displayed.
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.
_timer_was_active: Whether the _text_pop_timer was active before hiding
the command widget.
@ -130,7 +131,7 @@ class StatusBar(QWidget):
self._stack.addWidget(self.txt)
self._timer_was_active = False
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.timeout.connect(self._pop_text)
@ -159,7 +160,7 @@ class StatusBar(QWidget):
self._hbox.addWidget(self.prog)
def __repr__(self):
return '<StatusBar>'
return '<{}>'.format(self.__class__.__name__)
@pyqtProperty(bool)
def error(self):

View File

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

View File

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

View File

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

View File

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