Clean up imports

This commit is contained in:
Florian Bruhin 2014-08-26 19:10:14 +02:00
parent 45608ee9f8
commit d625cde28c
99 changed files with 1467 additions and 1458 deletions

View File

@ -289,7 +289,7 @@ or
[source,python] [source,python]
---- ----
import qutebrowser.utils.log as log from qutebrowser.utils import log
... ...
log.foo.debug("Hello World") log.foo.debug("Hello World")
---- ----

View File

@ -20,9 +20,10 @@
"""Entry point for qutebrowser. Simply execute qutebrowser.""" """Entry point for qutebrowser. Simply execute qutebrowser."""
import qutebrowser.qutebrowser
import sys import sys
import qutebrowser.qutebrowser
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(qutebrowser.qutebrowser.main()) sys.exit(qutebrowser.qutebrowser.main())

View File

@ -26,46 +26,28 @@ import faulthandler
import configparser import configparser
import signal import signal
import warnings import warnings
from bdb import BdbQuit import bdb
from base64 import b64encode import base64
from functools import partial import functools
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, QObject, QUrl) qInstallMessageHandler, QObject, QUrl)
import qutebrowser import qutebrowser
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import userscripts, runners
import qutebrowser.config.style as style from qutebrowser.commands import utils as cmdutils
import qutebrowser.config.config as config from qutebrowser.config import (style, config, websettings, iniparsers,
import qutebrowser.network.qutescheme as qutescheme lineparser, conftypes)
import qutebrowser.config.websettings as websettings from qutebrowser.network import qutescheme, proxy
import qutebrowser.network.proxy as proxy from qutebrowser.browser import quickmarks, cookies, downloads
import qutebrowser.browser.quickmarks as quickmarks from qutebrowser.widgets import mainwindow, console, crash
import qutebrowser.utils.log as log from qutebrowser.keyinput import modeparsers, keyparser, modeman
import qutebrowser.utils.version as version from qutebrowser.utils import log, version, message, utilcmds, readline
import qutebrowser.utils.url as urlutils from qutebrowser.utils import url as urlutils
import qutebrowser.utils.message as message from qutebrowser.utils import misc as utils
import qutebrowser.commands.userscripts as userscripts from qutebrowser.utils import qt as qtutils
import qutebrowser.utils.utilcmds as utilcmds from qutebrowser.utils import usertypes as utypes
from qutebrowser.config.config import ConfigManager
from qutebrowser.keyinput.modeman import ModeManager
from qutebrowser.widgets.mainwindow import MainWindow
from qutebrowser.widgets.console import ConsoleWidget
from qutebrowser.widgets.crash import (ExceptionCrashDialog, FatalCrashDialog,
ReportDialog)
from qutebrowser.keyinput.modeparsers import (NormalKeyParser, HintKeyParser,
PromptKeyParser)
from qutebrowser.keyinput.keyparser import PassthroughKeyParser
from qutebrowser.commands.runners import CommandRunner, SearchRunner
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.utils.misc import get_standard_dir, actute_warning
from qutebrowser.utils.qt import get_qt_args
from qutebrowser.utils.readline import ReadlineBridge
from qutebrowser.utils.usertypes import Timer, KeyMode
class Application(QApplication): class Application(QApplication):
@ -104,9 +86,9 @@ class Application(QApplication):
# We don't enable this earlier because some imports trigger # We don't enable this earlier because some imports trigger
# warnings (which are not our fault). # warnings (which are not our fault).
warnings.simplefilter('default') warnings.simplefilter('default')
qt_args = get_qt_args(args) qt_args = qtutils.get_qt_args(args)
log.init.debug("Qt arguments: {}, based on {}".format(qt_args, args)) log.init.debug("Qt arguments: {}, based on {}".format(qt_args, args))
super().__init__(get_qt_args(args)) super().__init__(qt_args)
self._quit_status = { self._quit_status = {
'crash': True, 'crash': True,
'tabs': False, 'tabs': False,
@ -129,7 +111,7 @@ class Application(QApplication):
self.args = args self.args = args
log.init.debug("Starting init...") log.init.debug("Starting init...")
self._init_misc() self._init_misc()
actute_warning() utils.actute_warning()
log.init.debug("Initializing config...") log.init.debug("Initializing config...")
self._init_config() self._init_config()
log.init.debug("Initializing crashlog...") log.init.debug("Initializing crashlog...")
@ -147,25 +129,25 @@ class Application(QApplication):
log.init.debug("Initializing utility commands...") log.init.debug("Initializing utility commands...")
utilcmds.init() utilcmds.init()
log.init.debug("Initializing cookies...") log.init.debug("Initializing cookies...")
self.cookiejar = CookieJar(self) self.cookiejar = cookies.CookieJar(self)
log.init.debug("Initializing commands...") log.init.debug("Initializing commands...")
self.commandrunner = CommandRunner() self.commandrunner = runners.CommandRunner()
log.init.debug("Initializing search...") log.init.debug("Initializing search...")
self.searchrunner = SearchRunner(self) self.searchrunner = runners.SearchRunner(self)
log.init.debug("Initializing downloads...") log.init.debug("Initializing downloads...")
self.downloadmanager = DownloadManager(self) self.downloadmanager = downloads.DownloadManager(self)
log.init.debug("Initializing main window...") log.init.debug("Initializing main window...")
self.mainwindow = MainWindow() self.mainwindow = mainwindow.MainWindow()
self.modeman.mainwindow = self.mainwindow self.modeman.mainwindow = self.mainwindow
log.init.debug("Initializing debug console...") log.init.debug("Initializing debug console...")
self.debugconsole = ConsoleWidget() self.debugconsole = console.ConsoleWidget()
log.init.debug("Initializing eventfilter...") log.init.debug("Initializing eventfilter...")
self.installEventFilter(self.modeman) self.installEventFilter(self.modeman)
self.setQuitOnLastWindowClosed(False) self.setQuitOnLastWindowClosed(False)
log.init.debug("Connecting signals...") log.init.debug("Connecting signals...")
self._connect_signals() self._connect_signals()
self.modeman.enter(KeyMode.normal, 'init') self.modeman.enter(utypes.KeyMode.normal, 'init')
log.init.debug("Showing mainwindow...") log.init.debug("Showing mainwindow...")
if not args.nowindow: if not args.nowindow:
@ -183,14 +165,15 @@ class Application(QApplication):
def _init_config(self): def _init_config(self):
"""Inizialize and read the config.""" """Inizialize and read the config."""
if self.args.confdir is None: if self.args.confdir is None:
confdir = get_standard_dir(QStandardPaths.ConfigLocation) confdir = utils.get_standard_dir(QStandardPaths.ConfigLocation)
elif self.args.confdir == '': elif self.args.confdir == '':
confdir = None confdir = None
else: else:
confdir = self.args.confdir confdir = self.args.confdir
try: try:
self.config = ConfigManager(confdir, 'qutebrowser.conf', self) self.config = config.ConfigManager(confdir, 'qutebrowser.conf',
except (config.ValidationError, self)
except (conftypes.ValidationError,
config.NoOptionError, config.NoOptionError,
config.InterpolationSyntaxError, config.InterpolationSyntaxError,
configparser.InterpolationError, configparser.InterpolationError,
@ -207,47 +190,49 @@ class Application(QApplication):
msgbox.exec_() msgbox.exec_()
# We didn't really initialize much so far, so we just quit hard. # We didn't really initialize much so far, so we just quit hard.
sys.exit(1) sys.exit(1)
self.stateconfig = ReadWriteConfigParser(confdir, 'state') self.stateconfig = iniparsers.ReadWriteConfigParser(confdir, 'state')
self.cmd_history = LineConfigParser(confdir, 'cmd_history', self.cmd_history = lineparser.LineConfigParser(
('completion', 'history-length')) confdir, 'cmd_history', ('completion', 'history-length'))
def _init_modes(self): def _init_modes(self):
"""Inizialize the mode manager and the keyparsers.""" """Inizialize the mode manager and the keyparsers."""
self._keyparsers = { self._keyparsers = {
KeyMode.normal: utypes.KeyMode.normal:
NormalKeyParser(self), modeparsers.NormalKeyParser(self),
KeyMode.hint: utypes.KeyMode.hint:
HintKeyParser(self), modeparsers.HintKeyParser(self),
KeyMode.insert: utypes.KeyMode.insert:
PassthroughKeyParser('keybind.insert', self), keyparser.PassthroughKeyParser('keybind.insert', self),
KeyMode.passthrough: utypes.KeyMode.passthrough:
PassthroughKeyParser('keybind.passthrough', self), keyparser.PassthroughKeyParser('keybind.passthrough', self),
KeyMode.command: utypes.KeyMode.command:
PassthroughKeyParser('keybind.command', self), keyparser.PassthroughKeyParser('keybind.command', self),
KeyMode.prompt: utypes.KeyMode.prompt:
PassthroughKeyParser('keybind.prompt', self, warn=False), keyparser.PassthroughKeyParser('keybind.prompt', self,
KeyMode.yesno: warn=False),
PromptKeyParser(self), utypes.KeyMode.yesno:
modeparsers.PromptKeyParser(self),
} }
self.modeman = ModeManager(self) self.modeman = modeman.ModeManager(self)
self.modeman.register(KeyMode.normal, self.modeman.register(utypes.KeyMode.normal,
self._keyparsers[KeyMode.normal].handle) self._keyparsers[utypes.KeyMode.normal].handle)
self.modeman.register(KeyMode.hint, self.modeman.register(utypes.KeyMode.hint,
self._keyparsers[KeyMode.hint].handle) self._keyparsers[utypes.KeyMode.hint].handle)
self.modeman.register(KeyMode.insert, self.modeman.register(utypes.KeyMode.insert,
self._keyparsers[KeyMode.insert].handle, self._keyparsers[utypes.KeyMode.insert].handle,
passthrough=True) passthrough=True)
self.modeman.register(KeyMode.passthrough, self.modeman.register(
self._keyparsers[KeyMode.passthrough].handle, utypes.KeyMode.passthrough,
self._keyparsers[utypes.KeyMode.passthrough].handle,
passthrough=True)
self.modeman.register(utypes.KeyMode.command,
self._keyparsers[utypes.KeyMode.command].handle,
passthrough=True) passthrough=True)
self.modeman.register(KeyMode.command, self.modeman.register(utypes.KeyMode.prompt,
self._keyparsers[KeyMode.command].handle, self._keyparsers[utypes.KeyMode.prompt].handle,
passthrough=True) passthrough=True)
self.modeman.register(KeyMode.prompt, self.modeman.register(utypes.KeyMode.yesno,
self._keyparsers[KeyMode.prompt].handle, self._keyparsers[utypes.KeyMode.yesno].handle)
passthrough=True)
self.modeman.register(KeyMode.yesno,
self._keyparsers[KeyMode.yesno].handle)
def _init_misc(self): def _init_misc(self):
"""Initialize misc things.""" """Initialize misc things."""
@ -263,7 +248,7 @@ class Application(QApplication):
self.setApplicationName("qutebrowser") self.setApplicationName("qutebrowser")
self.setApplicationVersion(qutebrowser.__version__) self.setApplicationVersion(qutebrowser.__version__)
self.messagebridge = message.MessageBridge(self) self.messagebridge = message.MessageBridge(self)
self.rl_bridge = ReadlineBridge() self.rl_bridge = readline.ReadlineBridge()
def _handle_segfault(self): def _handle_segfault(self):
"""Handle a segfault from a previous run.""" """Handle a segfault from a previous run."""
@ -272,8 +257,8 @@ class Application(QApplication):
# However this also means if the logfile is there for some weird # However this also means if the logfile is there for some weird
# reason, we'll *always* log to stderr, but that's still better than no # reason, we'll *always* log to stderr, but that's still better than no
# dialogs at all. # dialogs at all.
logname = os.path.join(get_standard_dir(QStandardPaths.DataLocation), path = utils.get_standard_dir(QStandardPaths.DataLocation)
'crash.log') logname = os.path.join(path, 'crash.log')
# First check if an old logfile exists. # First check if an old logfile exists.
if os.path.exists(logname): if os.path.exists(logname):
with open(logname, 'r', encoding='ascii') as f: with open(logname, 'r', encoding='ascii') as f:
@ -287,7 +272,7 @@ class Application(QApplication):
log.init.warning("Could not remove crash log!") log.init.warning("Could not remove crash log!")
else: else:
self._init_crashlogfile() self._init_crashlogfile()
self._crashdlg = FatalCrashDialog(data) self._crashdlg = crash.FatalCrashDialog(data)
self._crashdlg.show() self._crashdlg.show()
else: else:
# Crashlog exists but without data. # Crashlog exists but without data.
@ -307,8 +292,8 @@ class Application(QApplication):
def _init_crashlogfile(self): def _init_crashlogfile(self):
"""Start a new logfile and redirect faulthandler to it.""" """Start a new logfile and redirect faulthandler to it."""
logname = os.path.join(get_standard_dir(QStandardPaths.DataLocation), path = utils.get_standard_dir(QStandardPaths.DataLocation)
'crash.log') logname = os.path.join(path, 'crash.log')
self._crashlogfile = open(logname, 'w', encoding='ascii') self._crashlogfile = open(logname, 'w', encoding='ascii')
faulthandler.enable(self._crashlogfile) faulthandler.enable(self._crashlogfile)
if (hasattr(faulthandler, 'register') and if (hasattr(faulthandler, 'register') and
@ -360,7 +345,7 @@ class Application(QApplication):
""" """
signal.signal(signal.SIGINT, self.interrupt) signal.signal(signal.SIGINT, self.interrupt)
signal.signal(signal.SIGTERM, self.interrupt) signal.signal(signal.SIGTERM, self.interrupt)
timer = Timer(self, 'python_hacks') timer = utypes.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)
@ -392,15 +377,16 @@ class Application(QApplication):
cmd.got_search_rev.connect(self.searchrunner.search_rev) cmd.got_search_rev.connect(self.searchrunner.search_rev)
cmd.returnPressed.connect(tabs.setFocus) cmd.returnPressed.connect(tabs.setFocus)
self.searchrunner.do_search.connect(tabs.search) self.searchrunner.do_search.connect(tabs.search)
kp[KeyMode.normal].keystring_updated.connect(status.keystring.setText) kp[utypes.KeyMode.normal].keystring_updated.connect(
status.keystring.setText)
tabs.got_cmd.connect(self.commandrunner.run_safely) tabs.got_cmd.connect(self.commandrunner.run_safely)
# hints # hints
kp[KeyMode.hint].fire_hint.connect(tabs.fire_hint) kp[utypes.KeyMode.hint].fire_hint.connect(tabs.fire_hint)
kp[KeyMode.hint].filter_hints.connect(tabs.filter_hints) kp[utypes.KeyMode.hint].filter_hints.connect(tabs.filter_hints)
kp[KeyMode.hint].keystring_updated.connect(tabs.handle_hint_key) kp[utypes.KeyMode.hint].keystring_updated.connect(tabs.handle_hint_key)
tabs.hint_strings_updated.connect( tabs.hint_strings_updated.connect(
kp[KeyMode.hint].on_hint_strings_updated) kp[utypes.KeyMode.hint].on_hint_strings_updated)
# messages # messages
self.messagebridge.s_error.connect(status.disp_error) self.messagebridge.s_error.connect(status.disp_error)
@ -413,8 +399,8 @@ class Application(QApplication):
# config # config
self.config.style_changed.connect(style.invalidate_caches) self.config.style_changed.connect(style.invalidate_caches)
for obj in (tabs, completion, self.mainwindow, self.cmd_history, for obj in (tabs, completion, self.mainwindow, self.cmd_history,
websettings, kp[KeyMode.normal], self.modeman, status, websettings, kp[utypes.KeyMode.normal], self.modeman,
status.txt): status, status.txt):
self.config.changed.connect(obj.on_config_changed) self.config.changed.connect(obj.on_config_changed)
# statusbar # statusbar
@ -498,7 +484,8 @@ class Application(QApplication):
def _save_geometry(self): def _save_geometry(self):
"""Save the window geometry to the state config.""" """Save the window geometry to the state config."""
geom = b64encode(bytes(self.mainwindow.saveGeometry())).decode('ASCII') data = bytes(self.mainwindow.saveGeometry())
geom = base64.b64encode(data).decode('ASCII')
try: try:
self.stateconfig.add_section('geometry') self.stateconfig.add_section('geometry')
except configparser.DuplicateSectionError: except configparser.DuplicateSectionError:
@ -530,7 +517,7 @@ class Application(QApplication):
""" """
# pylint: disable=broad-except # pylint: disable=broad-except
if exctype is BdbQuit or not issubclass(exctype, Exception): if exctype is bdb.BdbQuit or not issubclass(exctype, Exception):
# pdb exit, KeyboardInterrupt, ... # pdb exit, KeyboardInterrupt, ...
try: try:
self.shutdown() self.shutdown()
@ -580,8 +567,8 @@ class Application(QApplication):
log.destroy.debug("Error while preventing shutdown: {}: {}".format( log.destroy.debug("Error while preventing shutdown: {}: {}".format(
e.__class__.__name__, e)) e.__class__.__name__, e))
QApplication.closeAllWindows() QApplication.closeAllWindows()
self._crashdlg = ExceptionCrashDialog(pages, history, exc, widgets, self._crashdlg = crash.ExceptionCrashDialog(pages, history, exc,
objects) widgets, objects)
ret = self._crashdlg.exec_() ret = self._crashdlg.exec_()
if ret == QDialog.Accepted: # restore if ret == QDialog.Accepted: # restore
self.restart(shutdown=False, pages=pages) self.restart(shutdown=False, pages=pages)
@ -655,7 +642,7 @@ class Application(QApplication):
history = self.mainwindow.status.cmd.history[-5:] history = self.mainwindow.status.cmd.history[-5:]
widgets = self.get_all_widgets() widgets = self.get_all_widgets()
objects = self.get_all_objects() objects = self.get_all_objects()
self._crashdlg = ReportDialog(pages, history, widgets, objects) self._crashdlg = crash.ReportDialog(pages, history, widgets, objects)
self._crashdlg.show() self._crashdlg.show()
@cmdutils.register(instance='', debug=True, name='debug-console') @cmdutils.register(instance='', debug=True, name='debug-console')
@ -674,7 +661,7 @@ class Application(QApplication):
signal.signal(signal.SIGINT, self.interrupt_forcefully) signal.signal(signal.SIGINT, self.interrupt_forcefully)
signal.signal(signal.SIGTERM, self.interrupt_forcefully) signal.signal(signal.SIGTERM, self.interrupt_forcefully)
# If we call shutdown directly here, we get a segfault. # If we call shutdown directly here, we get a segfault.
QTimer.singleShot(0, partial(self.shutdown, 128 + signum)) QTimer.singleShot(0, functools.partial(self.shutdown, 128 + signum))
def interrupt_forcefully(self, signum, _frame): def interrupt_forcefully(self, signum, _frame):
"""Interrupt forcefully on the second SIGINT/SIGTERM request. """Interrupt forcefully on the second SIGINT/SIGTERM request.
@ -689,7 +676,7 @@ class Application(QApplication):
signal.signal(signal.SIGTERM, self.interrupt_really_forcefully) signal.signal(signal.SIGTERM, self.interrupt_really_forcefully)
# This *should* work without a QTimer, but because of the trouble in # This *should* work without a QTimer, but because of the trouble in
# self.interrupt we're better safe than sorry. # self.interrupt we're better safe than sorry.
QTimer.singleShot(0, partial(self.exit, 128 + signum)) QTimer.singleShot(0, functools.partial(self.exit, 128 + signum))
def interrupt_really_forcefully(self, signum, _frame): def interrupt_really_forcefully(self, signum, _frame):
"""Interrupt with even more force on the third SIGINT/SIGTERM request. """Interrupt with even more force on the third SIGINT/SIGTERM request.
@ -722,7 +709,7 @@ class Application(QApplication):
# in the real main event loop, or we'll get a segfault. # in the real main event loop, or we'll get a segfault.
log.destroy.debug("Deferring real shutdown because question was " log.destroy.debug("Deferring real shutdown because question was "
"active.") "active.")
QTimer.singleShot(0, partial(self._shutdown, status)) QTimer.singleShot(0, functools.partial(self._shutdown, status))
else: else:
# If we have no questions to shut down, we are already in the real # If we have no questions to shut down, we are already in the real
# event loop, so we can shut down immediately. # event loop, so we can shut down immediately.
@ -773,7 +760,7 @@ class Application(QApplication):
log.destroy.debug("Deferring QApplication::exit...") log.destroy.debug("Deferring QApplication::exit...")
# We use a singleshot timer to exit here to minimize the likelyhood of # We use a singleshot timer to exit here to minimize the likelyhood of
# segfaults. # segfaults.
QTimer.singleShot(0, partial(self.exit, status)) QTimer.singleShot(0, functools.partial(self.exit, status))
def exit(self, status): def exit(self, status):
"""Extend QApplication::exit to log the event.""" """Extend QApplication::exit to log the event."""

View File

@ -29,19 +29,14 @@ from PyQt5.QtGui import QClipboard
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
from PyQt5.QtWebKitWidgets import QWebInspector from PyQt5.QtWebKitWidgets import QWebInspector
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import userscripts
import qutebrowser.config.config as config from qutebrowser.commands import utils as cmdutils
import qutebrowser.browser.hints as hints from qutebrowser.commands import exceptions as cmdexc
import qutebrowser.utils.message as message from qutebrowser.config import config
import qutebrowser.utils.webelem as webelem from qutebrowser.browser import hints, quickmarks
import qutebrowser.browser.quickmarks as quickmarks from qutebrowser.utils import message, webelem, editor, usertypes, log
import qutebrowser.utils.log as log from qutebrowser.utils import qt as qtutils
import qutebrowser.utils.url as urlutils from qutebrowser.utils import url as urlutils
import qutebrowser.commands.userscripts as userscripts
from qutebrowser.utils.qt import check_overflow, check_print_compat
from qutebrowser.utils.editor import ExternalEditor
from qutebrowser.commands.exceptions import CommandError
from qutebrowser.utils.usertypes import KeyMode
class CommandDispatcher: class CommandDispatcher:
@ -82,7 +77,7 @@ class CommandDispatcher:
perc = int(count) perc = int(count)
else: else:
perc = float(perc) perc = float(perc)
perc = check_overflow(perc, 'int', fatal=False) perc = qtutils.check_overflow(perc, 'int', fatal=False)
frame = self._tabs.currentWidget().page().currentFrame() frame = self._tabs.currentWidget().page().currentFrame()
m = frame.scrollBarMaximum(orientation) m = frame.scrollBarMaximum(orientation)
if m == 0: if m == 0:
@ -94,7 +89,7 @@ class CommandDispatcher:
widget = self._tabs.currentWidget() widget = self._tabs.currentWidget()
frame = widget.page().currentFrame() frame = widget.page().currentFrame()
if frame is None: if frame is None:
raise CommandError("No frame focused!") raise cmdexc.CommandError("No frame focused!")
widget.hintmanager.follow_prevnext(frame, self._tabs.current_url(), widget.hintmanager.follow_prevnext(frame, self._tabs.current_url(),
prev, newtab) prev, newtab)
@ -130,10 +125,10 @@ class CommandDispatcher:
def _tab_focus_last(self): def _tab_focus_last(self):
"""Select the tab which was last focused.""" """Select the tab which was last focused."""
if self._tabs.last_focused is None: if self._tabs.last_focused is None:
raise CommandError("No last focused tab!") raise cmdexc.CommandError("No last focused tab!")
idx = self._tabs.indexOf(self._tabs.last_focused) idx = self._tabs.indexOf(self._tabs.last_focused)
if idx == -1: if idx == -1:
raise CommandError("Last focused tab vanished!") raise cmdexc.CommandError("Last focused tab vanished!")
self._tabs.setCurrentIndex(idx) self._tabs.setCurrentIndex(idx)
def _editor_cleanup(self, oshandle, filename): def _editor_cleanup(self, oshandle, filename):
@ -142,7 +137,7 @@ class CommandDispatcher:
try: try:
os.remove(filename) os.remove(filename)
except PermissionError: except PermissionError:
raise CommandError("Failed to delete tempfile...") raise cmdexc.CommandError("Failed to delete tempfile...")
@cmdutils.register(instance='mainwindow.tabs.cmd') @cmdutils.register(instance='mainwindow.tabs.cmd')
def tab_close(self, count=None): def tab_close(self, count=None):
@ -173,7 +168,7 @@ class CommandDispatcher:
try: try:
url = urlutils.fuzzy_url(urlstr) url = urlutils.fuzzy_url(urlstr)
except urlutils.FuzzyUrlError as e: except urlutils.FuzzyUrlError as e:
raise CommandError(e) raise cmdexc.CommandError(e)
if tab is None: if tab is None:
if count is None: if count is None:
# We want to open a URL in the current tab, but none exists # We want to open a URL in the current tab, but none exists
@ -214,9 +209,9 @@ class CommandDispatcher:
Args: Args:
count: The tab index to print, or None. count: The tab index to print, or None.
""" """
if not check_print_compat(): if not qtutils.check_print_compat():
raise CommandError("Printing on Qt < 5.3.0 on Windows is broken, " raise cmdexc.CommandError(
"please upgrade!") "Printing on Qt < 5.3.0 on Windows is broken, please upgrade!")
tab = self._tabs.cntwidget(count) tab = self._tabs.cntwidget(count)
if tab is not None: if tab is not None:
preview = QPrintPreviewDialog() preview = QPrintPreviewDialog()
@ -231,9 +226,9 @@ class CommandDispatcher:
Args: Args:
count: The tab index to print, or None. count: The tab index to print, or None.
""" """
if not check_print_compat(): if not qtutils.check_print_compat():
raise CommandError("Printing on Qt < 5.3.0 on Windows is broken, " raise cmdexc.CommandError(
"please upgrade!") "Printing on Qt < 5.3.0 on Windows is broken, please upgrade!")
tab = self._tabs.cntwidget(count) tab = self._tabs.cntwidget(count)
if tab is not None: if tab is not None:
printdiag = QPrintDialog() printdiag = QPrintDialog()
@ -303,15 +298,17 @@ class CommandDispatcher:
widget = self._tabs.currentWidget() widget = self._tabs.currentWidget()
frame = widget.page().mainFrame() frame = widget.page().mainFrame()
if frame is None: if frame is None:
raise CommandError("No frame focused!") raise cmdexc.CommandError("No frame focused!")
try: try:
group_enum = webelem.Group[group.replace('-', '_')] group_enum = webelem.Group[group.replace('-', '_')]
except KeyError: except KeyError:
raise CommandError("Unknown hinting group {}!".format(group)) raise cmdexc.CommandError("Unknown hinting group {}!".format(
group))
try: try:
target_enum = hints.Target[target.replace('-', '_')] target_enum = hints.Target[target.replace('-', '_')]
except KeyError: except KeyError:
raise CommandError("Unknown hinting target {}!".format(target)) raise cmdexc.CommandError("Unknown hinting target {}!".format(
target))
widget.hintmanager.start(frame, self._tabs.current_url(), group_enum, widget.hintmanager.start(frame, self._tabs.current_url(), group_enum,
target_enum, *args) target_enum, *args)
@ -488,7 +485,7 @@ class CommandDispatcher:
try: try:
level = cmdutils.arg_or_count(zoom, count, default=100) level = cmdutils.arg_or_count(zoom, count, default=100)
except ValueError as e: except ValueError as e:
raise CommandError(e) raise cmdexc.CommandError(e)
tab = self._tabs.currentWidget() tab = self._tabs.currentWidget()
tab.zoom_perc(level) tab.zoom_perc(level)
@ -506,7 +503,7 @@ class CommandDispatcher:
try: try:
url = urlutils.fuzzy_url(urlstr) url = urlutils.fuzzy_url(urlstr)
except urlutils.FuzzyUrlError as e: except urlutils.FuzzyUrlError as e:
raise CommandError(e) raise cmdexc.CommandError(e)
self._tabs.tabopen(url, background=False, explicit=True) self._tabs.tabopen(url, background=False, explicit=True)
@cmdutils.register(instance='mainwindow.tabs.cmd', split=False) @cmdutils.register(instance='mainwindow.tabs.cmd', split=False)
@ -515,7 +512,7 @@ class CommandDispatcher:
try: try:
url = urlutils.fuzzy_url(urlstr) url = urlutils.fuzzy_url(urlstr)
except urlutils.FuzzyUrlError as e: except urlutils.FuzzyUrlError as e:
raise CommandError(e) raise cmdexc.CommandError(e)
self._tabs.tabopen(url, background=True, explicit=True) self._tabs.tabopen(url, background=True, explicit=True)
@cmdutils.register(instance='mainwindow.tabs.cmd') @cmdutils.register(instance='mainwindow.tabs.cmd')
@ -524,7 +521,7 @@ class CommandDispatcher:
if self._tabs.url_stack: if self._tabs.url_stack:
self._tabs.tabopen(self._tabs.url_stack.pop()) self._tabs.tabopen(self._tabs.url_stack.pop())
else: else:
raise CommandError("Nothing to undo!") raise cmdexc.CommandError("Nothing to undo!")
@cmdutils.register(instance='mainwindow.tabs.cmd') @cmdutils.register(instance='mainwindow.tabs.cmd')
def tab_prev(self, count=1): def tab_prev(self, count=1):
@ -539,7 +536,7 @@ class CommandDispatcher:
elif config.get('tabs', 'wrap'): elif config.get('tabs', 'wrap'):
self._tabs.setCurrentIndex(newidx % self._tabs.count()) self._tabs.setCurrentIndex(newidx % self._tabs.count())
else: else:
raise CommandError("First tab") raise cmdexc.CommandError("First tab")
@cmdutils.register(instance='mainwindow.tabs.cmd') @cmdutils.register(instance='mainwindow.tabs.cmd')
def tab_next(self, count=1): def tab_next(self, count=1):
@ -554,7 +551,7 @@ class CommandDispatcher:
elif config.get('tabs', 'wrap'): elif config.get('tabs', 'wrap'):
self._tabs.setCurrentIndex(newidx % self._tabs.count()) self._tabs.setCurrentIndex(newidx % self._tabs.count())
else: else:
raise CommandError("Last tab") raise cmdexc.CommandError("Last tab")
@cmdutils.register(instance='mainwindow.tabs.cmd', nargs=(0, 1)) @cmdutils.register(instance='mainwindow.tabs.cmd', nargs=(0, 1))
def paste(self, sel=False, tab=False): def paste(self, sel=False, tab=False):
@ -573,12 +570,12 @@ class CommandDispatcher:
target = "Clipboard" target = "Clipboard"
text = clipboard.text(mode) text = clipboard.text(mode)
if not text: if not text:
raise CommandError("{} is empty.".format(target)) raise cmdexc.CommandError("{} is empty.".format(target))
log.misc.debug("{} contained: '{}'".format(target, text)) log.misc.debug("{} contained: '{}'".format(target, text))
try: try:
url = urlutils.fuzzy_url(text) url = urlutils.fuzzy_url(text)
except urlutils.FuzzyUrlError as e: except urlutils.FuzzyUrlError as e:
raise CommandError(e) raise cmdexc.CommandError(e)
if tab: if tab:
self._tabs.tabopen(url, explicit=True) self._tabs.tabopen(url, explicit=True)
else: else:
@ -610,12 +607,13 @@ class CommandDispatcher:
idx = cmdutils.arg_or_count(index, count, default=1, idx = cmdutils.arg_or_count(index, count, default=1,
countzero=self._tabs.count()) countzero=self._tabs.count())
except ValueError as e: except ValueError as e:
raise CommandError(e) raise cmdexc.CommandError(e)
cmdutils.check_overflow(idx + 1, 'int') cmdutils.check_overflow(idx + 1, 'int')
if 1 <= idx <= self._tabs.count(): if 1 <= idx <= self._tabs.count():
self._tabs.setCurrentIndex(idx - 1) self._tabs.setCurrentIndex(idx - 1)
else: else:
raise CommandError("There's no tab with index {}!".format(idx)) raise cmdexc.CommandError("There's no tab with index {}!".format(
idx))
@cmdutils.register(instance='mainwindow.tabs.cmd') @cmdutils.register(instance='mainwindow.tabs.cmd')
def tab_move(self, direction=None, count=None): def tab_move(self, direction=None, count=None):
@ -632,11 +630,13 @@ class CommandDispatcher:
try: try:
new_idx = self._tab_move_relative(direction, count) new_idx = self._tab_move_relative(direction, count)
except ValueError: except ValueError:
raise CommandError("Count must be given for relative moving!") raise cmdexc.CommandError("Count must be given for relative "
"moving!")
else: else:
raise CommandError("Invalid direction '{}'!".format(direction)) raise cmdexc.CommandError("Invalid direction '{}'!".format(
direction))
if not 0 <= new_idx < self._tabs.count(): if not 0 <= new_idx < self._tabs.count():
raise CommandError("Can't move tab to position {}!".format( raise cmdexc.CommandError("Can't move tab to position {}!".format(
new_idx)) new_idx))
tab = self._tabs.currentWidget() tab = self._tabs.currentWidget()
cur_idx = self._tabs.currentIndex() cur_idx = self._tabs.currentIndex()
@ -697,7 +697,7 @@ class CommandDispatcher:
urlstr = quickmarks.get(name) urlstr = quickmarks.get(name)
url = QUrl(urlstr) url = QUrl(urlstr)
if not url.isValid(): if not url.isValid():
raise CommandError("Invalid URL {} ({})".format( raise cmdexc.CommandError("Invalid URL {} ({})".format(
urlstr, url.errorString())) urlstr, url.errorString()))
self._tabs.currentWidget().openurl(url) self._tabs.currentWidget().openurl(url)
@ -719,8 +719,9 @@ class CommandDispatcher:
cur = self._tabs.currentWidget() cur = self._tabs.currentWidget()
if cur.inspector is None: if cur.inspector is None:
if not config.get('general', 'developer-extras'): if not config.get('general', 'developer-extras'):
raise CommandError("Please enable developer-extras before " raise cmdexc.CommandError(
"using the webinspector!") "Please enable developer-extras before using the "
"webinspector!")
cur.inspector = QWebInspector() cur.inspector = QWebInspector()
cur.inspector.setPage(cur.page()) cur.inspector.setPage(cur.page())
cur.inspector.show() cur.inspector.show()
@ -728,8 +729,9 @@ class CommandDispatcher:
cur.inspector.hide() cur.inspector.hide()
else: else:
if not config.get('general', 'developer-extras'): if not config.get('general', 'developer-extras'):
raise CommandError("Please enable developer-extras before " raise cmdexc.CommandError(
"using the webinspector!") "Please enable developer-extras before using the "
"webinspector!")
else: else:
cur.inspector.show() cur.inspector.show()
@ -739,7 +741,8 @@ class CommandDispatcher:
page = self._tabs.currentWidget().page() page = self._tabs.currentWidget().page()
self._tabs.download_get.emit(self._tabs.current_url(), page) self._tabs.download_get.emit(self._tabs.current_url(), page)
@cmdutils.register(instance='mainwindow.tabs.cmd', modes=[KeyMode.insert], @cmdutils.register(instance='mainwindow.tabs.cmd',
modes=[usertypes.KeyMode.insert],
hide=True) hide=True)
def open_editor(self): def open_editor(self):
"""Open an external editor with the currently selected form field. """Open an external editor with the currently selected form field.
@ -756,14 +759,14 @@ class CommandDispatcher:
frame = self._tabs.currentWidget().page().currentFrame() frame = self._tabs.currentWidget().page().currentFrame()
elem = webelem.focus_elem(frame) elem = webelem.focus_elem(frame)
if elem.isNull(): if elem.isNull():
raise CommandError("No element focused!") raise cmdexc.CommandError("No element focused!")
if not webelem.is_editable(elem, strict=True): if not webelem.is_editable(elem, strict=True):
raise CommandError("Focused element is not editable!") raise cmdexc.CommandError("Focused element is not editable!")
if webelem.is_content_editable(elem): if webelem.is_content_editable(elem):
text = elem.toPlainText() text = elem.toPlainText()
else: else:
text = elem.evaluateJavaScript('this.value') text = elem.evaluateJavaScript('this.value')
self._editor = ExternalEditor(self._tabs) self._editor = editor.ExternalEditor(self._tabs)
self._editor.editing_finished.connect( self._editor.editing_finished.connect(
partial(self.on_editing_finished, elem)) partial(self.on_editing_finished, elem))
self._editor.edit(text) self._editor.edit(text)
@ -778,7 +781,7 @@ class CommandDispatcher:
text: The new text to insert. text: The new text to insert.
""" """
if elem.isNull(): if elem.isNull():
raise CommandError("Element vanished while editing!") raise cmdexc.CommandError("Element vanished while editing!")
if webelem.is_content_editable(elem): if webelem.is_content_editable(elem):
log.misc.debug("Filling element {} via setPlainText.".format( log.misc.debug("Filling element {} via setPlainText.".format(
webelem.debug_text(elem))) webelem.debug_text(elem)))

View File

@ -22,9 +22,8 @@
from PyQt5.QtNetwork import QNetworkCookie, QNetworkCookieJar from PyQt5.QtNetwork import QNetworkCookie, QNetworkCookieJar
from PyQt5.QtCore import QStandardPaths, QDateTime from PyQt5.QtCore import QStandardPaths, QDateTime
import qutebrowser.config.config as config from qutebrowser.config import config, lineparser
from qutebrowser.config.lineparser import LineConfigParser from qutebrowser.utils import misc as utils
from qutebrowser.utils.misc import get_standard_dir
class CookieJar(QNetworkCookieJar): class CookieJar(QNetworkCookieJar):
@ -33,8 +32,8 @@ class CookieJar(QNetworkCookieJar):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
datadir = get_standard_dir(QStandardPaths.DataLocation) datadir = utils.get_standard_dir(QStandardPaths.DataLocation)
self._linecp = LineConfigParser(datadir, 'cookies') self._linecp = lineparser.LineConfigParser(datadir, 'cookies')
cookies = [] cookies = []
for line in self._linecp: for line in self._linecp:
cookies += QNetworkCookie.parseCookies(line.encode('utf-8')) cookies += QNetworkCookie.parseCookies(line.encode('utf-8'))

View File

@ -21,21 +21,19 @@
import os import os
import os.path import os.path
from functools import partial import functools
from collections import deque import collections
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QTimer, QStandardPaths from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QTimer, QStandardPaths
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.utils.message as message from qutebrowser.commands import utils as cmdutils
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import exceptions as cmdexc
import qutebrowser.utils.misc as utils from qutebrowser.utils import message, http, usertypes
from qutebrowser.utils.http import parse_content_disposition from qutebrowser.utils import misc as utils
from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.log import downloads as logger from qutebrowser.utils.log import downloads as logger
from qutebrowser.utils.usertypes import PromptMode, Question, Timer
from qutebrowser.utils.qt import qt_ensure_valid
from qutebrowser.commands.exceptions import CommandError
class DownloadItem(QObject): class DownloadItem(QObject):
@ -92,7 +90,7 @@ class DownloadItem(QObject):
self.basename = '???' self.basename = '???'
samples = int(self.SPEED_AVG_WINDOW * samples = int(self.SPEED_AVG_WINDOW *
(1000 / self.SPEED_REFRESH_INTERVAL)) (1000 / self.SPEED_REFRESH_INTERVAL))
self.speed_avg = deque(maxlen=samples) self.speed_avg = collections.deque(maxlen=samples)
self.fileobj = None self.fileobj = None
self.filename = None self.filename = None
self.is_cancelled = False self.is_cancelled = False
@ -111,7 +109,7 @@ class DownloadItem(QObject):
QTimer.singleShot(0, lambda: self.error.emit(reply.errorString())) QTimer.singleShot(0, lambda: self.error.emit(reply.errorString()))
if reply.isFinished(): if reply.isFinished():
QTimer.singleShot(0, self.finished.emit) QTimer.singleShot(0, self.finished.emit)
self.timer = Timer(self, 'speed_refresh') self.timer = usertypes.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()
@ -349,7 +347,7 @@ class DownloadManager(QObject):
url: The URL to get, as QUrl url: The URL to get, as QUrl
page: The QWebPage to get the download from. page: The QWebPage to get the download from.
""" """
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
req = QNetworkRequest(url) req = QNetworkRequest(url)
reply = page.networkAccessManager().get(req) reply = page.networkAccessManager().get(req)
self.fetch(reply) self.fetch(reply)
@ -362,7 +360,7 @@ class DownloadManager(QObject):
try: try:
download = self.downloads[count - 1] download = self.downloads[count - 1]
except IndexError: except IndexError:
raise CommandError("There's no download {}!".format(count)) raise cmdexc.CommandError("There's no download {}!".format(count))
download.cancel() download.cancel()
@pyqtSlot('QNetworkReply') @pyqtSlot('QNetworkReply')
@ -372,25 +370,27 @@ class DownloadManager(QObject):
Args: Args:
reply: The QNetworkReply to download. reply: The QNetworkReply to download.
""" """
_inline, suggested_filename = parse_content_disposition(reply) _inline, suggested_filename = http.parse_content_disposition(reply)
logger.debug("fetch: {} -> {}".format(reply.url(), suggested_filename)) logger.debug("fetch: {} -> {}".format(reply.url(), suggested_filename))
download = DownloadItem(reply, self) download = DownloadItem(reply, self)
download.finished.connect(partial(self.on_finished, download)) download.finished.connect(
download.data_changed.connect(partial(self.on_data_changed, download)) functools.partial(self.on_finished, download))
download.data_changed.connect(
functools.partial(self.on_data_changed, download))
download.error.connect(self.on_error) download.error.connect(self.on_error)
download.basename = suggested_filename download.basename = suggested_filename
self.download_about_to_be_added.emit(len(self.downloads) + 1) self.download_about_to_be_added.emit(len(self.downloads) + 1)
self.downloads.append(download) self.downloads.append(download)
self.download_added.emit() self.download_added.emit()
q = Question(self) q = usertypes.Question(self)
q.text = "Save file to:" q.text = "Save file to:"
q.mode = PromptMode.text q.mode = usertypes.PromptMode.text
q.default = suggested_filename q.default = suggested_filename
q.answered.connect(download.set_filename) q.answered.connect(download.set_filename)
q.cancelled.connect(download.cancel) q.cancelled.connect(download.cancel)
q.completed.connect(q.deleteLater) q.completed.connect(q.deleteLater)
q.destroyed.connect(partial(self.questions.remove, q)) q.destroyed.connect(functools.partial(self.questions.remove, q))
self.questions.append(q) self.questions.append(q)
download.cancelled.connect(q.abort) download.cancelled.connect(q.abort)
message.instance().ask(q, blocking=False) message.instance().ask(q, blocking=False)

View File

@ -21,28 +21,28 @@
import math import math
import subprocess import subprocess
from collections import namedtuple import collections
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl
from PyQt5.QtGui import QMouseEvent, QClipboard from PyQt5.QtGui import QMouseEvent, QClipboard
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.keyinput.modeman as modeman from qutebrowser.keyinput import modeman
import qutebrowser.utils.message as message from qutebrowser.utils import message, webelem
import qutebrowser.utils.webelem as webelem from qutebrowser.commands import userscripts
import qutebrowser.commands.userscripts as userscripts from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.commands.exceptions import CommandError from qutebrowser.utils import usertypes
from qutebrowser.utils.usertypes import enum, KeyMode from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.log import hints as logger from qutebrowser.utils.log import hints as logger
from qutebrowser.utils.qt import qt_ensure_valid
ElemTuple = namedtuple('ElemTuple', 'elem, label') ElemTuple = collections.namedtuple('ElemTuple', 'elem, label')
Target = enum('Target', 'normal', 'tab', 'tab_bg', 'yank', 'yank_primary', Target = usertypes.enum('Target', 'normal', 'tab', 'tab_bg', 'yank',
'fill', 'rapid', 'download', 'userscript', 'spawn') 'yank_primary', 'fill', 'rapid', 'download',
'userscript', 'spawn')
class HintContext: class HintContext:
@ -340,7 +340,7 @@ class HintManager(QObject):
Args: Args:
url: The URL to open as a QURL. url: The URL to open as a QURL.
""" """
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
sel = self._context.target == Target.yank_primary sel = self._context.target == Target.yank_primary
mode = QClipboard.Selection if sel else QClipboard.Clipboard mode = QClipboard.Selection if sel else QClipboard.Clipboard
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword) urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
@ -354,7 +354,7 @@ class HintManager(QObject):
Args: Args:
url: The URL to open as a QUrl. url: The URL to open as a QUrl.
""" """
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
urlstr = url.toDisplayString(QUrl.FullyEncoded) urlstr = url.toDisplayString(QUrl.FullyEncoded)
args = self._context.get_args(urlstr) args = self._context.get_args(urlstr)
message.set_cmd_text(' '.join(args)) message.set_cmd_text(' '.join(args))
@ -370,19 +370,19 @@ class HintManager(QObject):
message.error("No suitable link found for this element.", message.error("No suitable link found for this element.",
immediately=True) immediately=True)
return return
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
self.download_get.emit(url, elem.webFrame().page()) self.download_get.emit(url, elem.webFrame().page())
def _call_userscript(self, url): def _call_userscript(self, url):
"""Call an userscript from a hint.""" """Call an userscript from a hint."""
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
cmd = self._context.args[0] cmd = self._context.args[0]
args = self._context.args[1:] args = self._context.args[1:]
userscripts.run(cmd, *args, url=url) userscripts.run(cmd, *args, url=url)
def _spawn(self, url): def _spawn(self, url):
"""Spawn a simple command from a hint.""" """Spawn a simple command from a hint."""
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword) urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
args = self._context.get_args(urlstr) args = self._context.get_args(urlstr)
subprocess.Popen(args) subprocess.Popen(args)
@ -406,7 +406,7 @@ class HintManager(QObject):
url = QUrl(text) url = QUrl(text)
if url.isRelative(): if url.isRelative():
url = baseurl.resolved(url) url = baseurl.resolved(url)
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
return url return url
def _find_prevnext(self, frame, prev=False): def _find_prevnext(self, frame, prev=False):
@ -457,11 +457,11 @@ class HintManager(QObject):
""" """
elem = self._find_prevnext(frame, prev) elem = self._find_prevnext(frame, prev)
if elem is None: if elem is None:
raise CommandError("No {} links found!".format( raise cmdexc.CommandError("No {} links found!".format(
"prev" if prev else "forward")) "prev" if prev else "forward"))
url = self._resolve_url(elem, baseurl) url = self._resolve_url(elem, baseurl)
if url is None or not url.isValid(): if url is None or not url.isValid():
raise CommandError("No {} links found!".format( raise cmdexc.CommandError("No {} links found!".format(
"prev" if prev else "forward")) "prev" if prev else "forward"))
self.openurl.emit(url, newtab) self.openurl.emit(url, newtab)
@ -488,12 +488,13 @@ class HintManager(QObject):
raise ValueError("start() was called with frame=None") raise ValueError("start() was called with frame=None")
if target in (Target.userscript, Target.spawn, Target.fill): if target in (Target.userscript, Target.spawn, Target.fill):
if not args: if not args:
raise CommandError("Additional arguments are required with " raise cmdexc.CommandError(
"target userscript/spawn/fill.") "Additional arguments are required with target "
"userscript/spawn/fill.")
else: else:
if args: if args:
raise CommandError("Arguments are only allowed with target " raise cmdexc.CommandError(
"userscript/spawn.") "Arguments are only allowed with target userscript/spawn.")
elems = [] elems = []
ctx = HintContext() ctx = HintContext()
ctx.frames = webelem.get_child_frames(mainframe) ctx.frames = webelem.get_child_frames(mainframe)
@ -503,7 +504,7 @@ class HintManager(QObject):
visible_elems = [e for e in elems if filterfunc(e) and visible_elems = [e for e in elems if filterfunc(e) and
webelem.is_visible(e, mainframe)] webelem.is_visible(e, mainframe)]
if not visible_elems: if not visible_elems:
raise CommandError("No elements found.") raise cmdexc.CommandError("No elements found.")
ctx.target = target ctx.target = target
ctx.baseurl = baseurl ctx.baseurl = baseurl
ctx.args = args ctx.args = args
@ -516,7 +517,7 @@ class HintManager(QObject):
self._connect_frame_signals() self._connect_frame_signals()
self.hint_strings_updated.emit(strings) self.hint_strings_updated.emit(strings)
try: try:
modeman.enter(KeyMode.hint, 'HintManager.start') modeman.enter(usertypes.KeyMode.hint, 'HintManager.start')
except modeman.ModeLockedError: except modeman.ModeLockedError:
self._cleanup() self._cleanup()
@ -560,7 +561,7 @@ class HintManager(QObject):
visible[k] = e visible[k] = e
if not visible: if not visible:
# Whoops, filtered all hints # Whoops, filtered all hints
modeman.leave(KeyMode.hint, 'all filtered') modeman.leave(usertypes.KeyMode.hint, 'all filtered')
elif len(visible) == 1 and config.get('hints', 'auto-follow'): elif len(visible) == 1 and config.get('hints', 'auto-follow'):
# unpacking gets us the first (and only) key in the dict. # unpacking gets us the first (and only) key in the dict.
self.fire(*visible) self.fire(*visible)
@ -606,12 +607,12 @@ class HintManager(QObject):
else: else:
raise ValueError("No suitable handler found!") raise ValueError("No suitable handler found!")
if self._context.target != Target.rapid: if self._context.target != Target.rapid:
modeman.maybe_leave(KeyMode.hint, 'followed') modeman.maybe_leave(usertypes.KeyMode.hint, 'followed')
def follow_hint(self): def follow_hint(self):
"""Follow the currently selected hint.""" """Follow the currently selected hint."""
if not self._context.to_follow: if not self._context.to_follow:
raise CommandError("No hint to follow") raise cmdexc.CommandError("No hint to follow")
self.fire(self._context.to_follow, force=True) self.fire(self._context.to_follow, force=True)
@pyqtSlot('QSize') @pyqtSlot('QSize')
@ -627,16 +628,16 @@ class HintManager(QObject):
css = self._get_hint_css(elems.elem, elems.label) css = self._get_hint_css(elems.elem, elems.label)
elems.label.setAttribute('style', css) elems.label.setAttribute('style', css)
@pyqtSlot(KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_entered(self, mode): def on_mode_entered(self, mode):
"""Stop hinting when insert mode was entered.""" """Stop hinting when insert mode was entered."""
if mode == KeyMode.insert: if mode == usertypes.KeyMode.insert:
modeman.maybe_leave(KeyMode.hint, 'insert mode') modeman.maybe_leave(usertypes.KeyMode.hint, 'insert mode')
@pyqtSlot(KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode): def on_mode_left(self, mode):
"""Stop hinting when hinting mode was left.""" """Stop hinting when hinting mode was left."""
if mode != KeyMode.hint or self._context is None: if mode != usertypes.KeyMode.hint or self._context is None:
# We have one HintManager per tab, so when this gets called, # We have one HintManager per tab, so when this gets called,
# self._context might be None, because the current tab is not # self._context might be None, because the current tab is not
# hinting. # hinting.

View File

@ -24,29 +24,28 @@ OrderedDict. This is because we read them from a file at start and write them
to a file on shutdown, so it makes semse to keep them as strings her.e to a file on shutdown, so it makes semse to keep them as strings her.e
""" """
from functools import partial import functools
from collections import OrderedDict import collections
from PyQt5.QtCore import QStandardPaths, QUrl from PyQt5.QtCore import QStandardPaths, QUrl
import qutebrowser.utils.message as message from qutebrowser.utils import message, usertypes
import qutebrowser.commands.utils as cmdutils from qutebrowser.utils import misc as utils
from qutebrowser.utils.usertypes import PromptMode from qutebrowser.utils import qt as qtutils
from qutebrowser.config.lineparser import LineConfigParser from qutebrowser.commands import utils as cmdutils
from qutebrowser.utils.misc import get_standard_dir from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.utils.qt import qt_ensure_valid from qutebrowser.config import lineparser
from qutebrowser.commands.exceptions import CommandError
marks = OrderedDict() marks = collections.OrderedDict()
linecp = None linecp = None
def init(): def init():
"""Read quickmarks from the config file.""" """Read quickmarks from the config file."""
global linecp global linecp
confdir = get_standard_dir(QStandardPaths.ConfigLocation) confdir = utils.get_standard_dir(QStandardPaths.ConfigLocation)
linecp = LineConfigParser(confdir, 'quickmarks') linecp = lineparser.LineConfigParser(confdir, 'quickmarks')
for line in linecp: for line in linecp:
try: try:
key, url = line.split(maxsplit=1) key, url = line.split(maxsplit=1)
@ -68,10 +67,10 @@ def prompt_save(url):
Args: Args:
url: The quickmark url as a QUrl. url: The quickmark url as a QUrl.
""" """
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
message.ask_async("Add quickmark:", PromptMode.text, message.ask_async("Add quickmark:", usertypes.PromptMode.text,
partial(quickmark_add, urlstr)) functools.partial(quickmark_add, urlstr))
@cmdutils.register() @cmdutils.register()
@ -83,9 +82,9 @@ def quickmark_add(urlstr, name):
name: The name for the new quickmark. name: The name for the new quickmark.
""" """
if not name: if not name:
raise CommandError("Can't set mark with empty name!") raise cmdexc.CommandError("Can't set mark with empty name!")
if not urlstr: if not urlstr:
raise CommandError("Can't set mark with empty URL!") raise cmdexc.CommandError("Can't set mark with empty URL!")
def set_mark(): def set_mark():
"""Really set the quickmark.""" """Really set the quickmark."""
@ -101,10 +100,12 @@ def quickmark_add(urlstr, name):
def get(name): def get(name):
"""Get the URL of the quickmark named name as a QUrl.""" """Get the URL of the quickmark named name as a QUrl."""
if name not in marks: if name not in marks:
raise CommandError("Quickmark '{}' does not exist!".format(name)) raise cmdexc.CommandError(
"Quickmark '{}' does not exist!".format(name))
urlstr = marks[name] urlstr = marks[name]
url = QUrl(urlstr) url = QUrl(urlstr)
if not url.isValid(): if not url.isValid():
raise CommandError("Invalid URL for quickmark {}: {} ({})".format( raise cmdexc.CommandError(
name, urlstr, url.errorString())) "Invalid URL for quickmark {}: {} ({})".format(name, urlstr,
url.errorString()))
return url return url

View File

@ -19,12 +19,12 @@
"""A filter for signals which either filters or passes them.""" """A filter for signals which either filters or passes them."""
from functools import partial import functools
from PyQt5.QtCore import QObject from PyQt5.QtCore import QObject
from qutebrowser.utils.debug import dbg_signal, signal_name from qutebrowser.utils import debug
from qutebrowser.widgets.webview import WebView from qutebrowser.widgets import webview
from qutebrowser.utils.log import signals as logger from qutebrowser.utils.log import signals as logger
@ -58,10 +58,10 @@ class SignalFilter(QObject):
Return: Return:
A partial functon calling _filter_signals with a signal. A partial functon calling _filter_signals with a signal.
""" """
if not isinstance(tab, WebView): if not isinstance(tab, webview.WebView):
raise ValueError("Tried to create filter for {} which is no " raise ValueError("Tried to create filter for {} which is no "
"WebView!".format(tab)) "WebView!".format(tab))
return partial(self._filter_signals, signal, tab) return functools.partial(self._filter_signals, signal, tab)
def _filter_signals(self, signal, tab, *args): def _filter_signals(self, signal, tab, *args):
"""Filter signals and trigger TabbedBrowser signals if needed. """Filter signals and trigger TabbedBrowser signals if needed.
@ -80,7 +80,7 @@ class SignalFilter(QObject):
Emit: Emit:
The target signal if the sender was the current widget. The target signal if the sender was the current widget.
""" """
log_signal = signal_name(signal) not in self.BLACKLIST log_signal = debug.signal_name(signal) not in self.BLACKLIST
try: try:
tabidx = self._tabs.indexOf(tab) tabidx = self._tabs.indexOf(tab)
except RuntimeError: except RuntimeError:
@ -89,9 +89,9 @@ class SignalFilter(QObject):
if tabidx == self._tabs.currentIndex(): if tabidx == self._tabs.currentIndex():
if log_signal: if log_signal:
logger.debug("emitting: {} (tab {})".format( logger.debug("emitting: {} (tab {})".format(
dbg_signal(signal, args), tabidx)) debug.dbg_signal(signal, args), tabidx))
signal.emit(*args) signal.emit(*args)
else: else:
if log_signal: if log_signal:
logger.debug("ignoring: {} (tab {})".format( logger.debug("ignoring: {} (tab {})".format(
dbg_signal(signal, args), tabidx)) debug.dbg_signal(signal, args), tabidx))

View File

@ -28,14 +28,11 @@ from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtPrintSupport import QPrintDialog from PyQt5.QtPrintSupport import QPrintDialog
from PyQt5.QtWebKitWidgets import QWebPage from PyQt5.QtWebKitWidgets import QWebPage
import qutebrowser.utils.message as message from qutebrowser.config import config
import qutebrowser.config.config as config from qutebrowser.network import networkmanager
import qutebrowser.utils.log as log from qutebrowser.utils import message, usertypes, log, http
import qutebrowser.utils.http as http from qutebrowser.utils import misc as utils
from qutebrowser.network.networkmanager import NetworkManager from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.misc import read_file
from qutebrowser.utils.qt import check_print_compat
from qutebrowser.utils.usertypes import PromptMode, ClickTarget
class BrowserPage(QWebPage): class BrowserPage(QWebPage):
@ -61,7 +58,7 @@ class BrowserPage(QWebPage):
QWebPage.ErrorPageExtension: self._handle_errorpage, QWebPage.ErrorPageExtension: self._handle_errorpage,
QWebPage.ChooseMultipleFilesExtension: self._handle_multiple_files, QWebPage.ChooseMultipleFilesExtension: self._handle_multiple_files,
} }
self._networkmanager = NetworkManager(self) self._networkmanager = networkmanager.NetworkManager(self)
self.setNetworkAccessManager(self._networkmanager) self.setNetworkAccessManager(self._networkmanager)
self.setForwardUnsupportedContent(True) self.setForwardUnsupportedContent(True)
self.printRequested.connect(self.on_print_requested) self.printRequested.connect(self.on_print_requested)
@ -83,7 +80,8 @@ class BrowserPage(QWebPage):
http://www.riverbankcomputing.com/pipermail/pyqt/2014-June/034385.html http://www.riverbankcomputing.com/pipermail/pyqt/2014-June/034385.html
""" """
answer = message.ask("js: {}".format(msg), PromptMode.text, default) answer = message.ask("js: {}".format(msg), usertypes.PromptMode.text,
default)
if answer is None: if answer is None:
return (False, "") return (False, "")
else: else:
@ -122,7 +120,7 @@ class BrowserPage(QWebPage):
log.webview.debug("Error domain: {}, error code: {}".format( log.webview.debug("Error domain: {}, error code: {}".format(
info.domain, info.error)) info.domain, info.error))
title = "Error loading page: {}".format(urlstr) title = "Error loading page: {}".format(urlstr)
errpage.content = read_file('html/error.html').format( errpage.content = utils.read_file('html/error.html').format(
title=title, url=urlstr, error=info.errorString, icon='') title=title, url=urlstr, error=info.errorString, icon='')
return True return True
@ -158,7 +156,7 @@ class BrowserPage(QWebPage):
def on_print_requested(self, frame): def on_print_requested(self, frame):
"""Handle printing when requested via javascript.""" """Handle printing when requested via javascript."""
if not check_print_compat(): if not qtutils.check_print_compat():
message.error("Printing on Qt < 5.3.0 on Windows is broken, " message.error("Printing on Qt < 5.3.0 on Windows is broken, "
"please upgrade!", immediately=True) "please upgrade!", immediately=True)
return return
@ -246,11 +244,12 @@ class BrowserPage(QWebPage):
def javaScriptAlert(self, _frame, msg): def javaScriptAlert(self, _frame, msg):
"""Override javaScriptAlert to use the statusbar.""" """Override javaScriptAlert to use the statusbar."""
message.ask("[js alert] {}".format(msg), PromptMode.alert) message.ask("[js alert] {}".format(msg), usertypes.PromptMode.alert)
def javaScriptConfirm(self, _frame, msg): def javaScriptConfirm(self, _frame, msg):
"""Override javaScriptConfirm to use the statusbar.""" """Override javaScriptConfirm to use the statusbar."""
ans = message.ask("[js confirm] {}".format(msg), PromptMode.yesno) ans = message.ask("[js confirm] {}".format(msg),
usertypes.PromptMode.yesno)
return bool(ans) return bool(ans)
def javaScriptConsoleMessage(self, msg, line, source): def javaScriptConsoleMessage(self, msg, line, source):
@ -270,7 +269,7 @@ class BrowserPage(QWebPage):
def shouldInterruptJavaScript(self): def shouldInterruptJavaScript(self):
"""Override shouldInterruptJavaScript to use the statusbar.""" """Override shouldInterruptJavaScript to use the statusbar."""
answer = message.ask("Interrupt long-running javascript?", answer = message.ask("Interrupt long-running javascript?",
PromptMode.yesno) usertypes.PromptMode.yesno)
if answer is None: if answer is None:
answer = True answer = True
return answer return answer
@ -298,10 +297,10 @@ class BrowserPage(QWebPage):
message.error("Invalid link {} clicked!".format(urlstr)) message.error("Invalid link {} clicked!".format(urlstr))
log.webview.debug(url.errorString()) log.webview.debug(url.errorString())
return False return False
if self._view.open_target == ClickTarget.tab: if self._view.open_target == usertypes.ClickTarget.tab:
self._view.tabbedbrowser.tabopen(url, False) self._view.tabbedbrowser.tabopen(url, False)
return False return False
elif self._view.open_target == ClickTarget.tab_bg: elif self._view.open_target == usertypes.ClickTarget.tab_bg:
self._view.tabbedbrowser.tabopen(url, True) self._view.tabbedbrowser.tabopen(url, True)
return False return False
else: else:

View File

@ -22,9 +22,8 @@
from PyQt5.QtCore import QCoreApplication, QUrl from PyQt5.QtCore import QCoreApplication, QUrl
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings
from qutebrowser.commands.exceptions import (ArgumentCountError, from qutebrowser.commands import exceptions as cmdexc
PrerequisitesError) from qutebrowser.utils import misc as utils
from qutebrowser.utils.misc import dotted_getattr
from qutebrowser.utils.log import commands as logger from qutebrowser.utils.log import commands as logger
@ -84,16 +83,18 @@ class Command:
curmode = QCoreApplication.instance().modeman.mode curmode = QCoreApplication.instance().modeman.mode
if self.modes is not None and curmode not in self.modes: if self.modes is not None and curmode not in self.modes:
mode_names = '/'.join(mode.name for mode in self.modes) mode_names = '/'.join(mode.name for mode in self.modes)
raise PrerequisitesError("{}: This command is only allowed in {} " raise cmdexc.PrerequisitesError(
"mode.".format(self.name, mode_names)) "{}: This command is only allowed in {} mode.".format(
self.name, mode_names))
elif self.not_modes is not None and curmode in self.not_modes: elif self.not_modes is not None and curmode in self.not_modes:
mode_names = '/'.join(mode.name for mode in self.not_modes) mode_names = '/'.join(mode.name for mode in self.not_modes)
raise PrerequisitesError("{}: This command is not allowed in {} " raise cmdexc.PrerequisitesError(
"mode.".format(self.name, mode_names)) "{}: This command is not allowed in {} mode.".format(
self.name, mode_names))
if self.needs_js and not QWebSettings.globalSettings().testAttribute( if self.needs_js and not QWebSettings.globalSettings().testAttribute(
QWebSettings.JavascriptEnabled): QWebSettings.JavascriptEnabled):
raise PrerequisitesError("{}: This command needs javascript " raise cmdexc.PrerequisitesError(
"enabled.".format(self.name)) "{}: This command needs javascript enabled.".format(self.name))
if self.nargs[1] is None and self.nargs[0] <= len(args): if self.nargs[1] is None and self.nargs[0] <= len(args):
pass pass
elif self.nargs[0] <= len(args) <= self.nargs[1]: elif self.nargs[0] <= len(args) <= self.nargs[1]:
@ -105,8 +106,9 @@ class Command:
argcnt = '{}-inf'.format(self.nargs[0]) argcnt = '{}-inf'.format(self.nargs[0])
else: else:
argcnt = '{}-{}'.format(self.nargs[0], self.nargs[1]) argcnt = '{}-{}'.format(self.nargs[0], self.nargs[1])
raise ArgumentCountError("{}: {} args expected, but got {}".format( raise cmdexc.ArgumentCountError(
self.name, argcnt, len(args))) "{}: {} args expected, but got {}".format(self.name, argcnt,
len(args)))
def run(self, args=None, count=None): def run(self, args=None, count=None):
"""Run the command. """Run the command.
@ -142,7 +144,7 @@ class Command:
if self.instance == '': if self.instance == '':
obj = app obj = app
else: else:
obj = dotted_getattr(app, self.instance) obj = utils.dotted_getattr(app, self.instance)
new_args.insert(0, obj) new_args.insert(0, obj)
if count is not None and self.count: if count is not None and self.count:

View File

@ -22,12 +22,11 @@
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
from PyQt5.QtWebKitWidgets import QWebPage from PyQt5.QtWebKitWidgets import QWebPage
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import utils as cmdutils
import qutebrowser.utils.message as message from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.commands.exceptions import (NoSuchCommandError, from qutebrowser.utils import message
CommandMetaError, CommandError) from qutebrowser.utils import misc as utils
from qutebrowser.utils.misc import safe_shlex_split
from qutebrowser.utils.log import commands as logger from qutebrowser.utils.log import commands as logger
@ -201,7 +200,7 @@ class CommandRunner:
""" """
parts = text.strip().split(maxsplit=1) parts = text.strip().split(maxsplit=1)
if not parts: if not parts:
raise NoSuchCommandError("No command given") raise cmdexc.NoSuchCommandError("No command given")
cmdstr = parts[0] cmdstr = parts[0]
if aliases: if aliases:
new_cmd = self._get_alias(text, alias_no_args) new_cmd = self._get_alias(text, alias_no_args)
@ -217,11 +216,12 @@ class CommandRunner:
parts.append('') parts.append('')
return parts return parts
else: else:
raise NoSuchCommandError('{}: no such command'.format(cmdstr)) raise cmdexc.NoSuchCommandError(
'{}: no such command'.format(cmdstr))
if len(parts) == 1: if len(parts) == 1:
args = [] args = []
elif cmd.split: elif cmd.split:
args = safe_shlex_split(parts[1]) args = utils.safe_shlex_split(parts[1])
else: else:
args = parts[1].split(maxsplit=cmd.nargs[0] - 1) args = parts[1].split(maxsplit=cmd.nargs[0] - 1)
self._cmd = cmd self._cmd = cmd
@ -266,7 +266,7 @@ class CommandRunner:
"""Run a command and display exceptions in the statusbar.""" """Run a command and display exceptions in the statusbar."""
try: try:
self.run(text, count) self.run(text, count)
except (CommandMetaError, CommandError) as e: except (cmdexc.CommandMetaError, cmdexc.CommandError) as e:
message.error(e, immediately=True) message.error(e, immediately=True)
@pyqtSlot(str, int) @pyqtSlot(str, int)
@ -277,5 +277,5 @@ class CommandRunner:
suitable to use while initializing.""" suitable to use while initializing."""
try: try:
self.run(text, count) self.run(text, count)
except (CommandMetaError, CommandError) as e: except (cmdexc.CommandMetaError, cmdexc.CommandError) as e:
message.error(e) message.error(e)

View File

@ -26,17 +26,17 @@ Module attributes:
import os import os
import os.path import os.path
import tempfile import tempfile
from select import select import select
from functools import partial import functools
from PyQt5.QtCore import (pyqtSignal, QObject, QThread, QStandardPaths, from PyQt5.QtCore import (pyqtSignal, QObject, QThread, QStandardPaths,
QProcessEnvironment, QProcess, QUrl) QProcessEnvironment, QProcess, QUrl)
import qutebrowser.utils.message as message from qutebrowser.utils import message
from qutebrowser.utils.misc import get_standard_dir from qutebrowser.utils import misc as utils
from qutebrowser.utils.log import procs as logger from qutebrowser.utils.log import procs as logger
from qutebrowser.commands.exceptions import CommandError from qutebrowser.commands import runners
from qutebrowser.commands.runners import CommandRunner from qutebrowser.commands import exceptions as cmdexc
_runners = [] _runners = []
@ -83,7 +83,7 @@ class _BlockingFIFOReader(QObject):
self.fifo = os.fdopen(fd, 'r') self.fifo = os.fdopen(fd, 'r')
while True: while True:
logger.debug("thread loop") logger.debug("thread loop")
ready_r, _ready_w, _ready_e = select([self.fifo], [], [], 1) ready_r, _ready_w, _ready_e = select.select([self.fifo], [], [], 1)
if ready_r: if ready_r:
logger.debug("reading data") logger.debug("reading data")
for line in self.fifo: for line in self.fifo:
@ -205,7 +205,7 @@ class _POSIXUserscriptRunner(_BaseUserscriptRunner):
self.thread = None self.thread = None
def run(self, cmd, *args, env=None): def run(self, cmd, *args, env=None):
rundir = get_standard_dir(QStandardPaths.RuntimeLocation) rundir = utils.get_standard_dir(QStandardPaths.RuntimeLocation)
# tempfile.mktemp is deprecated and discouraged, but we use it here to # tempfile.mktemp is deprecated and discouraged, but we use it here to
# create a FIFO since the only other alternative would be to create a # create a FIFO since the only other alternative would be to create a
# directory and place the FIFO there, which sucks. Since os.kfifo will # directory and place the FIFO there, which sucks. Since os.kfifo will
@ -313,7 +313,8 @@ class _DummyUserscriptRunner:
def run(self, _cmd, *_args, _env=None): def run(self, _cmd, *_args, _env=None):
"""Print an error as userscripts are not supported.""" """Print an error as userscripts are not supported."""
self.finished.emit() self.finished.emit()
raise CommandError("Userscripts are not supported on this platform!") raise cmdexc.CommandError(
"Userscripts are not supported on this platform!")
# Here we basically just assign a generic UserscriptRunner class which does the # Here we basically just assign a generic UserscriptRunner class which does the
@ -329,7 +330,7 @@ else:
def init(): def init():
"""Initialize the global _commandrunner.""" """Initialize the global _commandrunner."""
global _commandrunner global _commandrunner
_commandrunner = CommandRunner() _commandrunner = runners.CommandRunner()
def run(cmd, *args, url): def run(cmd, *args, url):
@ -341,4 +342,4 @@ def run(cmd, *args, url):
runner.got_cmd.connect(_commandrunner.run_safely) runner.got_cmd.connect(_commandrunner.run_safely)
runner.run(cmd, *args, env={'QUTE_URL': urlstr}) runner.run(cmd, *args, env={'QUTE_URL': urlstr})
_runners.append(runner) _runners.append(runner)
runner.finished.connect(partial(_runners.remove, runner)) runner.finished.connect(functools.partial(_runners.remove, runner))

View File

@ -24,12 +24,12 @@ Module attributes:
""" """
import inspect import inspect
from collections import Iterable import collections
import qutebrowser.utils.qt as qtutils from qutebrowser.utils import usertypes
from qutebrowser.commands.command import Command from qutebrowser.utils import qt as qtutils
from qutebrowser.commands.exceptions import CommandError from qutebrowser.commands import command
from qutebrowser.utils.usertypes import KeyMode from qutebrowser.commands import exceptions as cmdexc
cmd_dict = {} cmd_dict = {}
@ -49,8 +49,9 @@ def check_overflow(arg, ctype):
try: try:
qtutils.check_overflow(arg, ctype) qtutils.check_overflow(arg, ctype)
except OverflowError: except OverflowError:
raise CommandError("Numeric argument is too large for internal {} " raise cmdexc.CommandError(
"representation.".format(ctype)) "Numeric argument is too large for internal {} "
"representation.".format(ctype))
def arg_or_count(arg, count, default=None, countzero=None): def arg_or_count(arg, count, default=None, countzero=None):
@ -135,11 +136,11 @@ class register: # pylint: disable=invalid-name
self.debug = debug self.debug = debug
if modes is not None: if modes is not None:
for m in modes: for m in modes:
if not isinstance(m, KeyMode): if not isinstance(m, usertypes.KeyMode):
raise TypeError("Mode {} is no KeyMode member!".format(m)) raise TypeError("Mode {} is no KeyMode member!".format(m))
if not_modes is not None: if not_modes is not None:
for m in not_modes: for m in not_modes:
if not isinstance(m, KeyMode): if not isinstance(m, usertypes.KeyMode):
raise TypeError("Mode {} is no KeyMode member!".format(m)) raise TypeError("Mode {} is no KeyMode member!".format(m))
def __call__(self, func): def __call__(self, func):
@ -178,12 +179,11 @@ class register: # pylint: disable=invalid-name
desc = func.__doc__.splitlines()[0].strip() desc = func.__doc__.splitlines()[0].strip()
else: else:
desc = "" desc = ""
cmd = Command(name=mainname, split=self.split, cmd = command.Command(
hide=self.hide, nargs=nargs, count=count, desc=desc, name=mainname, split=self.split, hide=self.hide, nargs=nargs,
instance=self.instance, handler=func, count=count, desc=desc, instance=self.instance, handler=func,
completion=self.completion, modes=self.modes, completion=self.completion, modes=self.modes,
not_modes=self.not_modes, needs_js=self.needs_js, not_modes=self.not_modes, needs_js=self.needs_js, debug=self.debug)
debug=self.debug)
for name in names: for name in names:
cmd_dict[name] = cmd cmd_dict[name] = cmd
return func return func
@ -209,7 +209,7 @@ class register: # pylint: disable=invalid-name
# we assume count always has a default (and it should!) # we assume count always has a default (and it should!)
if self.nargs is not None: if self.nargs is not None:
# If nargs is overriden, use that. # If nargs is overriden, use that.
if isinstance(self.nargs, Iterable): if isinstance(self.nargs, collections.Iterable):
# Iterable (min, max) # Iterable (min, max)
# pylint: disable=unpacking-non-sequence # pylint: disable=unpacking-non-sequence
minargs, maxargs = self.nargs minargs, maxargs = self.nargs

View File

@ -28,18 +28,15 @@ import os
import os.path import os.path
import textwrap import textwrap
import configparser import configparser
from configparser import ExtendedInterpolation import collections.abc
from collections.abc import MutableMapping
from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication
import qutebrowser.config.configdata as configdata from qutebrowser.utils import log
import qutebrowser.commands.utils as cmdutils from qutebrowser.config import configdata, iniparsers, conftypes
import qutebrowser.utils.message as message from qutebrowser.commands import utils as cmdutils
import qutebrowser.utils.log as log from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.config.iniparsers import ReadConfigParser from qutebrowser.utils import message
from qutebrowser.config.conftypes import ValidationError
from qutebrowser.commands.exceptions import CommandError
from qutebrowser.utils.usertypes import Completion from qutebrowser.utils.usertypes import Completion
@ -114,7 +111,7 @@ class ConfigManager(QObject):
def __init__(self, configdir, fname, parent=None): def __init__(self, configdir, fname, parent=None):
super().__init__(parent) super().__init__(parent)
self.sections = configdata.DATA self.sections = configdata.DATA
self._configparser = ReadConfigParser(configdir, fname) self._configparser = iniparsers.ReadConfigParser(configdir, fname)
self._configfile = os.path.join(configdir, fname) self._configfile = os.path.join(configdir, fname)
self._wrapper_args = { self._wrapper_args = {
'width': 72, 'width': 72,
@ -124,7 +121,7 @@ class ConfigManager(QObject):
} }
self._configdir = configdir self._configdir = configdir
self._fname = fname self._fname = fname
self._interpolation = ExtendedInterpolation() self._interpolation = configparser.ExtendedInterpolation()
self._proxies = {} self._proxies = {}
for sectname in self.sections.keys(): for sectname in self.sections.keys():
self._proxies[sectname] = SectionProxy(self, sectname) self._proxies[sectname] = SectionProxy(self, sectname)
@ -227,7 +224,7 @@ class ConfigManager(QObject):
k = k.replace('<eq>', '=') k = k.replace('<eq>', '=')
try: try:
self.set('conf', sectname, k, v) self.set('conf', sectname, k, v)
except ValidationError as e: except conftypes.ValidationError as e:
e.section = sectname e.section = sectname
e.option = k e.option = k
raise raise
@ -299,7 +296,8 @@ class ConfigManager(QObject):
try: try:
val = self.get(sectname, optname, transformed=False) val = self.get(sectname, optname, transformed=False)
except (NoOptionError, NoSectionError) as e: except (NoOptionError, NoSectionError) as e:
raise CommandError("get: {} - {}".format(e.__class__.__name__, e)) raise cmdexc.CommandError("get: {} - {}".format(
e.__class__.__name__, e))
else: else:
message.info("{} {} = {}".format(sectname, optname, val), message.info("{} {} = {}".format(sectname, optname, val),
immediately=True) immediately=True)
@ -350,9 +348,10 @@ class ConfigManager(QObject):
""" """
try: try:
self.set('conf', sectname, optname, value) self.set('conf', sectname, optname, value)
except (NoOptionError, NoSectionError, ValidationError, except (NoOptionError, NoSectionError, conftypes.ValidationError,
ValueError) as e: ValueError) as e:
raise CommandError("set: {} - {}".format(e.__class__.__name__, e)) raise cmdexc.CommandError("set: {} - {}".format(
e.__class__.__name__, e))
@cmdutils.register(name='set-temp', instance='config', @cmdutils.register(name='set-temp', instance='config',
completion=[Completion.section, Completion.option, completion=[Completion.section, Completion.option,
@ -371,8 +370,9 @@ class ConfigManager(QObject):
""" """
try: try:
self.set('temp', sectname, optname, value) self.set('temp', sectname, optname, value)
except (NoOptionError, NoSectionError, ValidationError) as e: except (NoOptionError, NoSectionError, conftypes.ValidationError) as e:
raise CommandError("set: {} - {}".format(e.__class__.__name__, e)) raise cmdexc.CommandError("set: {} - {}".format(
e.__class__.__name__, e))
def set(self, layer, sectname, optname, value): def set(self, layer, sectname, optname, value):
"""Set an option. """Set an option.
@ -442,7 +442,7 @@ class ConfigManager(QObject):
return val return val
class SectionProxy(MutableMapping): class SectionProxy(collections.abc.MutableMapping):
"""A proxy for a single section from a config. """A proxy for a single section from a config.

View File

@ -27,11 +27,11 @@ DATA: The config defaults, an OrderedDict of sections.
""" """
import re import re
from collections import OrderedDict import collections
from qutebrowser.config import conftypes as typ
from qutebrowser.config import sections as sect
from qutebrowser.config.value import SettingValue from qutebrowser.config.value import SettingValue
import qutebrowser.config.conftypes as types
import qutebrowser.config.sections as sect
from qutebrowser.utils.qt import MAXVALS from qutebrowser.utils.qt import MAXVALS
@ -165,57 +165,57 @@ SECTION_DESC = {
} }
DATA = OrderedDict([ DATA = collections.OrderedDict([
('general', sect.KeyValue( ('general', sect.KeyValue(
('ignore-case', ('ignore-case',
SettingValue(types.IgnoreCase(), 'smart'), SettingValue(typ.IgnoreCase(), 'smart'),
"Whether to find text on a page case-insensitively."), "Whether to find text on a page case-insensitively."),
('wrap-search', ('wrap-search',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to wrap finding text to the top when arriving at the end."), "Whether to wrap finding text to the top when arriving at the end."),
('startpage', ('startpage',
SettingValue(types.List(), 'http://www.duckduckgo.com'), SettingValue(typ.List(), 'http://www.duckduckgo.com'),
"The default page(s) to open at the start, separated by commas."), "The default page(s) to open at the start, separated by commas."),
('auto-search', ('auto-search',
SettingValue(types.AutoSearch(), 'naive'), SettingValue(typ.AutoSearch(), 'naive'),
"Whether to start a search when something else than a URL is " "Whether to start a search when something else than a URL is "
"entered."), "entered."),
('auto-save-config', ('auto-save-config',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to save the config automatically on quit."), "Whether to save the config automatically on quit."),
('editor', ('editor',
SettingValue(types.ShellCommand(placeholder=True), 'gvim -f "{}"'), SettingValue(typ.ShellCommand(placeholder=True), 'gvim -f "{}"'),
"The editor (and arguments) to use for the `open-editor` command.\n\n" "The editor (and arguments) to use for the `open-editor` command.\n\n"
"Use `{}` for the filename. The value gets split like in a shell, so " "Use `{}` for the filename. The value gets split like in a shell, so "
"you can use `\"` or `'` to quote arguments."), "you can use `\"` or `'` to quote arguments."),
('editor-encoding', ('editor-encoding',
SettingValue(types.Encoding(), 'utf-8'), SettingValue(typ.Encoding(), 'utf-8'),
"Encoding to use for editor."), "Encoding to use for editor."),
('private-browsing', ('private-browsing',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Do not record visited pages in the history or store web page " "Do not record visited pages in the history or store web page "
"icons."), "icons."),
('developer-extras', ('developer-extras',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Enable extra tools for Web developers.\n\n" "Enable extra tools for Web developers.\n\n"
"This needs to be enabled for `:inspector` to work and also adds an " "This needs to be enabled for `:inspector` to work and also adds an "
"_Inspect_ entry to the context menu."), "_Inspect_ entry to the context menu."),
('print-element-backgrounds', ('print-element-backgrounds',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether the background color and images are also drawn when the " "Whether the background color and images are also drawn when the "
"page is printed."), "page is printed."),
('xss-auditing', ('xss-auditing',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether load requests should be monitored for cross-site scripting " "Whether load requests should be monitored for cross-site scripting "
"attempts.\n\n" "attempts.\n\n"
"Suspicious scripts will be blocked and reported in the inspector's " "Suspicious scripts will be blocked and reported in the inspector's "
@ -223,11 +223,11 @@ DATA = OrderedDict([
"performance."), "performance."),
('site-specific-quirks', ('site-specific-quirks',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Enable workarounds for broken sites."), "Enable workarounds for broken sites."),
('default-encoding', ('default-encoding',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Default encoding to use for websites.\n\n" "Default encoding to use for websites.\n\n"
"The encoding must be a string describing an encoding such as " "The encoding must be a string describing an encoding such as "
'_utf-8_, _iso-8859-1_, etc. If left empty a default value will be ' '_utf-8_, _iso-8859-1_, etc. If left empty a default value will be '
@ -236,126 +236,125 @@ DATA = OrderedDict([
('ui', sect.KeyValue( ('ui', sect.KeyValue(
('zoom-levels', ('zoom-levels',
SettingValue(types.PercList(minval=0), SettingValue(typ.PercList(minval=0),
'25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,' '25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,'
'250%,300%,400%,500%'), '250%,300%,400%,500%'),
"The available zoom levels, separated by commas."), "The available zoom levels, separated by commas."),
('default-zoom', ('default-zoom',
SettingValue(types.ZoomPerc(), '100%'), SettingValue(typ.ZoomPerc(), '100%'),
"The default zoom level."), "The default zoom level."),
('message-timeout', ('message-timeout',
SettingValue(types.Int(), '2000'), SettingValue(typ.Int(), '2000'),
"Time (in ms) to show messages in the statusbar for."), "Time (in ms) to show messages in the statusbar for."),
('confirm-quit', ('confirm-quit',
SettingValue(types.ConfirmQuit(), 'never'), SettingValue(typ.ConfirmQuit(), 'never'),
"Whether to confirm quitting the application."), "Whether to confirm quitting the application."),
('display-statusbar-messages', ('display-statusbar-messages',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to display javascript statusbar messages."), "Whether to display javascript statusbar messages."),
('zoom-text-only', ('zoom-text-only',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether the zoom factor on a frame applies only to the text or to " "Whether the zoom factor on a frame applies only to the text or to "
"all content."), "all content."),
('frame-flattening', ('frame-flattening',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to expand each subframe to its contents.\n\n" "Whether to expand each subframe to its contents.\n\n"
"This will flatten all the frames to become one scrollable page."), "This will flatten all the frames to become one scrollable page."),
('user-stylesheet', ('user-stylesheet',
SettingValue(types.WebSettingsFile(), ''), SettingValue(typ.WebSettingsFile(), ''),
"User stylesheet to use."), "User stylesheet to use."),
('css-media-type', ('css-media-type',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Set the CSS media type."), "Set the CSS media type."),
)), )),
('network', sect.KeyValue( ('network', sect.KeyValue(
('do-not-track', ('do-not-track',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Value to send in the `DNT` header."), "Value to send in the `DNT` header."),
('accept-language', ('accept-language',
SettingValue(types.String(none_ok=True), 'en-US,en'), SettingValue(typ.String(none_ok=True), 'en-US,en'),
"Value to send in the `accept-language` header."), "Value to send in the `accept-language` header."),
('user-agent', ('user-agent',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"User agent to send. Empty to send the default."), "User agent to send. Empty to send the default."),
('proxy', ('proxy',
SettingValue(types.Proxy(), 'system'), SettingValue(typ.Proxy(), 'system'),
"The proxy to use.\n\n" "The proxy to use.\n\n"
"In addition to the listed values, you can use a `socks://...` or " "In addition to the listed values, you can use a `socks://...` or "
"`http://...` URL."), "`http://...` URL."),
('ssl-strict', ('ssl-strict',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to validate SSL handshakes."), "Whether to validate SSL handshakes."),
('dns-prefetch', ('dns-prefetch',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to try to pre-fetch DNS entries to speed up browsing."), "Whether to try to pre-fetch DNS entries to speed up browsing."),
)), )),
('completion', sect.KeyValue( ('completion', sect.KeyValue(
('show', ('show',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to show the autocompletion window."), "Whether to show the autocompletion window."),
('height', ('height',
SettingValue(types.PercOrInt(minperc=0, maxperc=100, minint=1), SettingValue(typ.PercOrInt(minperc=0, maxperc=100, minint=1), '50%'),
'50%'),
"The height of the completion, in px or as percentage of the " "The height of the completion, in px or as percentage of the "
"window."), "window."),
('history-length', ('history-length',
SettingValue(types.Int(minval=-1), '100'), SettingValue(typ.Int(minval=-1), '100'),
"How many commands to save in the history.\n\n" "How many commands to save in the history.\n\n"
"0: no history / -1: unlimited"), "0: no history / -1: unlimited"),
('quick-complete', ('quick-complete',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to move on to the next part when there's only one possible " "Whether to move on to the next part when there's only one possible "
"completion left."), "completion left."),
('shrink', ('shrink',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to shrink the completion to be smaller than the configured " "Whether to shrink the completion to be smaller than the configured "
"size if there are no scrollbars."), "size if there are no scrollbars."),
)), )),
('input', sect.KeyValue( ('input', sect.KeyValue(
('timeout', ('timeout',
SettingValue(types.Int(minval=0, maxval=MAXVALS['int']), '500'), SettingValue(typ.Int(minval=0, maxval=MAXVALS['int']), '500'),
"Timeout for ambiguous keybindings."), "Timeout for ambiguous keybindings."),
('insert-mode-on-plugins', ('insert-mode-on-plugins',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to switch to insert mode when clicking flash and other " "Whether to switch to insert mode when clicking flash and other "
"plugins."), "plugins."),
('auto-leave-insert-mode', ('auto-leave-insert-mode',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to leave insert mode if a non-editable element is clicked."), "Whether to leave insert mode if a non-editable element is clicked."),
('auto-insert-mode', ('auto-insert-mode',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to automatically enter insert mode if an editable element " "Whether to automatically enter insert mode if an editable element "
"is focused after page load."), "is focused after page load."),
('forward-unbound-keys', ('forward-unbound-keys',
SettingValue(types.ForwardUnboundKeys(), 'auto'), SettingValue(typ.ForwardUnboundKeys(), 'auto'),
"Whether to forward unbound keys to the webview in normal mode."), "Whether to forward unbound keys to the webview in normal mode."),
('spatial-navigation', ('spatial-navigation',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Enables or disables the Spatial Navigation feature\n\n" "Enables or disables the Spatial Navigation feature\n\n"
"Spatial navigation consists in the ability to navigate between " "Spatial navigation consists in the ability to navigate between "
"focusable elements in a Web page, such as hyperlinks and form " "focusable elements in a Web page, such as hyperlinks and form "
@ -365,76 +364,74 @@ DATA = OrderedDict([
"right and which element he probably wants."), "right and which element he probably wants."),
('links-included-in-focus-chain', ('links-included-in-focus-chain',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether hyperlinks should be included in the keyboard focus " "Whether hyperlinks should be included in the keyboard focus chain."),
"chain."),
)), )),
('tabs', sect.KeyValue( ('tabs', sect.KeyValue(
('background-tabs', ('background-tabs',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether to open new tabs (middleclick/ctrl+click) in background."), "Whether to open new tabs (middleclick/ctrl+click) in background."),
('select-on-remove', ('select-on-remove',
SettingValue(types.SelectOnRemove(), 'right'), SettingValue(typ.SelectOnRemove(), 'right'),
"Which tab to select when the focused tab is removed."), "Which tab to select when the focused tab is removed."),
('new-tab-position', ('new-tab-position',
SettingValue(types.NewTabPosition(), 'right'), SettingValue(typ.NewTabPosition(), 'right'),
"How new tabs are positioned."), "How new tabs are positioned."),
('new-tab-position-explicit', ('new-tab-position-explicit',
SettingValue(types.NewTabPosition(), 'last'), SettingValue(typ.NewTabPosition(), 'last'),
"How new tabs opened explicitely are positioned."), "How new tabs opened explicitely are positioned."),
('last-close', ('last-close',
SettingValue(types.LastClose(), 'ignore'), SettingValue(typ.LastClose(), 'ignore'),
"Behaviour when the last tab is closed."), "Behaviour when the last tab is closed."),
('wrap', ('wrap',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to wrap when changing tabs."), "Whether to wrap when changing tabs."),
('movable', ('movable',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether tabs should be movable."), "Whether tabs should be movable."),
('close-mouse-button', ('close-mouse-button',
SettingValue(types.CloseButton(), 'middle'), SettingValue(typ.CloseButton(), 'middle'),
"On which mouse button to close tabs."), "On which mouse button to close tabs."),
('position', ('position',
SettingValue(types.Position(), 'north'), SettingValue(typ.Position(), 'north'),
"The position of the tab bar."), "The position of the tab bar."),
('show-favicons', ('show-favicons',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to show favicons in the tab bar."), "Whether to show favicons in the tab bar."),
('width', ('width',
SettingValue(types.PercOrInt(minperc=0, maxperc=100, minint=1), SettingValue(typ.PercOrInt(minperc=0, maxperc=100, minint=1), '20%'),
'20%'),
"The width of the tab bar if it's vertical, in px or as percentage " "The width of the tab bar if it's vertical, in px or as percentage "
"of the window."), "of the window."),
('indicator-width', ('indicator-width',
SettingValue(types.Int(minval=0), '3'), SettingValue(typ.Int(minval=0), '3'),
"Width of the progress indicator (0 to disable)."), "Width of the progress indicator (0 to disable)."),
('indicator-space', ('indicator-space',
SettingValue(types.Int(minval=0), '3'), SettingValue(typ.Int(minval=0), '3'),
"Spacing between tab edge and indicator."), "Spacing between tab edge and indicator."),
)), )),
('storage', sect.KeyValue( ('storage', sect.KeyValue(
('download-directory', ('download-directory',
SettingValue(types.Directory(none_ok=True), ''), SettingValue(typ.Directory(none_ok=True), ''),
"The directory to save downloads to. An empty value selects a " "The directory to save downloads to. An empty value selects a "
"sensible os-specific default."), "sensible os-specific default."),
('maximum-pages-in-cache', ('maximum-pages-in-cache',
SettingValue(types.Int(none_ok=True, minval=0, maxval=MAXVALS['int']), SettingValue(
''), typ.Int(none_ok=True, minval=0, maxval=MAXVALS['int']), ''),
"The maximum number of pages to hold in the memory page cache.\n\n" "The maximum number of pages to hold in the memory page cache.\n\n"
"The Page Cache allows for a nicer user experience when navigating " "The Page Cache allows for a nicer user experience when navigating "
"forth or back to pages in the forward/back history, by pausing and " "forth or back to pages in the forward/back history, by pausing and "
@ -443,8 +440,8 @@ DATA = OrderedDict([
"http://webkit.org/blog/427/webkit-page-cache-i-the-basics/"), "http://webkit.org/blog/427/webkit-page-cache-i-the-basics/"),
('object-cache-capacities', ('object-cache-capacities',
SettingValue(types.WebKitBytesList(length=3, maxsize=MAXVALS['int']), SettingValue(
''), typ.WebKitBytesList(length=3, maxsize=MAXVALS['int']), ''),
"The capacities for the memory cache for dead objects such as " "The capacities for the memory cache for dead objects such as "
"stylesheets or scripts. Syntax: cacheMinDeadCapacity, cacheMaxDead, " "stylesheets or scripts. Syntax: cacheMinDeadCapacity, cacheMaxDead, "
"totalCapacity.\n\n" "totalCapacity.\n\n"
@ -457,19 +454,19 @@ DATA = OrderedDict([
"that the cache should consume *overall*."), "that the cache should consume *overall*."),
('offline-storage-default-quota', ('offline-storage-default-quota',
SettingValue(types.WebKitBytes(maxsize=MAXVALS['int64']), ''), SettingValue(typ.WebKitBytes(maxsize=MAXVALS['int64']), ''),
"Default quota for new offline storage databases."), "Default quota for new offline storage databases."),
('offline-web-application-cache-quota', ('offline-web-application-cache-quota',
SettingValue(types.WebKitBytes(maxsize=MAXVALS['int64']), ''), SettingValue(typ.WebKitBytes(maxsize=MAXVALS['int64']), ''),
"Quota for the offline web application cache."), "Quota for the offline web application cache."),
('offline-storage-database', ('offline-storage-database',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether support for the HTML 5 offline storage feature is enabled."), "Whether support for the HTML 5 offline storage feature is enabled."),
('offline-web-application-storage', ('offline-web-application-storage',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether support for the HTML 5 web application cache feature is " "Whether support for the HTML 5 web application cache feature is "
"enabled.\n\n" "enabled.\n\n"
"An application cache acts like an HTTP cache in some sense. For " "An application cache acts like an HTTP cache in some sense. For "
@ -480,96 +477,96 @@ DATA = OrderedDict([
"http://dev.w3.org/html5/spec/Overview.html#appcache"), "http://dev.w3.org/html5/spec/Overview.html#appcache"),
('local-storage', ('local-storage',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether support for the HTML 5 local storage feature is enabled."), "Whether support for the HTML 5 local storage feature is enabled."),
)), )),
('permissions', sect.KeyValue( ('permissions', sect.KeyValue(
('allow-images', ('allow-images',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether images are automatically loaded in web pages."), "Whether images are automatically loaded in web pages."),
('allow-javascript', ('allow-javascript',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Enables or disables the running of JavaScript programs."), "Enables or disables the running of JavaScript programs."),
('allow-plugins', ('allow-plugins',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Enables or disables plugins in Web pages.\n\n" "Enables or disables plugins in Web pages.\n\n"
'Qt plugins with a mimetype such as "application/x-qt-plugin" are ' 'Qt plugins with a mimetype such as "application/x-qt-plugin" are '
"not affected by this setting."), "not affected by this setting."),
#('allow-java', #('allow-java',
# SettingValue(types.Bool(), 'true'), # SettingValue(typ.Bool(), 'true'),
# "Enables or disables Java applets. Currently Java applets are " # "Enables or disables Java applets. Currently Java applets are "
# "not supported"), # "not supported"),
('javascript-can-open-windows', ('javascript-can-open-windows',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether JavaScript programs can open new windows."), "Whether JavaScript programs can open new windows."),
('javascript-can-close-windows', ('javascript-can-close-windows',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether JavaScript programs can close windows."), "Whether JavaScript programs can close windows."),
('javascript-can-access-clipboard', ('javascript-can-access-clipboard',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether JavaScript programs can read or write to the clipboard."), "Whether JavaScript programs can read or write to the clipboard."),
('local-content-can-access-remote-urls', ('local-content-can-access-remote-urls',
SettingValue(types.Bool(), 'false'), SettingValue(typ.Bool(), 'false'),
"Whether locally loaded documents are allowed to access remote " "Whether locally loaded documents are allowed to access remote "
"urls."), "urls."),
('local-content-can-access-file-urls', ('local-content-can-access-file-urls',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether locally loaded documents are allowed to access other local " "Whether locally loaded documents are allowed to access other local "
"urls."), "urls."),
('cookies-accept', ('cookies-accept',
SettingValue(types.AcceptCookies(), 'default'), SettingValue(typ.AcceptCookies(), 'default'),
"Whether to accept cookies."), "Whether to accept cookies."),
('cookies-store', ('cookies-store',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to store cookies."), "Whether to store cookies."),
)), )),
('hints', sect.KeyValue( ('hints', sect.KeyValue(
('border', ('border',
SettingValue(types.String(), '1px solid #E3BE23'), SettingValue(typ.String(), '1px solid #E3BE23'),
"CSS border value for hints."), "CSS border value for hints."),
('opacity', ('opacity',
SettingValue(types.Float(minval=0.0, maxval=1.0), '0.7'), SettingValue(typ.Float(minval=0.0, maxval=1.0), '0.7'),
"Opacity for hints."), "Opacity for hints."),
('mode', ('mode',
SettingValue(types.HintMode(), 'letter'), SettingValue(typ.HintMode(), 'letter'),
"Mode to use for hints."), "Mode to use for hints."),
('chars', ('chars',
SettingValue(types.String(minlen=2), 'asdfghjkl'), SettingValue(typ.String(minlen=2), 'asdfghjkl'),
"Chars used for hint strings."), "Chars used for hint strings."),
('auto-follow', ('auto-follow',
SettingValue(types.Bool(), 'true'), SettingValue(typ.Bool(), 'true'),
"Whether to auto-follow a hint if there's only one left."), "Whether to auto-follow a hint if there's only one left."),
('next-regexes', ('next-regexes',
SettingValue(types.RegexList(flags=re.IGNORECASE), SettingValue(typ.RegexList(flags=re.IGNORECASE),
r'\bnext\b,\bmore\b,\bnewer\b,\b[>→≫]\b,\b(>>|»)\b'), r'\bnext\b,\bmore\b,\bnewer\b,\b[>→≫]\b,\b(>>|»)\b'),
"A comma-separated list of regexes to use for 'next' links."), "A comma-separated list of regexes to use for 'next' links."),
('prev-regexes', ('prev-regexes',
SettingValue(types.RegexList(flags=re.IGNORECASE), SettingValue(typ.RegexList(flags=re.IGNORECASE),
r'\bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,' r'\bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,'
r'\b(<<|«)\b'), r'\b(<<|«)\b'),
"A comma-separated list of regexes to use for 'prev' links."), "A comma-separated list of regexes to use for 'prev' links."),
)), )),
('searchengines', sect.ValueList( ('searchengines', sect.ValueList(
types.SearchEngineName(), types.SearchEngineUrl(), typ.SearchEngineName(), typ.SearchEngineUrl(),
('DEFAULT', '${duckduckgo}'), ('DEFAULT', '${duckduckgo}'),
('duckduckgo', 'https://duckduckgo.com/?q={}'), ('duckduckgo', 'https://duckduckgo.com/?q={}'),
('ddg', '${duckduckgo}'), ('ddg', '${duckduckgo}'),
@ -581,7 +578,7 @@ DATA = OrderedDict([
)), )),
('keybind', sect.ValueList( ('keybind', sect.ValueList(
types.KeyBindingName(), types.KeyBinding(), typ.KeyBindingName(), typ.KeyBinding(),
('o', 'set-cmd-text ":open "'), ('o', 'set-cmd-text ":open "'),
('go', 'set-cmd-text :open {url}'), ('go', 'set-cmd-text :open {url}'),
('O', 'set-cmd-text ":open-tab "'), ('O', 'set-cmd-text ":open-tab "'),
@ -674,7 +671,7 @@ DATA = OrderedDict([
)), )),
('keybind.insert', sect.ValueList( ('keybind.insert', sect.ValueList(
types.KeyBindingName(), types.KeyBinding(), typ.KeyBindingName(), typ.KeyBinding(),
('<Escape>', 'leave-mode'), ('<Escape>', 'leave-mode'),
('<Ctrl-N>', 'leave-mode'), ('<Ctrl-N>', 'leave-mode'),
('<Ctrl-E>', 'open-editor'), ('<Ctrl-E>', 'open-editor'),
@ -682,7 +679,7 @@ DATA = OrderedDict([
)), )),
('keybind.hint', sect.ValueList( ('keybind.hint', sect.ValueList(
types.KeyBindingName(), types.KeyBinding(), typ.KeyBindingName(), typ.KeyBinding(),
('<Return>', 'follow-hint'), ('<Return>', 'follow-hint'),
('<Escape>', 'leave-mode'), ('<Escape>', 'leave-mode'),
('<Ctrl-N>', 'leave-mode'), ('<Ctrl-N>', 'leave-mode'),
@ -690,7 +687,7 @@ DATA = OrderedDict([
)), )),
('keybind.passthrough', sect.ValueList( ('keybind.passthrough', sect.ValueList(
types.KeyBindingName(), types.KeyBinding(), typ.KeyBindingName(), typ.KeyBinding(),
('<Escape>', 'leave-mode'), ('<Escape>', 'leave-mode'),
('<Ctrl-[>', '${<Escape>}'), ('<Ctrl-[>', '${<Escape>}'),
)), )),
@ -699,7 +696,7 @@ DATA = OrderedDict([
# text field. # text field.
('keybind.command', sect.ValueList( ('keybind.command', sect.ValueList(
types.KeyBindingName(), types.KeyBinding(), typ.KeyBindingName(), typ.KeyBinding(),
('<Escape>', 'leave-mode'), ('<Escape>', 'leave-mode'),
('<Ctrl-P>', 'command-history-prev'), ('<Ctrl-P>', 'command-history-prev'),
('<Ctrl-N>', 'command-history-next'), ('<Ctrl-N>', 'command-history-next'),
@ -726,7 +723,7 @@ DATA = OrderedDict([
)), )),
('keybind.prompt', sect.ValueList( ('keybind.prompt', sect.ValueList(
types.KeyBindingName(), types.KeyBinding(), typ.KeyBindingName(), typ.KeyBinding(),
('<Escape>', 'leave-mode'), ('<Escape>', 'leave-mode'),
('<Return>', 'prompt-accept'), ('<Return>', 'prompt-accept'),
('y', 'prompt-yes'), ('y', 'prompt-yes'),
@ -749,255 +746,255 @@ DATA = OrderedDict([
)), )),
('aliases', sect.ValueList( ('aliases', sect.ValueList(
types.String(forbidden=' '), types.Command(), typ.String(forbidden=' '), typ.Command(),
)), )),
('colors', sect.KeyValue( ('colors', sect.KeyValue(
('completion.fg', ('completion.fg',
SettingValue(types.QtColor(), 'white'), SettingValue(typ.QtColor(), 'white'),
"Text color of the completion widget."), "Text color of the completion widget."),
('completion.bg', ('completion.bg',
SettingValue(types.QssColor(), '#333333'), SettingValue(typ.QssColor(), '#333333'),
"Background color of the completion widget."), "Background color of the completion widget."),
('completion.item.bg', ('completion.item.bg',
SettingValue(types.QssColor(), '${completion.bg}'), SettingValue(typ.QssColor(), '${completion.bg}'),
"Background color of completion widget items."), "Background color of completion widget items."),
('completion.category.fg', ('completion.category.fg',
SettingValue(types.QtColor(), 'white'), SettingValue(typ.QtColor(), 'white'),
"Foreground color of completion widget category headers."), "Foreground color of completion widget category headers."),
('completion.category.bg', ('completion.category.bg',
SettingValue(types.QssColor(), 'qlineargradient(x1:0, y1:0, x2:0, ' SettingValue(typ.QssColor(), 'qlineargradient(x1:0, y1:0, x2:0, '
'y2:1, stop:0 #888888, stop:1 #505050)'), 'y2:1, stop:0 #888888, stop:1 #505050)'),
"Background color of the completion widget category headers."), "Background color of the completion widget category headers."),
('completion.category.border.top', ('completion.category.border.top',
SettingValue(types.QssColor(), 'black'), SettingValue(typ.QssColor(), 'black'),
"Top border color of the completion widget category headers."), "Top border color of the completion widget category headers."),
('completion.category.border.bottom', ('completion.category.border.bottom',
SettingValue(types.QssColor(), '${completion.category.border.top}'), SettingValue(typ.QssColor(), '${completion.category.border.top}'),
"Bottom border color of the completion widget category headers."), "Bottom border color of the completion widget category headers."),
('completion.item.selected.fg', ('completion.item.selected.fg',
SettingValue(types.QtColor(), 'black'), SettingValue(typ.QtColor(), 'black'),
"Foreground color of the selected completion item."), "Foreground color of the selected completion item."),
('completion.item.selected.bg', ('completion.item.selected.bg',
SettingValue(types.QssColor(), '#e8c000'), SettingValue(typ.QssColor(), '#e8c000'),
"Background color of the selected completion item."), "Background color of the selected completion item."),
('completion.item.selected.border.top', ('completion.item.selected.border.top',
SettingValue(types.QssColor(), '#bbbb00'), SettingValue(typ.QssColor(), '#bbbb00'),
"Top border color of the completion widget category headers."), "Top border color of the completion widget category headers."),
('completion.item.selected.border.bottom', ('completion.item.selected.border.bottom',
SettingValue(types.QssColor(), '${completion.item.selected.border.' SettingValue(typ.QssColor(), '${completion.item.selected.border.'
'top}'), 'top}'),
"Bottom border color of the selected completion item."), "Bottom border color of the selected completion item."),
('completion.match.fg', ('completion.match.fg',
SettingValue(types.QssColor(), '#ff4444'), SettingValue(typ.QssColor(), '#ff4444'),
"Foreground color of the matched text in the completion."), "Foreground color of the matched text in the completion."),
('statusbar.bg', ('statusbar.bg',
SettingValue(types.QssColor(), 'black'), SettingValue(typ.QssColor(), 'black'),
"Foreground color of the statusbar."), "Foreground color of the statusbar."),
('statusbar.fg', ('statusbar.fg',
SettingValue(types.QssColor(), 'white'), SettingValue(typ.QssColor(), 'white'),
"Foreground color of the statusbar."), "Foreground color of the statusbar."),
('statusbar.bg.error', ('statusbar.bg.error',
SettingValue(types.QssColor(), 'red'), SettingValue(typ.QssColor(), 'red'),
"Background color of the statusbar if there was an error."), "Background color of the statusbar if there was an error."),
('statusbar.bg.prompt', ('statusbar.bg.prompt',
SettingValue(types.QssColor(), 'darkblue'), SettingValue(typ.QssColor(), 'darkblue'),
"Background color of the statusbar if there is a prompt."), "Background color of the statusbar if there is a prompt."),
('statusbar.bg.insert', ('statusbar.bg.insert',
SettingValue(types.QssColor(), 'darkgreen'), SettingValue(typ.QssColor(), 'darkgreen'),
"Background color of the statusbar in insert mode."), "Background color of the statusbar in insert mode."),
('statusbar.progress.bg', ('statusbar.progress.bg',
SettingValue(types.QssColor(), 'white'), SettingValue(typ.QssColor(), 'white'),
"Background color of the progress bar."), "Background color of the progress bar."),
('statusbar.url.fg', ('statusbar.url.fg',
SettingValue(types.QssColor(), '${statusbar.fg}'), SettingValue(typ.QssColor(), '${statusbar.fg}'),
"Default foreground color of the URL in the statusbar."), "Default foreground color of the URL in the statusbar."),
('statusbar.url.fg.success', ('statusbar.url.fg.success',
SettingValue(types.QssColor(), 'lime'), SettingValue(typ.QssColor(), 'lime'),
"Foreground color of the URL in the statusbar on successful " "Foreground color of the URL in the statusbar on successful "
"load."), "load."),
('statusbar.url.fg.error', ('statusbar.url.fg.error',
SettingValue(types.QssColor(), 'orange'), SettingValue(typ.QssColor(), 'orange'),
"Foreground color of the URL in the statusbar on error."), "Foreground color of the URL in the statusbar on error."),
('statusbar.url.fg.warn', ('statusbar.url.fg.warn',
SettingValue(types.QssColor(), 'yellow'), SettingValue(typ.QssColor(), 'yellow'),
"Foreground color of the URL in the statusbar when there's a " "Foreground color of the URL in the statusbar when there's a "
"warning."), "warning."),
('statusbar.url.fg.hover', ('statusbar.url.fg.hover',
SettingValue(types.QssColor(), 'aqua'), SettingValue(typ.QssColor(), 'aqua'),
"Foreground color of the URL in the statusbar for hovered " "Foreground color of the URL in the statusbar for hovered links."),
"links."),
('tab.fg', ('tab.fg',
SettingValue(types.QtColor(), 'white'), SettingValue(typ.QtColor(), 'white'),
"Foreground color of tabs."), "Foreground color of tabs."),
('tab.bg.odd', ('tab.bg.odd',
SettingValue(types.QtColor(), 'grey'), SettingValue(typ.QtColor(), 'grey'),
"Background color of unselected odd tabs."), "Background color of unselected odd tabs."),
('tab.bg.even', ('tab.bg.even',
SettingValue(types.QtColor(), 'darkgrey'), SettingValue(typ.QtColor(), 'darkgrey'),
"Background color of unselected even tabs."), "Background color of unselected even tabs."),
('tab.bg.selected', ('tab.bg.selected',
SettingValue(types.QtColor(), 'black'), SettingValue(typ.QtColor(), 'black'),
"Background color of selected tabs."), "Background color of selected tabs."),
('tab.bg.bar', ('tab.bg.bar',
SettingValue(types.QtColor(), '#555555'), SettingValue(typ.QtColor(), '#555555'),
"Background color of the tabbar."), "Background color of the tabbar."),
('tab.indicator.start', ('tab.indicator.start',
SettingValue(types.QtColor(), '#0000aa'), SettingValue(typ.QtColor(), '#0000aa'),
"Color gradient start for the tab indicator."), "Color gradient start for the tab indicator."),
('tab.indicator.stop', ('tab.indicator.stop',
SettingValue(types.QtColor(), '#00aa00'), SettingValue(typ.QtColor(), '#00aa00'),
"Color gradient end for the tab indicator."), "Color gradient end for the tab indicator."),
('tab.indicator.error', ('tab.indicator.error',
SettingValue(types.QtColor(), '#ff0000'), SettingValue(typ.QtColor(), '#ff0000'),
"Color for the tab indicator on errors.."), "Color for the tab indicator on errors.."),
('tab.indicator.system', ('tab.indicator.system',
SettingValue(types.ColorSystem(), 'rgb'), SettingValue(typ.ColorSystem(), 'rgb'),
"Color gradient interpolation system for the tab indicator."), "Color gradient interpolation system for the tab indicator."),
('tab.seperator', ('tab.seperator',
SettingValue(types.QssColor(), '#555555'), SettingValue(typ.QssColor(), '#555555'),
"Color for the tab seperator."), "Color for the tab seperator."),
('hints.fg', ('hints.fg',
SettingValue(types.CssColor(), 'black'), SettingValue(typ.CssColor(), 'black'),
"Font color for hints."), "Font color for hints."),
('hints.fg.match', ('hints.fg.match',
SettingValue(types.CssColor(), 'green'), SettingValue(typ.CssColor(), 'green'),
"Font color for the matched part of hints."), "Font color for the matched part of hints."),
('hints.bg', ('hints.bg',
SettingValue(types.CssColor(), '-webkit-gradient(linear, left top, ' SettingValue(typ.CssColor(), '-webkit-gradient(linear, left top, '
'left bottom, color-stop(0%,#FFF785), ' 'left bottom, color-stop(0%,#FFF785), '
'color-stop(100%,#FFC542))'), 'color-stop(100%,#FFC542))'),
"Background color for hints."), "Background color for hints."),
('downloads.fg', ('downloads.fg',
SettingValue(types.QtColor(), '#ffffff'), SettingValue(typ.QtColor(), '#ffffff'),
"Foreground color for downloads."), "Foreground color for downloads."),
('downloads.bg.bar', ('downloads.bg.bar',
SettingValue(types.QssColor(), 'black'), SettingValue(typ.QssColor(), 'black'),
"Background color for the download bar."), "Background color for the download bar."),
('downloads.bg.start', ('downloads.bg.start',
SettingValue(types.QtColor(), '#0000aa'), SettingValue(typ.QtColor(), '#0000aa'),
"Color gradient start for downloads."), "Color gradient start for downloads."),
('downloads.bg.stop', ('downloads.bg.stop',
SettingValue(types.QtColor(), '#00aa00'), SettingValue(typ.QtColor(), '#00aa00'),
"Color gradient end for downloads."), "Color gradient end for downloads."),
('downloads.bg.system', ('downloads.bg.system',
SettingValue(types.ColorSystem(), 'rgb'), SettingValue(typ.ColorSystem(), 'rgb'),
"Color gradient interpolation system for downloads."), "Color gradient interpolation system for downloads."),
)), )),
('fonts', sect.KeyValue( ('fonts', sect.KeyValue(
('_monospace', ('_monospace',
SettingValue(types.Font(), 'Terminus, Monospace, "DejaVu Sans Mono", ' SettingValue(typ.Font(), 'Terminus, Monospace, "DejaVu Sans Mono", '
'Consolas, Monaco, "Bitstream Vera Sans Mono", ' 'Consolas, Monaco, "Bitstream Vera Sans Mono", '
'"Andale Mono", "Liberation Mono", "Courier New", ' '"Andale Mono", "Liberation Mono", "Courier New", '
'Courier, monospace, Fixed, Terminal'), 'Courier, monospace, Fixed, Terminal'),
"Default monospace fonts."), "Default monospace fonts."),
('completion', ('completion',
SettingValue(types.Font(), '8pt ${_monospace}'), SettingValue(typ.Font(), '8pt ${_monospace}'),
"Font used in the completion widget."), "Font used in the completion widget."),
('tabbar', ('tabbar',
SettingValue(types.QtFont(), '8pt ${_monospace}'), SettingValue(typ.QtFont(), '8pt ${_monospace}'),
"Font used in the tabbar."), "Font used in the tabbar."),
('statusbar', ('statusbar',
SettingValue(types.Font(), '8pt ${_monospace}'), SettingValue(typ.Font(), '8pt ${_monospace}'),
"Font used in the statusbar."), "Font used in the statusbar."),
('downloads', ('downloads',
SettingValue(types.Font(), '8pt ${_monospace}'), SettingValue(typ.Font(), '8pt ${_monospace}'),
"Font used for the downloadbar."), "Font used for the downloadbar."),
('hints', ('hints',
SettingValue(types.Font(), 'bold 12px Monospace'), SettingValue(typ.Font(), 'bold 12px Monospace'),
"Font used for the hints."), "Font used for the hints."),
('debug-console', ('debug-console',
SettingValue(types.QtFont(), '8pt ${_monospace}'), SettingValue(typ.QtFont(), '8pt ${_monospace}'),
"Font used for the debugging console."), "Font used for the debugging console."),
('web-family-standard', ('web-family-standard',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Font family for standard fonts."), "Font family for standard fonts."),
('web-family-fixed', ('web-family-fixed',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Font family for fixed fonts."), "Font family for fixed fonts."),
('web-family-serif', ('web-family-serif',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Font family for serif fonts."), "Font family for serif fonts."),
('web-family-sans-serif', ('web-family-sans-serif',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Font family for sans-serif fonts."), "Font family for sans-serif fonts."),
('web-family-cursive', ('web-family-cursive',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Font family for cursive fonts."), "Font family for cursive fonts."),
('web-family-fantasy', ('web-family-fantasy',
SettingValue(types.String(none_ok=True), ''), SettingValue(typ.String(none_ok=True), ''),
"Font family for fantasy fonts."), "Font family for fantasy fonts."),
('web-size-minimum', ('web-size-minimum',
SettingValue(types.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), SettingValue(
''), typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''),
"The hard minimum font size."), "The hard minimum font size."),
('web-size-minimum-logical', ('web-size-minimum-logical',
SettingValue(types.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), SettingValue(
''), typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''),
"The minimum logical font size that is applied when zooming out."), "The minimum logical font size that is applied when zooming out."),
('web-size-default', ('web-size-default',
SettingValue(types.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), SettingValue(
''), "The default font size for regular text."), typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''),
"The default font size for regular text."),
('web-size-default-fixed', ('web-size-default-fixed',
SettingValue(types.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), SettingValue(
''), typ.Int(none_ok=True, minval=1, maxval=MAXVALS['int']), ''),
"The default font size for fixed-pitch text."), "The default font size for fixed-pitch text."),
)), )),
]) ])

View File

@ -23,13 +23,13 @@ import re
import shlex import shlex
import codecs import codecs
import os.path import os.path
from sre_constants import error as RegexError import sre_constants
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QColor, QFont from PyQt5.QtGui import QColor, QFont
from PyQt5.QtNetwork import QNetworkProxy from PyQt5.QtNetwork import QNetworkProxy
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import utils as cmdutils
SYSTEM_PROXY = object() # Return value for Proxy type SYSTEM_PROXY = object() # Return value for Proxy type
@ -734,7 +734,7 @@ class Regex(BaseType):
raise ValidationError(value, "may not be empty!") raise ValidationError(value, "may not be empty!")
try: try:
re.compile(value, self.flags) re.compile(value, self.flags)
except RegexError as e: except sre_constants.error as e:
raise ValidationError(value, "must be a valid regex - " + str(e)) raise ValidationError(value, "must be a valid regex - " + str(e))
def transform(self, value): def transform(self, value):
@ -762,7 +762,7 @@ class RegexList(List):
def validate(self, value): def validate(self, value):
try: try:
vals = self.transform(value) vals = self.transform(value)
except RegexError as e: except sre_constants.error as e:
raise ValidationError(value, "must be a list valid regexes - " + raise ValidationError(value, "must be a list valid regexes - " +
str(e)) str(e))
if not self.none_ok and None in vals: if not self.none_ok and None in vals:

View File

@ -21,12 +21,12 @@
import os import os
import os.path import os.path
from configparser import ConfigParser import configparser
import qutebrowser.utils.log as log from qutebrowser.utils import log
class ReadConfigParser(ConfigParser): class ReadConfigParser(configparser.ConfigParser):
"""Our own ConfigParser subclass to read the main config. """Our own ConfigParser subclass to read the main config.

View File

@ -24,7 +24,7 @@ import os.path
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot
import qutebrowser.utils.log as log from qutebrowser.utils import log
class LineConfigParser: class LineConfigParser:
@ -82,7 +82,7 @@ class LineConfigParser:
log.destroy.debug("No data to save.") log.destroy.debug("No data to save.")
return return
# We need to import this here because config needs LineConfigParser. # We need to import this here because config needs LineConfigParser.
import qutebrowser.config.config as config from qutebrowser.config import config
limit = -1 if self._limit is None else config.get(*self._limit) limit = -1 if self._limit is None else config.get(*self._limit)
if limit == 0: if limit == 0:
return return
@ -98,7 +98,7 @@ class LineConfigParser:
if self._limit is None: if self._limit is None:
return return
# We need to import this here because config needs LineConfigParser. # We need to import this here because config needs LineConfigParser.
import qutebrowser.config.config as config from qutebrowser.config import config
value = config.get(section, option) value = config.get(section, option)
if (section, option) == self._limit and value == 0: if (section, option) == self._limit and value == 0:
if os.path.exists(self._configfile): if os.path.exists(self._configfile):

View File

@ -19,9 +19,9 @@
"""Setting sections used for qutebrowser.""" """Setting sections used for qutebrowser."""
from collections import OrderedDict, ChainMap import collections
from qutebrowser.config.value import SettingValue from qutebrowser.config import value as confvalue
class Section: class Section:
@ -108,7 +108,7 @@ class KeyValue(Section):
super().__init__() super().__init__()
if not defaults: if not defaults:
return return
self.values = OrderedDict() self.values = collections.OrderedDict()
for (k, v, desc) in defaults: for (k, v, desc) in defaults:
assert k not in self.values, k assert k not in self.values, k
self.values[k] = v self.values[k] = v
@ -160,17 +160,17 @@ class ValueList(Section):
self._ordered_value_cache = None self._ordered_value_cache = None
self.keytype = keytype self.keytype = keytype
self.valtype = valtype self.valtype = valtype
self.layers = OrderedDict([ self.layers = collections.OrderedDict([
('default', OrderedDict()), ('default', collections.OrderedDict()),
('conf', OrderedDict()), ('conf', collections.OrderedDict()),
('temp', OrderedDict()), ('temp', collections.OrderedDict()),
]) ])
defaultlayer = self.layers['default'] defaultlayer = self.layers['default']
for key, value in defaults: for key, value in defaults:
assert key not in defaultlayer, key assert key not in defaultlayer, key
defaultlayer[key] = SettingValue(valtype, value) defaultlayer[key] = confvalue.SettingValue(valtype, value)
self.values = ChainMap(self.layers['temp'], self.layers['conf'], self.values = collections.ChainMap(
self.layers['default']) self.layers['temp'], self.layers['conf'], self.layers['default'])
@property @property
def ordered_values(self): def ordered_values(self):
@ -180,7 +180,7 @@ class ValueList(Section):
iterating/items/etc. when order matters. iterating/items/etc. when order matters.
""" """
if self._ordered_value_cache is None: if self._ordered_value_cache is None:
self._ordered_value_cache = OrderedDict() self._ordered_value_cache = collections.OrderedDict()
for layer in self.layers.values(): for layer in self.layers.values():
self._ordered_value_cache.update(layer) self._ordered_value_cache.update(layer)
return self._ordered_value_cache return self._ordered_value_cache
@ -190,14 +190,15 @@ class ValueList(Section):
if key in self.layers[layer]: if key in self.layers[layer]:
self.layers[layer][key].setv(layer, value, interpolated) self.layers[layer][key].setv(layer, value, interpolated)
else: else:
val = SettingValue(self.valtype) val = confvalue.SettingValue(self.valtype)
val.setv(layer, value, interpolated) val.setv(layer, value, interpolated)
self.layers[layer][key] = val self.layers[layer][key] = val
self._ordered_value_cache = None self._ordered_value_cache = None
def dump_userconfig(self): def dump_userconfig(self):
changed = [] changed = []
mapping = ChainMap(self.layers['temp'], self.layers['conf']) mapping = collections.ChainMap(
self.layers['temp'], self.layers['conf'])
for k, v in mapping.items(): for k, v in mapping.items():
try: try:
if v.value != self.layers['default'][k].value: if v.value != self.layers['default'][k].value:

View File

@ -24,13 +24,13 @@ Module attributes:
_fontdict: The global cached FontDict. _fontdict: The global cached FontDict.
""" """
from functools import partial import functools
from PyQt5.QtGui import QColor from PyQt5.QtGui import QColor
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.utils import misc as utils
from qutebrowser.utils.log import style as logger from qutebrowser.utils.log import style as logger
from qutebrowser.utils.misc import compact_text
_colordict = None _colordict = None
@ -68,9 +68,10 @@ def set_register_stylesheet(obj):
""" """
qss = get_stylesheet(obj.STYLESHEET) qss = get_stylesheet(obj.STYLESHEET)
logger.debug("stylesheet for {}: {}".format(obj.__class__.__name__, logger.debug("stylesheet for {}: {}".format(obj.__class__.__name__,
compact_text(qss))) utils.compact_text(qss)))
obj.setStyleSheet(qss) obj.setStyleSheet(qss)
config.instance().changed.connect(partial(_update_stylesheet, obj)) config.instance().changed.connect(
functools.partial(_update_stylesheet, obj))
def _update_stylesheet(obj, _section, _option): def _update_stylesheet(obj, _section, _option):

View File

@ -19,7 +19,7 @@
"""A single value (with multiple layers possibly) in the config.""" """A single value (with multiple layers possibly) in the config."""
from collections import OrderedDict import collections
class SettingValue: class SettingValue:
@ -43,7 +43,8 @@ class SettingValue:
default: Raw value to set. default: Raw value to set.
""" """
self.typ = typ self.typ = typ
self._values = OrderedDict.fromkeys(['temp', 'conf', 'default']) self._values = collections.OrderedDict.fromkeys(
['temp', 'conf', 'default'])
self._values['default'] = default self._values['default'] = default
def __str__(self): def __str__(self):
@ -72,7 +73,7 @@ class SettingValue:
startlayer: The first layer to include. startlayer: The first layer to include.
""" """
idx = list(self._values.keys()).index(startlayer) idx = list(self._values.keys()).index(startlayer)
d = OrderedDict(list(self._values.items())[idx:]) d = collections.OrderedDict(list(self._values.items())[idx:])
return d return d
def get_first_value(self, startlayer=None): def get_first_value(self, startlayer=None):

View File

@ -30,11 +30,11 @@ from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtCore import QStandardPaths from PyQt5.QtCore import QStandardPaths
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import usertypes
from qutebrowser.utils.misc import get_standard_dir from qutebrowser.utils import misc as utils
MapType = enum('MapType', 'attribute', 'setter', 'static_setter') MapType = usertypes.enum('MapType', 'attribute', 'setter', 'static_setter')
MAPPINGS = { MAPPINGS = {
@ -177,7 +177,7 @@ def _set_setting(typ, arg, value):
def init(): def init():
"""Initialize the global QWebSettings.""" """Initialize the global QWebSettings."""
global settings global settings
cachedir = get_standard_dir(QStandardPaths.CacheLocation) cachedir = utils.get_standard_dir(QStandardPaths.CacheLocation)
QWebSettings.enablePersistentStorage(cachedir) QWebSettings.enablePersistentStorage(cachedir)
settings = QWebSettings.globalSettings() settings = QWebSettings.globalSettings()
for sectname, section in MAPPINGS.items(): for sectname, section in MAPPINGS.items():

View File

@ -21,14 +21,14 @@
import re import re
import string import string
from functools import partial import functools
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QObject
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.utils.usertypes import enum, Timer from qutebrowser.utils import usertypes
from qutebrowser.utils import misc as utils
from qutebrowser.utils.log import keyboard as logger from qutebrowser.utils.log import keyboard as logger
from qutebrowser.utils.misc import keyevent_to_string, normalize_keystr
class BaseKeyParser(QObject): class BaseKeyParser(QObject):
@ -71,8 +71,9 @@ class BaseKeyParser(QObject):
keystring_updated = pyqtSignal(str) keystring_updated = pyqtSignal(str)
do_log = True do_log = True
Match = enum('Match', 'partial', 'definitive', 'ambiguous', 'none') Match = usertypes.enum('Match', 'partial', 'definitive', 'ambiguous',
Type = enum('Type', 'chain', 'special') 'none')
Type = usertypes.enum('Type', 'chain', 'special')
def __init__(self, parent=None, supports_count=None, def __init__(self, parent=None, supports_count=None,
supports_chains=False): supports_chains=False):
@ -113,7 +114,7 @@ class BaseKeyParser(QObject):
Return: Return:
True if event has been handled, False otherwise. True if event has been handled, False otherwise.
""" """
binding = keyevent_to_string(e) binding = utils.keyevent_to_string(e)
if binding is None: if binding is None:
self._debug_log("Ignoring only-modifier keyeevent.") self._debug_log("Ignoring only-modifier keyeevent.")
return False return False
@ -266,11 +267,11 @@ class BaseKeyParser(QObject):
# execute in `time' ms # execute in `time' ms
self._debug_log("Scheduling execution of {} in {}ms".format( self._debug_log("Scheduling execution of {} in {}ms".format(
binding, time)) binding, time))
self._timer = Timer(self, 'ambigious_match') self._timer = usertypes.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(
count)) functools.partial(self.delayed_exec, binding, count))
self._timer.start() self._timer.start()
def delayed_exec(self, command, count): def delayed_exec(self, command, count):
@ -329,7 +330,7 @@ class BaseKeyParser(QObject):
if not cmd: if not cmd:
continue continue
elif key.startswith('<') and key.endswith('>'): elif key.startswith('<') and key.endswith('>'):
keystr = normalize_keystr(key[1:-1]) keystr = utils.normalize_keystr(key[1:-1])
self.special_bindings[keystr] = cmd self.special_bindings[keystr] = cmd
elif self._supports_chains: elif self._supports_chains:
self.bindings[key] = cmd self.bindings[key] = cmd

View File

@ -20,10 +20,9 @@
"""Advanced keyparsers.""" """Advanced keyparsers."""
from qutebrowser.keyinput.basekeyparser import BaseKeyParser from qutebrowser.keyinput.basekeyparser import BaseKeyParser
import qutebrowser.utils.message as message from qutebrowser.utils import message
from qutebrowser.commands import runners
from qutebrowser.commands.runners import CommandRunner from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.commands.exceptions import CommandMetaError, CommandError
class CommandKeyParser(BaseKeyParser): class CommandKeyParser(BaseKeyParser):
@ -37,12 +36,12 @@ class CommandKeyParser(BaseKeyParser):
def __init__(self, parent=None, supports_count=None, def __init__(self, parent=None, supports_count=None,
supports_chains=False): supports_chains=False):
super().__init__(parent, supports_count, supports_chains) super().__init__(parent, supports_count, supports_chains)
self.commandrunner = CommandRunner() self.commandrunner = runners.CommandRunner()
def execute(self, cmdstr, _keytype, count=None): def execute(self, cmdstr, _keytype, count=None):
try: try:
self.commandrunner.run(cmdstr, count) self.commandrunner.run(cmdstr, count)
except (CommandMetaError, CommandError) as e: except (cmdexc.CommandMetaError, cmdexc.CommandError) as e:
message.error(e, immediately=True) message.error(e, immediately=True)

View File

@ -27,11 +27,11 @@ from PyQt5.QtGui import QWindow
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import utils as cmdutils
from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.utils import usertypes
from qutebrowser.utils.log import modes as logger from qutebrowser.utils.log import modes as logger
from qutebrowser.utils.usertypes import KeyMode
from qutebrowser.commands.exceptions import CommandError
class ModeLockedError(Exception): class ModeLockedError(Exception):
@ -96,8 +96,8 @@ class ModeManager(QObject):
arg: The mode which has been left. arg: The mode which has been left.
""" """
entered = pyqtSignal(KeyMode) entered = pyqtSignal(usertypes.KeyMode)
left = pyqtSignal(KeyMode) left = pyqtSignal(usertypes.KeyMode)
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
@ -142,7 +142,7 @@ class ModeManager(QObject):
True if event should be filtered, False otherwise. True if event should be filtered, False otherwise.
""" """
handler = self._handlers[self.mode] handler = self._handlers[self.mode]
if self.mode != KeyMode.insert: if self.mode != usertypes.KeyMode.insert:
logger.debug("got keypress in mode {} - calling handler {}".format( logger.debug("got keypress in mode {} - calling handler {}".format(
self.mode, handler.__qualname__)) self.mode, handler.__qualname__))
handled = handler(event) if handler is not None else False handled = handler(event) if handler is not None else False
@ -161,7 +161,7 @@ class ModeManager(QObject):
if not filter_this: if not filter_this:
self._releaseevents_to_pass.append(event) self._releaseevents_to_pass.append(event)
if self.mode != KeyMode.insert: if self.mode != usertypes.KeyMode.insert:
logger.debug("handled: {}, forward-unbound-keys: {}, passthrough: " logger.debug("handled: {}, forward-unbound-keys: {}, passthrough: "
"{}, is_non_alnum: {} --> filter: {}".format( "{}, is_non_alnum: {} --> filter: {}".format(
handled, self._forward_unbound_keys, handled, self._forward_unbound_keys,
@ -186,7 +186,7 @@ class ModeManager(QObject):
filter_this = False filter_this = False
else: else:
filter_this = True filter_this = True
if self.mode != KeyMode.insert: if self.mode != usertypes.KeyMode.insert:
logger.debug("filter: {}".format(filter_this)) logger.debug("filter: {}".format(filter_this))
return filter_this return filter_this
@ -199,7 +199,7 @@ class ModeManager(QObject):
passthrough: Whether to pass keybindings in this mode through to passthrough: Whether to pass keybindings in this mode through to
the widgets. the widgets.
""" """
if not isinstance(mode, KeyMode): if not isinstance(mode, usertypes.KeyMode):
raise TypeError("Mode {} is no KeyMode member!".format(mode)) raise TypeError("Mode {} is no KeyMode member!".format(mode))
self._handlers[mode] = handler self._handlers[mode] = handler
if passthrough: if passthrough:
@ -215,7 +215,7 @@ class ModeManager(QObject):
Emit: Emit:
entered: With the new mode name. entered: With the new mode name.
""" """
if not isinstance(mode, KeyMode): if not isinstance(mode, usertypes.KeyMode):
raise TypeError("Mode {} is no KeyMode member!".format(mode)) raise TypeError("Mode {} is no KeyMode member!".format(mode))
if self.locked: if self.locked:
logger.debug("Not entering mode {} because mode is locked to " logger.debug("Not entering mode {} because mode is locked to "
@ -241,9 +241,9 @@ class ModeManager(QObject):
mode: The mode to enter. mode: The mode to enter.
""" """
try: try:
m = KeyMode[mode] m = usertypes.KeyMode[mode]
except KeyError: except KeyError:
raise CommandError("Mode {} does not exist!".format(mode)) raise cmdexc.CommandError("Mode {} does not exist!".format(mode))
self.enter(m, 'command') self.enter(m, 'command')
def leave(self, mode, reason=None): def leave(self, mode, reason=None):
@ -267,10 +267,10 @@ class ModeManager(QObject):
self.left.emit(mode) self.left.emit(mode)
@cmdutils.register(instance='modeman', name='leave-mode', @cmdutils.register(instance='modeman', name='leave-mode',
not_modes=[KeyMode.normal], hide=True) not_modes=[usertypes.KeyMode.normal], hide=True)
def leave_current_mode(self): def leave_current_mode(self):
"""Leave the mode we're currently in.""" """Leave the mode we're currently in."""
if self.mode == KeyMode.normal: if self.mode == usertypes.KeyMode.normal:
raise ValueError("Can't leave normal mode!") raise ValueError("Can't leave normal mode!")
self.leave(self.mode, 'leave current') self.leave(self.mode, 'leave current')

View File

@ -25,18 +25,18 @@ Module attributes:
from PyQt5.QtCore import pyqtSignal, Qt from PyQt5.QtCore import pyqtSignal, Qt
import qutebrowser.utils.message as message from qutebrowser.utils import message
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.keyinput.keyparser import CommandKeyParser from qutebrowser.keyinput import keyparser
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import usertypes
from qutebrowser.utils.log import keyboard as logger from qutebrowser.utils.log import keyboard as logger
STARTCHARS = ":/?" STARTCHARS = ":/?"
LastPress = enum('LastPress', 'none', 'filtertext', 'keystring') LastPress = usertypes.enum('LastPress', 'none', 'filtertext', 'keystring')
class NormalKeyParser(CommandKeyParser): class NormalKeyParser(keyparser.CommandKeyParser):
"""KeyParser for normalmode with added STARTCHARS detection.""" """KeyParser for normalmode with added STARTCHARS detection."""
@ -63,7 +63,7 @@ class NormalKeyParser(CommandKeyParser):
return super()._handle_single_key(e) return super()._handle_single_key(e)
class PromptKeyParser(CommandKeyParser): class PromptKeyParser(keyparser.CommandKeyParser):
"""KeyParser for yes/no prompts.""" """KeyParser for yes/no prompts."""
@ -77,7 +77,7 @@ class PromptKeyParser(CommandKeyParser):
return '<{}>'.format(self.__class__.__name__) return '<{}>'.format(self.__class__.__name__)
class HintKeyParser(CommandKeyParser): class HintKeyParser(keyparser.CommandKeyParser):
"""KeyChainParser for hints. """KeyChainParser for hints.

View File

@ -26,11 +26,11 @@ Module attributes:
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem from PyQt5.QtGui import QStandardItemModel, QStandardItem
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import usertypes
from qutebrowser.utils.qt import qt_ensure_valid from qutebrowser.utils import qt as qtutils
Role = enum('Role', 'marks', 'sort', start=Qt.UserRole, is_int=True) Role = usertypes.enum('Role', 'marks', 'sort', start=Qt.UserRole, is_int=True)
class BaseCompletionModel(QStandardItemModel): class BaseCompletionModel(QStandardItemModel):
@ -74,7 +74,7 @@ class BaseCompletionModel(QStandardItemModel):
index: A QModelIndex of the item to mark. index: A QModelIndex of the item to mark.
needle: The string to mark. needle: The string to mark.
""" """
qt_ensure_valid(index) qtutils.qt_ensure_valid(index)
haystack = self.data(index) haystack = self.data(index)
marks = self._get_marks(needle, haystack) marks = self._get_marks(needle, haystack)
ok = self.setData(index, marks, Role.marks) ok = self.setData(index, marks, Role.marks)
@ -132,7 +132,7 @@ class BaseCompletionModel(QStandardItemModel):
Return: Return:
The item flags, or Qt.NoItemFlags on error. The item flags, or Qt.NoItemFlags on error.
""" """
qt_ensure_valid(index) qtutils.qt_ensure_valid(index)
if index.parent().isValid(): if index.parent().isValid():
# item # item
return Qt.ItemIsEnabled | Qt.ItemIsSelectable return Qt.ItemIsEnabled | Qt.ItemIsSelectable

View File

@ -21,7 +21,7 @@
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot
from qutebrowser.utils.usertypes import NeighborList from qutebrowser.utils import usertypes
from qutebrowser.utils.log import misc as logger from qutebrowser.utils.log import misc as logger
@ -85,7 +85,7 @@ class History:
items = self.history items = self.history
if not items: if not items:
raise HistoryEmptyError raise HistoryEmptyError
self._tmphist = NeighborList(items) self._tmphist = usertypes.NeighborList(items)
return self._tmphist.lastitem() return self._tmphist.lastitem()
@pyqtSlot() @pyqtSlot()

View File

@ -21,15 +21,14 @@
from PyQt5.QtCore import pyqtSlot, Qt, QCoreApplication from PyQt5.QtCore import pyqtSlot, Qt, QCoreApplication
import qutebrowser.config.config as config from qutebrowser.config import config, configdata
import qutebrowser.config.configdata as configdata from qutebrowser.models import basecompletion
from qutebrowser.models.basecompletion import BaseCompletionModel from qutebrowser.commands import utils as cmdutils
from qutebrowser.commands.utils import cmd_dict from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.log import completion as logger from qutebrowser.utils.log import completion as logger
from qutebrowser.utils.qt import qt_ensure_valid
class SettingSectionCompletionModel(BaseCompletionModel): class SettingSectionCompletionModel(basecompletion.BaseCompletionModel):
"""A CompletionModel filled with settings sections.""" """A CompletionModel filled with settings sections."""
@ -43,7 +42,7 @@ class SettingSectionCompletionModel(BaseCompletionModel):
self.new_item(cat, name, desc) self.new_item(cat, name, desc)
class SettingOptionCompletionModel(BaseCompletionModel): class SettingOptionCompletionModel(basecompletion.BaseCompletionModel):
"""A CompletionModel filled with settings and their descriptions. """A CompletionModel filled with settings and their descriptions.
@ -88,14 +87,14 @@ class SettingOptionCompletionModel(BaseCompletionModel):
return return
val = config.get(section, option, raw=True) val = config.get(section, option, raw=True)
idx = item.index() idx = item.index()
qt_ensure_valid(idx) qtutils.qt_ensure_valid(idx)
ok = self.setData(idx, val, Qt.DisplayRole) ok = self.setData(idx, val, Qt.DisplayRole)
if not ok: if not ok:
raise ValueError("Setting data failed! (section: {}, option: {}, " raise ValueError("Setting data failed! (section: {}, option: {}, "
"value: {})".format(section, option, val)) "value: {})".format(section, option, val))
class SettingValueCompletionModel(BaseCompletionModel): class SettingValueCompletionModel(basecompletion.BaseCompletionModel):
"""A CompletionModel filled with setting values. """A CompletionModel filled with setting values.
@ -139,14 +138,14 @@ class SettingValueCompletionModel(BaseCompletionModel):
if not value: if not value:
value = '""' value = '""'
idx = self.cur_item.index() idx = self.cur_item.index()
qt_ensure_valid(idx) qtutils.qt_ensure_valid(idx)
ok = self.setData(idx, value, Qt.DisplayRole) ok = self.setData(idx, value, Qt.DisplayRole)
if not ok: if not ok:
raise ValueError("Setting data failed! (section: {}, option: {}, " raise ValueError("Setting data failed! (section: {}, option: {}, "
"value: {})".format(section, option, value)) "value: {})".format(section, option, value))
class CommandCompletionModel(BaseCompletionModel): class CommandCompletionModel(basecompletion.BaseCompletionModel):
"""A CompletionModel filled with all commands and descriptions.""" """A CompletionModel filled with all commands and descriptions."""
@ -154,9 +153,9 @@ class CommandCompletionModel(BaseCompletionModel):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
assert cmd_dict assert cmdutils.cmd_dict
cmdlist = [] cmdlist = []
for obj in set(cmd_dict.values()): for obj in set(cmdutils.cmd_dict.values()):
if obj.hide or (obj.debug and not if obj.hide or (obj.debug and not
QCoreApplication.instance().args.debug): QCoreApplication.instance().args.debug):
pass pass

View File

@ -25,9 +25,9 @@ Contains:
from PyQt5.QtCore import QSortFilterProxyModel, QModelIndex from PyQt5.QtCore import QSortFilterProxyModel, QModelIndex
from qutebrowser.models.basecompletion import Role from qutebrowser.models import basecompletion as completion
from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.log import completion as logger from qutebrowser.utils.log import completion as logger
from qutebrowser.utils.qt import qt_ensure_valid
class CompletionFilterModel(QSortFilterProxyModel): class CompletionFilterModel(QSortFilterProxyModel):
@ -81,7 +81,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
count = 0 count = 0
for i in range(self.rowCount()): for i in range(self.rowCount()):
cat = self.index(i, 0) cat = self.index(i, 0)
qt_ensure_valid(cat) qtutils.qt_ensure_valid(cat)
count += self.rowCount(cat) count += self.rowCount(cat)
return count return count
@ -89,10 +89,10 @@ class CompletionFilterModel(QSortFilterProxyModel):
"""Return the first item in the model.""" """Return the first item in the model."""
for i in range(self.rowCount()): for i in range(self.rowCount()):
cat = self.index(i, 0) cat = self.index(i, 0)
qt_ensure_valid(cat) qtutils.qt_ensure_valid(cat)
if cat.model().hasChildren(cat): if cat.model().hasChildren(cat):
index = self.index(0, 0, cat) index = self.index(0, 0, cat)
qt_ensure_valid(index) qtutils.qt_ensure_valid(index)
return index return index
return QModelIndex() return QModelIndex()
@ -100,10 +100,10 @@ class CompletionFilterModel(QSortFilterProxyModel):
"""Return the last item in the model.""" """Return the last item in the model."""
for i in range(self.rowCount() - 1, -1, -1): for i in range(self.rowCount() - 1, -1, -1):
cat = self.index(i, 0) cat = self.index(i, 0)
qt_ensure_valid(cat) qtutils.qt_ensure_valid(cat)
if cat.model().hasChildren(cat): if cat.model().hasChildren(cat):
index = self.index(self.rowCount(cat) - 1, 0, cat) index = self.index(self.rowCount(cat) - 1, 0, cat)
qt_ensure_valid(index) qtutils.qt_ensure_valid(index)
return index return index
return QModelIndex() return QModelIndex()
@ -111,12 +111,12 @@ class CompletionFilterModel(QSortFilterProxyModel):
"""Mark the given text in all visible items.""" """Mark the given text in all visible items."""
for i in range(self.rowCount()): for i in range(self.rowCount()):
cat = self.index(i, 0) cat = self.index(i, 0)
qt_ensure_valid(cat) qtutils.qt_ensure_valid(cat)
for k in range(self.rowCount(cat)): for k in range(self.rowCount(cat)):
index = self.index(k, 0, cat) index = self.index(k, 0, cat)
qt_ensure_valid(index) qtutils.qt_ensure_valid(index)
index = self.mapToSource(index) index = self.mapToSource(index)
qt_ensure_valid(index) qtutils.qt_ensure_valid(index)
self.srcmodel.mark_item(index, text) self.srcmodel.mark_item(index, text)
def setSourceModel(self, model): def setSourceModel(self, model):
@ -142,7 +142,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
if parent == QModelIndex(): if parent == QModelIndex():
return True return True
idx = self.srcmodel.index(row, 0, parent) idx = self.srcmodel.index(row, 0, parent)
qt_ensure_valid(idx) qtutils.qt_ensure_valid(idx)
data = self.srcmodel.data(idx) data = self.srcmodel.data(idx)
# TODO more sophisticated filtering # TODO more sophisticated filtering
if not self.pattern: if not self.pattern:
@ -162,11 +162,11 @@ class CompletionFilterModel(QSortFilterProxyModel):
Return: Return:
True if left < right, else False True if left < right, else False
""" """
qt_ensure_valid(lindex) qtutils.qt_ensure_valid(lindex)
qt_ensure_valid(rindex) qtutils.qt_ensure_valid(rindex)
left_sort = self.srcmodel.data(lindex, role=Role.sort) left_sort = self.srcmodel.data(lindex, role=completion.Role.sort)
right_sort = self.srcmodel.data(rindex, role=Role.sort) right_sort = self.srcmodel.data(rindex, role=completion.Role.sort)
if left_sort is not None and right_sort is not None: if left_sort is not None and right_sort is not None:
return left_sort < right_sort return left_sort < right_sort

View File

@ -23,12 +23,12 @@ from PyQt5.QtCore import (pyqtSlot, Qt, QVariant, QAbstractListModel,
QModelIndex) QModelIndex)
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import usertypes
from qutebrowser.utils.qt import qt_ensure_valid from qutebrowser.utils import qt as qtutils
Role = enum('Role', 'item', start=Qt.UserRole, is_int=True) Role = usertypes.enum('Role', 'item', start=Qt.UserRole, is_int=True)
class DownloadModel(QAbstractListModel): class DownloadModel(QAbstractListModel):
@ -57,7 +57,7 @@ class DownloadModel(QAbstractListModel):
def on_data_changed(self, idx): def on_data_changed(self, idx):
"""Update view when DownloadManager data changed.""" """Update view when DownloadManager data changed."""
model_idx = self.index(idx, 0) model_idx = self.index(idx, 0)
qt_ensure_valid(model_idx) qtutils.qt_ensure_valid(model_idx)
self.dataChanged.emit(model_idx, model_idx) self.dataChanged.emit(model_idx, model_idx)
def last_index(self): def last_index(self):
@ -79,7 +79,7 @@ class DownloadModel(QAbstractListModel):
def data(self, index, role): def data(self, index, role):
"""Download data from DownloadManager.""" """Download data from DownloadManager."""
qt_ensure_valid(index) qtutils.qt_ensure_valid(index)
if index.parent().isValid() or index.column() != 0: if index.parent().isValid() or index.column() != 0:
return QVariant() return QVariant()

View File

@ -29,12 +29,9 @@ except ImportError:
else: else:
SSL_AVAILABLE = QSslSocket.supportsSsl() SSL_AVAILABLE = QSslSocket.supportsSsl()
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.utils.message as message from qutebrowser.utils import message, log, usertypes
import qutebrowser.utils.log as log from qutebrowser.network import qutescheme, schemehandler
from qutebrowser.network.qutescheme import QuteSchemeHandler
from qutebrowser.network.schemehandler import ErrorNetworkReply
from qutebrowser.utils.usertypes import PromptMode
class NetworkManager(QNetworkAccessManager): class NetworkManager(QNetworkAccessManager):
@ -52,7 +49,7 @@ class NetworkManager(QNetworkAccessManager):
super().__init__(parent) super().__init__(parent)
self._requests = [] self._requests = []
self._scheme_handlers = { self._scheme_handlers = {
'qute': QuteSchemeHandler(), 'qute': qutescheme.QuteSchemeHandler(),
} }
cookiejar = QCoreApplication.instance().cookiejar cookiejar = QCoreApplication.instance().cookiejar
parent = cookiejar.parent() parent = cookiejar.parent()
@ -105,14 +102,14 @@ class NetworkManager(QNetworkAccessManager):
def on_authentication_required(self, _reply, authenticator): def on_authentication_required(self, _reply, authenticator):
"""Called when a website needs authentication.""" """Called when a website needs authentication."""
answer = message.ask("Username ({}):".format(authenticator.realm()), answer = message.ask("Username ({}):".format(authenticator.realm()),
mode=PromptMode.user_pwd) mode=usertypes.PromptMode.user_pwd)
self._fill_authenticator(authenticator, answer) self._fill_authenticator(authenticator, answer)
@pyqtSlot('QNetworkProxy', 'QAuthenticator') @pyqtSlot('QNetworkProxy', 'QAuthenticator')
def on_proxy_authentication_required(self, _proxy, authenticator): def on_proxy_authentication_required(self, _proxy, authenticator):
"""Called when a proxy needs authentication.""" """Called when a proxy needs authentication."""
answer = message.ask("Proxy username ({}):".format( answer = message.ask("Proxy username ({}):".format(
authenticator.realm()), mode=PromptMode.user_pwd) authenticator.realm()), mode=usertypes.PromptMode.user_pwd)
self._fill_authenticator(authenticator, answer) self._fill_authenticator(authenticator, answer)
def createRequest(self, op, req, outgoing_data): def createRequest(self, op, req, outgoing_data):
@ -131,7 +128,7 @@ class NetworkManager(QNetworkAccessManager):
""" """
scheme = req.url().scheme() scheme = req.url().scheme()
if scheme == 'https' and not SSL_AVAILABLE: if scheme == 'https' and not SSL_AVAILABLE:
return ErrorNetworkReply( return schemehandler.ErrorNetworkReply(
req, "SSL is not supported by the installed Qt library!", req, "SSL is not supported by the installed Qt library!",
QNetworkReply.ProtocolUnknownError) QNetworkReply.ProtocolUnknownError)
elif scheme in self._scheme_handlers: elif scheme in self._scheme_handlers:

View File

@ -19,11 +19,11 @@
"""Handling of proxies.""" """Handling of proxies."""
import qutebrowser.config.config as config
from qutebrowser.config.conftypes import SYSTEM_PROXY
from PyQt5.QtNetwork import QNetworkProxyFactory from PyQt5.QtNetwork import QNetworkProxyFactory
from qutebrowser.config import config, conftypes
def init(): def init():
"""Set the application wide proxy factory.""" """Set the application wide proxy factory."""
@ -44,7 +44,7 @@ class ProxyFactory(QNetworkProxyFactory):
A list of QNetworkProxy objects in order of preference. A list of QNetworkProxy objects in order of preference.
""" """
proxy = config.get('network', 'proxy') proxy = config.get('network', 'proxy')
if proxy is SYSTEM_PROXY: if proxy is conftypes.SYSTEM_PROXY:
return QNetworkProxyFactory.systemProxyForQuery(query) return QNetworkProxyFactory.systemProxyForQuery(query)
else: else:
return [proxy] return [proxy]

View File

@ -29,12 +29,10 @@ import html as pyhtml
from PyQt5.QtNetwork import QNetworkReply from PyQt5.QtNetwork import QNetworkReply
import qutebrowser import qutebrowser
import qutebrowser.utils.log as logutils from qutebrowser.network import schemehandler
import qutebrowser.utils.version as version from qutebrowser.utils import version
from qutebrowser.network.schemehandler import (SchemeHandler, from qutebrowser.utils import log as logutils
SpecialNetworkReply, from qutebrowser.utils import misc as utils
ErrorNetworkReply)
from qutebrowser.utils.misc import read_file
_HTML_TEMPLATE = """ _HTML_TEMPLATE = """
@ -73,7 +71,7 @@ def _get_html(title, snippet, head=None):
return html return html
class QuteSchemeHandler(SchemeHandler): class QuteSchemeHandler(schemehandler.SchemeHandler):
"""Scheme handler for qute: URLs.""" """Scheme handler for qute: URLs."""
@ -97,12 +95,13 @@ class QuteSchemeHandler(SchemeHandler):
except AttributeError: except AttributeError:
errorstr = "No handler found for {}!".format( errorstr = "No handler found for {}!".format(
request.url().toDisplayString()) request.url().toDisplayString())
return ErrorNetworkReply(request, errorstr, return schemehandler.ErrorNetworkReply(
QNetworkReply.ContentNotFoundError, request, errorstr, QNetworkReply.ContentNotFoundError,
self.parent()) self.parent())
else: else:
data = handler() data = handler()
return SpecialNetworkReply(request, data, 'text/html', self.parent()) return schemehandler.SpecialNetworkReply(
request, data, 'text/html', self.parent())
class QuteHandlers: class QuteHandlers:
@ -171,4 +170,4 @@ class QuteHandlers:
@classmethod @classmethod
def gpl(cls): def gpl(cls):
"""Handler for qute:gpl. Return HTML content as bytes.""" """Handler for qute:gpl. Return HTML content as bytes."""
return read_file('html/COPYING.html').encode('ASCII') return utils.read_file('html/COPYING.html').encode('ASCII')

View File

@ -37,14 +37,14 @@ except ImportError:
sys.exit(100) sys.exit(100)
check_python_version() check_python_version()
from argparse import ArgumentParser import argparse
import qutebrowser.utils.earlyinit as earlyinit from qutebrowser.utils import earlyinit
def get_argparser(): def get_argparser():
"""Get the argparse parser.""" """Get the argparse parser."""
parser = ArgumentParser("usage: qutebrowser", parser = argparse.ArgumentParser("usage: qutebrowser",
description=qutebrowser.__description__) description=qutebrowser.__description__)
parser.add_argument('-c', '--confdir', help="Set config directory (empty " parser.add_argument('-c', '--confdir', help="Set config directory (empty "
"for no config storage)") "for no config storage)")
parser.add_argument('-V', '--version', help="Show version and quit.", parser.add_argument('-V', '--version', help="Show version and quit.",
@ -103,7 +103,7 @@ def main():
earlyinit.check_pyqt_core() earlyinit.check_pyqt_core()
# We do this import late as we need to do the version checking first. # We do this import late as we need to do the version checking first.
# Note we may not import webkit stuff yet as fix_harfbuzz didn't run. # Note we may not import webkit stuff yet as fix_harfbuzz didn't run.
import qutebrowser.utils.log as log from qutebrowser.utils import log
log.init_log(args) log.init_log(args)
log.init.debug("Log initialized.") log.init.debug("Log initialized.")
log.init.debug("Doing early init.") log.init.debug("Doing early init.")
@ -113,10 +113,10 @@ def main():
earlyinit.check_pkg_resources() earlyinit.check_pkg_resources()
earlyinit.check_pypeg2() earlyinit.check_pypeg2()
# We do this import late as we need to fix harfbuzz first. # We do this import late as we need to fix harfbuzz first.
from qutebrowser.app import Application from qutebrowser import app
from qutebrowser.utils.debug import trace_lines from qutebrowser.utils import debug
import PyQt5.QtWidgets as QtWidgets import PyQt5.QtWidgets as QtWidgets
app = Application(args) app = app.Application(args)
# We set qApp explicitely here to reduce the risk of segfaults while # We set qApp explicitely here to reduce the risk of segfaults while
# quitting. # quitting.
# See https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/561303/comments/7 # See https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/561303/comments/7
@ -127,6 +127,6 @@ def main():
ret = app.exec_() ret = app.exec_()
if args.debug_exit: if args.debug_exit:
print("Now logging late shutdown.", file=sys.stderr) print("Now logging late shutdown.", file=sys.stderr)
trace_lines(True) debug.trace_lines(True)
QtWidgets.qApp = None QtWidgets.qApp = None
return ret return ret

View File

@ -19,13 +19,13 @@
"""Tests for qutebrowser.config.conftypes.""" """Tests for qutebrowser.config.conftypes."""
import unittest import unittest
import unittest.mock as mock
import re import re
from collections import namedtuple import collections
from unittest import mock
import qutebrowser.config.conftypes as conftypes from qutebrowser.config import conftypes
from qutebrowser.test.stubs import FakeCmdUtils, FakeCommand from qutebrowser.test import stubs
from qutebrowser.utils.debug import qenum_key from qutebrowser.utils import debug
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QColor, QFont from PyQt5.QtGui import QColor, QFont
@ -37,9 +37,10 @@ class Font(QFont):
"""A QFont with a nicer repr().""" """A QFont with a nicer repr()."""
def __repr__(self): def __repr__(self):
weight = debug.qenum_key(QFont, self.weight(), add_base=True,
klass=QFont.Weight)
return '<Font family={}, pt={}, px={}, weight={}, style={}>'.format( return '<Font family={}, pt={}, px={}, weight={}, style={}>'.format(
self.family(), self.pointSize(), self.pixelSize(), self.family(), self.pointSize(), self.pixelSize(), weight,
qenum_key(QFont, self.weight(), add_base=True, klass=QFont.Weight),
self.style()) self.style())
@classmethod @classmethod
@ -853,10 +854,10 @@ class CommandTests(unittest.TestCase):
def setUp(self): def setUp(self):
self.old_cmdutils = conftypes.cmdutils self.old_cmdutils = conftypes.cmdutils
commands = { commands = {
'cmd1': FakeCommand("desc 1"), 'cmd1': stubs.FakeCommand("desc 1"),
'cmd2': FakeCommand("desc 2"), 'cmd2': stubs.FakeCommand("desc 2"),
} }
conftypes.cmdutils = FakeCmdUtils(commands) conftypes.cmdutils = stubs.FakeCmdUtils(commands)
self.t = conftypes.Command() self.t = conftypes.Command()
def tearDown(self): def tearDown(self):
@ -1057,7 +1058,8 @@ class QssColorTests(QtColorTests):
self.assertEqual(self.t.transform(v), v, v) self.assertEqual(self.t.transform(v), v, v)
FontDesc = namedtuple('FontDesc', ['style', 'weight', 'pt', 'px', 'family']) FontDesc = collections.namedtuple('FontDesc',
['style', 'weight', 'pt', 'px', 'family'])
class FontTests(unittest.TestCase): class FontTests(unittest.TestCase):

View File

@ -20,13 +20,13 @@
"""Helpers needed by tests.""" """Helpers needed by tests."""
import os import os
from contextlib import contextmanager import contextlib
from unittest.mock import create_autospec from unittest import mock
from PyQt5.QtGui import QKeyEvent from PyQt5.QtGui import QKeyEvent
@contextmanager @contextlib.contextmanager
def environ_set_temp(name, value): def environ_set_temp(name, value):
"""Set a temporary environment variable.""" """Set a temporary environment variable."""
try: try:
@ -43,8 +43,8 @@ def environ_set_temp(name, value):
def fake_keyevent(key, modifiers=0, text=''): def fake_keyevent(key, modifiers=0, text=''):
"""Generate a new fake QKeyPressEvent.""" """Generate a new fake QKeyPressEvent."""
mock = create_autospec(QKeyEvent, instance=True) evtmock = mock.create_autospec(QKeyEvent, instance=True)
mock.key.return_value = key evtmock.key.return_value = key
mock.modifiers.return_value = modifiers evtmock.modifiers.return_value = modifiers
mock.text.return_value = text evtmock.text.return_value = text
return mock return evtmock

View File

@ -23,14 +23,14 @@
import logging import logging
import unittest import unittest
from unittest.mock import Mock, patch from unittest import mock
import qutebrowser.keyinput.basekeyparser as basekeyparser
from qutebrowser.test.stubs import ConfigStub
from qutebrowser.test.helpers import fake_keyevent
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from qutebrowser.keyinput import basekeyparser
from qutebrowser.test import stubs, helpers
CONFIG = {'test': {'<Ctrl-a>': 'ctrla', CONFIG = {'test': {'<Ctrl-a>': 'ctrla',
'a': 'a', 'a': 'a',
'ba': 'ba', 'ba': 'ba',
@ -42,7 +42,7 @@ CONFIG = {'test': {'<Ctrl-a>': 'ctrla',
def setUpModule(): def setUpModule():
"""Mock out some imports in basekeyparser.""" """Mock out some imports in basekeyparser."""
basekeyparser.QObject = Mock() basekeyparser.QObject = mock.Mock()
logging.disable(logging.WARNING) logging.disable(logging.WARNING)
@ -99,8 +99,8 @@ class ReadConfigTests(unittest.TestCase):
"""Test reading the config.""" """Test reading the config."""
def setUp(self): def setUp(self):
basekeyparser.config = ConfigStub(CONFIG) basekeyparser.config = stubs.ConfigStub(CONFIG)
basekeyparser.Timer = Mock() basekeyparser.usertypes.Timer = mock.Mock()
def test_read_config_invalid(self): def test_read_config_invalid(self):
"""Test reading config without setting it before.""" """Test reading config without setting it before."""
@ -131,31 +131,32 @@ class SpecialKeysTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
patcher = patch('qutebrowser.keyinput.basekeyparser.Timer', patcher = mock.patch(
autospec=True) 'qutebrowser.keyinput.basekeyparser.usertypes.Timer',
autospec=True)
patcher.start() patcher.start()
self.addCleanup(patcher.stop) self.addCleanup(patcher.stop)
basekeyparser.config = ConfigStub(CONFIG) basekeyparser.config = stubs.ConfigStub(CONFIG)
self.kp = basekeyparser.BaseKeyParser() self.kp = basekeyparser.BaseKeyParser()
self.kp.execute = Mock() self.kp.execute = mock.Mock()
self.kp.read_config('test') self.kp.read_config('test')
def test_valid_key(self): def test_valid_key(self):
"""Test a valid special keyevent.""" """Test a valid special keyevent."""
self.kp.handle(fake_keyevent(Qt.Key_A, Qt.ControlModifier)) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, Qt.ControlModifier))
self.kp.handle(fake_keyevent(Qt.Key_X, Qt.ControlModifier)) self.kp.handle(helpers.fake_keyevent(Qt.Key_X, Qt.ControlModifier))
self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special) self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special)
def test_invalid_key(self): def test_invalid_key(self):
"""Test an invalid special keyevent.""" """Test an invalid special keyevent."""
self.kp.handle(fake_keyevent(Qt.Key_A, (Qt.ControlModifier | self.kp.handle(helpers.fake_keyevent(Qt.Key_A, (Qt.ControlModifier |
Qt.AltModifier))) Qt.AltModifier)))
self.assertFalse(self.kp.execute.called) self.assertFalse(self.kp.execute.called)
def test_keychain(self): def test_keychain(self):
"""Test a keychain.""" """Test a keychain."""
self.kp.handle(fake_keyevent(Qt.Key_B)) self.kp.handle(helpers.fake_keyevent(Qt.Key_B))
self.kp.handle(fake_keyevent(Qt.Key_A)) self.kp.handle(helpers.fake_keyevent(Qt.Key_A))
self.assertFalse(self.kp.execute.called) self.assertFalse(self.kp.execute.called)
@ -170,35 +171,35 @@ class KeyChainTests(unittest.TestCase):
def setUp(self): def setUp(self):
"""Set up mocks and read the test config.""" """Set up mocks and read the test config."""
basekeyparser.config = ConfigStub(CONFIG) basekeyparser.config = stubs.ConfigStub(CONFIG)
self.timermock = Mock() self.timermock = mock.Mock()
basekeyparser.Timer = Mock(return_value=self.timermock) basekeyparser.usertypes.Timer = mock.Mock(return_value=self.timermock)
self.kp = basekeyparser.BaseKeyParser(supports_chains=True, self.kp = basekeyparser.BaseKeyParser(supports_chains=True,
supports_count=False) supports_count=False)
self.kp.execute = Mock() self.kp.execute = mock.Mock()
self.kp.read_config('test') self.kp.read_config('test')
def test_valid_special_key(self): def test_valid_special_key(self):
"""Test valid special key.""" """Test valid special key."""
self.kp.handle(fake_keyevent(Qt.Key_A, Qt.ControlModifier)) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, Qt.ControlModifier))
self.kp.handle(fake_keyevent(Qt.Key_X, Qt.ControlModifier)) self.kp.handle(helpers.fake_keyevent(Qt.Key_X, Qt.ControlModifier))
self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special) self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
def test_invalid_special_key(self): def test_invalid_special_key(self):
"""Test invalid special key.""" """Test invalid special key."""
self.kp.handle(fake_keyevent(Qt.Key_A, (Qt.ControlModifier | self.kp.handle(helpers.fake_keyevent(Qt.Key_A, (Qt.ControlModifier |
Qt.AltModifier))) Qt.AltModifier)))
self.assertFalse(self.kp.execute.called) self.assertFalse(self.kp.execute.called)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
def test_keychain(self): def test_keychain(self):
"""Test valid keychain.""" """Test valid keychain."""
# Press 'x' which is ignored because of no match # Press 'x' which is ignored because of no match
self.kp.handle(fake_keyevent(Qt.Key_X, text='x')) self.kp.handle(helpers.fake_keyevent(Qt.Key_X, text='x'))
# Then start the real chain # Then start the real chain
self.kp.handle(fake_keyevent(Qt.Key_B, text='b')) self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='a')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None) self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
@ -206,9 +207,10 @@ class KeyChainTests(unittest.TestCase):
"""Test ambigious keychain.""" """Test ambigious keychain."""
# We start with 'a' where the keychain gives us an ambigious result. # We start with 'a' where the keychain gives us an ambigious result.
# Then we check if the timer has been set up correctly # Then we check if the timer has been set up correctly
self.kp.handle(fake_keyevent(Qt.Key_A, text='a')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
self.assertFalse(self.kp.execute.called) self.assertFalse(self.kp.execute.called)
basekeyparser.Timer.assert_called_once_with(self.kp, 'ambigious_match') basekeyparser.usertypes.Timer.assert_called_once_with(
self.kp, 'ambigious_match')
self.timermock.setSingleShot.assert_called_once_with(True) self.timermock.setSingleShot.assert_called_once_with(True)
self.timermock.setInterval.assert_called_once_with(100) self.timermock.setInterval.assert_called_once_with(100)
self.assertTrue(self.timermock.timeout.connect.called) self.assertTrue(self.timermock.timeout.connect.called)
@ -216,15 +218,15 @@ class KeyChainTests(unittest.TestCase):
self.timermock.start.assert_called_once_with() self.timermock.start.assert_called_once_with()
# Now we type an 'x' and check 'ax' has been executed and the timer # Now we type an 'x' and check 'ax' has been executed and the timer
# stopped. # stopped.
self.kp.handle(fake_keyevent(Qt.Key_X, text='x')) self.kp.handle(helpers.fake_keyevent(Qt.Key_X, text='x'))
self.kp.execute.assert_called_once_with('ax', self.kp.Type.chain, None) self.kp.execute.assert_called_once_with('ax', self.kp.Type.chain, None)
self.timermock.stop.assert_called_once_with() self.timermock.stop.assert_called_once_with()
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
def test_invalid_keychain(self): def test_invalid_keychain(self):
"""Test invalid keychain.""" """Test invalid keychain."""
self.kp.handle(fake_keyevent(Qt.Key_B, text='b')) self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
self.kp.handle(fake_keyevent(Qt.Key_C, text='c')) self.kp.handle(helpers.fake_keyevent(Qt.Key_C, text='c'))
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
@ -233,53 +235,53 @@ class CountTests(unittest.TestCase):
"""Test execute() with counts.""" """Test execute() with counts."""
def setUp(self): def setUp(self):
basekeyparser.config = ConfigStub(CONFIG) basekeyparser.config = stubs.ConfigStub(CONFIG)
basekeyparser.Timer = Mock() basekeyparser.usertypes.Timer = mock.Mock()
self.kp = basekeyparser.BaseKeyParser(supports_chains=True, self.kp = basekeyparser.BaseKeyParser(supports_chains=True,
supports_count=True) supports_count=True)
self.kp.execute = Mock() self.kp.execute = mock.Mock()
self.kp.read_config('test') self.kp.read_config('test')
def test_no_count(self): def test_no_count(self):
"""Test with no count added.""" """Test with no count added."""
self.kp.handle(fake_keyevent(Qt.Key_B, text='b')) self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='a')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None) self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
def test_count_0(self): def test_count_0(self):
"""Test with count=0.""" """Test with count=0."""
self.kp.handle(fake_keyevent(Qt.Key_0, text='0')) self.kp.handle(helpers.fake_keyevent(Qt.Key_0, text='0'))
self.kp.handle(fake_keyevent(Qt.Key_B, text='b')) self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='a')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 0) self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 0)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
def test_count_42(self): def test_count_42(self):
"""Test with count=42.""" """Test with count=42."""
self.kp.handle(fake_keyevent(Qt.Key_4, text='4')) self.kp.handle(helpers.fake_keyevent(Qt.Key_4, text='4'))
self.kp.handle(fake_keyevent(Qt.Key_2, text='2')) self.kp.handle(helpers.fake_keyevent(Qt.Key_2, text='2'))
self.kp.handle(fake_keyevent(Qt.Key_B, text='b')) self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='a')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 42) self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 42)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
def test_count_42_invalid(self): def test_count_42_invalid(self):
"""Test with count=42 and invalid command.""" """Test with count=42 and invalid command."""
# Invalid call with ccx gets ignored # Invalid call with ccx gets ignored
self.kp.handle(fake_keyevent(Qt.Key_4, text='4')) self.kp.handle(helpers.fake_keyevent(Qt.Key_4, text='4'))
self.kp.handle(fake_keyevent(Qt.Key_2, text='2')) self.kp.handle(helpers.fake_keyevent(Qt.Key_2, text='2'))
self.kp.handle(fake_keyevent(Qt.Key_B, text='c')) self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='c'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='c')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='c'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='x')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='x'))
self.assertFalse(self.kp.execute.called) self.assertFalse(self.kp.execute.called)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
# Valid call with ccc gets the correct count # Valid call with ccc gets the correct count
self.kp.handle(fake_keyevent(Qt.Key_4, text='2')) self.kp.handle(helpers.fake_keyevent(Qt.Key_4, text='2'))
self.kp.handle(fake_keyevent(Qt.Key_2, text='3')) self.kp.handle(helpers.fake_keyevent(Qt.Key_2, text='3'))
self.kp.handle(fake_keyevent(Qt.Key_B, text='c')) self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='c'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='c')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='c'))
self.kp.handle(fake_keyevent(Qt.Key_A, text='c')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='c'))
self.kp.execute.assert_called_once_with('ccc', self.kp.Type.chain, 23) self.kp.execute.assert_called_once_with('ccc', self.kp.Type.chain, 23)
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')

View File

@ -21,7 +21,7 @@
"""Fake objects/stubs.""" """Fake objects/stubs."""
from unittest.mock import Mock from unittest import mock
from PyQt5.QtCore import QPoint, QProcess from PyQt5.QtCore import QPoint, QProcess
from PyQt5.QtWebKit import QWebElement from PyQt5.QtWebKit import QWebElement
@ -73,9 +73,9 @@ class FakeKeyEvent:
"""Fake QKeyPressEvent stub.""" """Fake QKeyPressEvent stub."""
def __init__(self, key, modifiers=0, text=''): def __init__(self, key, modifiers=0, text=''):
self.key = Mock(return_value=key) self.key = mock.Mock(return_value=key)
self.text = Mock(return_value=text) self.text = mock.Mock(return_value=text)
self.modifiers = Mock(return_value=modifiers) self.modifiers = mock.Mock(return_value=modifiers)
class FakeWebElement: class FakeWebElement:
@ -99,10 +99,10 @@ class FakeWebElement:
Raise: Raise:
ValueError if element is not null and geometry/frame are not given. ValueError if element is not null and geometry/frame are not given.
""" """
self.geometry = Mock(return_value=geometry) self.geometry = mock.Mock(return_value=geometry)
self.webFrame = Mock(return_value=frame) self.webFrame = mock.Mock(return_value=frame)
self.isNull = Mock(return_value=null) self.isNull = mock.Mock(return_value=null)
self.tagName = Mock(return_value=tagname) self.tagName = mock.Mock(return_value=tagname)
self._visibility = visibility self._visibility = visibility
self._display = display self._display = display
self._attributes = attributes self._attributes = attributes
@ -170,9 +170,9 @@ class FakeWebFrame:
""" """
if scroll is None: if scroll is None:
scroll = QPoint(0, 0) scroll = QPoint(0, 0)
self.geometry = Mock(return_value=geometry) self.geometry = mock.Mock(return_value=geometry)
self.scrollPosition = Mock(return_value=scroll) self.scrollPosition = mock.Mock(return_value=scroll)
self.parentFrame = Mock(return_value=parent) self.parentFrame = mock.Mock(return_value=parent)
class FakeChildrenFrame: class FakeChildrenFrame:
@ -182,7 +182,7 @@ class FakeChildrenFrame:
def __init__(self, children=None): def __init__(self, children=None):
if children is None: if children is None:
children = [] children = []
self.childFrames = Mock(return_value=children) self.childFrames = mock.Mock(return_value=children)
class FakeQApplication: class FakeQApplication:
@ -190,8 +190,8 @@ class FakeQApplication:
"""Stub to insert as QApplication module.""" """Stub to insert as QApplication module."""
def __init__(self, focus): def __init__(self, focus):
self.focusWidget = Mock(return_value=focus) self.focusWidget = mock.Mock(return_value=focus)
self.instance = Mock(return_value=self) self.instance = mock.Mock(return_value=self)
class FakeUrl: class FakeUrl:
@ -199,7 +199,7 @@ class FakeUrl:
"""QUrl stub which provides .path().""" """QUrl stub which provides .path()."""
def __init__(self, path=None): def __init__(self, path=None):
self.path = Mock(return_value=path) self.path = mock.Mock(return_value=path)
class FakeNetworkReply: class FakeNetworkReply:
@ -217,7 +217,7 @@ class FakeNetworkReply:
self.headers = {} self.headers = {}
else: else:
self.headers = headers self.headers = headers
self.url = Mock(return_value=url) self.url = mock.Mock(return_value=url)
def hasRawHeader(self, name): def hasRawHeader(self, name):
"""Check if the reply has a certain header. """Check if the reply has a certain header.
@ -282,9 +282,9 @@ class FakeQProcess:
UnknownError = QProcess.UnknownError UnknownError = QProcess.UnknownError
def __init__(self, parent=None): # pylint: disable=unused-argument def __init__(self, parent=None): # pylint: disable=unused-argument
self.finished = Mock() self.finished = mock.Mock()
self.error = Mock() self.error = mock.Mock()
self.start = Mock() self.start = mock.Mock()
class FakeSignal: class FakeSignal:

View File

@ -23,7 +23,7 @@
import os import os
import unittest import unittest
from qutebrowser.test.helpers import environ_set_temp from qutebrowser.test import helpers
class TestEnvironSetTemp(unittest.TestCase): class TestEnvironSetTemp(unittest.TestCase):
@ -33,13 +33,13 @@ class TestEnvironSetTemp(unittest.TestCase):
def test_environ_set(self): def test_environ_set(self):
"""Test environ_set_temp with something which was set already.""" """Test environ_set_temp with something which was set already."""
os.environ['QUTEBROWSER_ENVIRON_TEST'] = 'oldval' os.environ['QUTEBROWSER_ENVIRON_TEST'] = 'oldval'
with environ_set_temp('QUTEBROWSER_ENVIRON_TEST', 'newval'): with helpers.environ_set_temp('QUTEBROWSER_ENVIRON_TEST', 'newval'):
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'newval') self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'newval')
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'oldval') self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'oldval')
def test_environ_unset(self): def test_environ_unset(self):
"""Test environ_set_temp with something which wasn't set yet.""" """Test environ_set_temp with something which wasn't set yet."""
with environ_set_temp('QUTEBROWSER_ENVIRON_TEST', 'newval'): with helpers.environ_set_temp('QUTEBROWSER_ENVIRON_TEST', 'newval'):
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'newval') self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'newval')
self.assertNotIn('QUTEBROWSER_ENVIRON_TEST', os.environ) self.assertNotIn('QUTEBROWSER_ENVIRON_TEST', os.environ)

View File

@ -23,8 +23,8 @@ import os
import unittest import unittest
import logging import logging
import qutebrowser.utils.http as httputils from qutebrowser.utils import http
from qutebrowser.test.stubs import FakeNetworkReply from qutebrowser.test import stubs
DEFAULT_NAME = 'qutebrowser-download' DEFAULT_NAME = 'qutebrowser-download'
@ -39,23 +39,23 @@ class AttachmentTestCase(unittest.TestCase):
def _check_filename(self, header, filename): def _check_filename(self, header, filename):
"""Check if the passed header has the given filename.""" """Check if the passed header has the given filename."""
reply = FakeNetworkReply(headers={'Content-Disposition': header}) reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
cd_inline, cd_filename = httputils.parse_content_disposition(reply) cd_inline, cd_filename = http.parse_content_disposition(reply)
self.assertIsNotNone(cd_filename) self.assertIsNotNone(cd_filename)
self.assertEqual(cd_filename, filename) self.assertEqual(cd_filename, filename)
self.assertFalse(cd_inline) self.assertFalse(cd_inline)
def _check_ignored(self, header): def _check_ignored(self, header):
"""Check if the passed header is ignored.""" """Check if the passed header is ignored."""
reply = FakeNetworkReply(headers={'Content-Disposition': header}) reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
cd_inline, cd_filename = httputils.parse_content_disposition(reply) cd_inline, cd_filename = http.parse_content_disposition(reply)
self.assertEqual(cd_filename, DEFAULT_NAME) self.assertEqual(cd_filename, DEFAULT_NAME)
self.assertTrue(cd_inline) self.assertTrue(cd_inline)
def _check_unnamed(self, header): def _check_unnamed(self, header):
"""Check if the passed header results in an unnamed attachment.""" """Check if the passed header results in an unnamed attachment."""
reply = FakeNetworkReply(headers={'Content-Disposition': header}) reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
cd_inline, cd_filename = httputils.parse_content_disposition(reply) cd_inline, cd_filename = http.parse_content_disposition(reply)
self.assertEqual(cd_filename, DEFAULT_NAME) self.assertEqual(cd_filename, DEFAULT_NAME)
self.assertFalse(cd_inline) self.assertFalse(cd_inline)
@ -69,15 +69,15 @@ class InlineTests(unittest.TestCase):
def _check_filename(self, header, filename): def _check_filename(self, header, filename):
"""Check if the passed header has the given filename.""" """Check if the passed header has the given filename."""
reply = FakeNetworkReply(headers={'Content-Disposition': header}) reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
cd_inline, cd_filename = httputils.parse_content_disposition(reply) cd_inline, cd_filename = http.parse_content_disposition(reply)
self.assertEqual(cd_filename, filename) self.assertEqual(cd_filename, filename)
self.assertTrue(cd_inline) self.assertTrue(cd_inline)
def _check_ignored(self, header): def _check_ignored(self, header):
"""Check if the passed header is ignored.""" """Check if the passed header is ignored."""
reply = FakeNetworkReply(headers={'Content-Disposition': header}) reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
cd_inline, cd_filename = httputils.parse_content_disposition(reply) cd_inline, cd_filename = http.parse_content_disposition(reply)
self.assertEqual(cd_filename, DEFAULT_NAME) self.assertEqual(cd_filename, DEFAULT_NAME)
self.assertTrue(cd_inline) self.assertTrue(cd_inline)
@ -134,8 +134,9 @@ class AttachmentTests(AttachmentTestCase):
UA should offer to download the resource. UA should offer to download the resource.
""" """
reply = FakeNetworkReply(headers={'Content-Disposition': 'attachment'}) reply = stubs.FakeNetworkReply(
cd_inline, cd_filename = httputils.parse_content_disposition(reply) headers={'Content-Disposition': 'attachment'})
cd_inline, cd_filename = http.parse_content_disposition(reply)
self.assertFalse(cd_inline) self.assertFalse(cd_inline)
self.assertEqual(cd_filename, DEFAULT_NAME) self.assertEqual(cd_filename, DEFAULT_NAME)

View File

@ -25,8 +25,8 @@ test_content_disposition.py file.
import unittest import unittest
import qutebrowser.utils.http as httputils from qutebrowser.utils import http
from qutebrowser.test.stubs import FakeNetworkReply from qutebrowser.test import stubs
class ParseContentTypeTests(unittest.TestCase): class ParseContentTypeTests(unittest.TestCase):
@ -35,30 +35,31 @@ class ParseContentTypeTests(unittest.TestCase):
def test_not_existing(self): def test_not_existing(self):
"""Test without any Content-Type header.""" """Test without any Content-Type header."""
reply = FakeNetworkReply() reply = stubs.FakeNetworkReply()
mimetype, rest = httputils.parse_content_type(reply) mimetype, rest = http.parse_content_type(reply)
self.assertIsNone(mimetype) self.assertIsNone(mimetype)
self.assertIsNone(rest) self.assertIsNone(rest)
def test_mimetype(self): def test_mimetype(self):
"""Test with simple Content-Type header.""" """Test with simple Content-Type header."""
reply = FakeNetworkReply(headers={'Content-Type': 'image/example'}) reply = stubs.FakeNetworkReply(
mimetype, rest = httputils.parse_content_type(reply) headers={'Content-Type': 'image/example'})
mimetype, rest = http.parse_content_type(reply)
self.assertEqual(mimetype, 'image/example') self.assertEqual(mimetype, 'image/example')
self.assertIsNone(rest) self.assertIsNone(rest)
def test_empty(self): def test_empty(self):
"""Test with empty Content-Type header.""" """Test with empty Content-Type header."""
reply = FakeNetworkReply(headers={'Content-Type': ''}) reply = stubs.FakeNetworkReply(headers={'Content-Type': ''})
mimetype, rest = httputils.parse_content_type(reply) mimetype, rest = http.parse_content_type(reply)
self.assertEqual(mimetype, '') self.assertEqual(mimetype, '')
self.assertIsNone(rest) self.assertIsNone(rest)
def test_additional(self): def test_additional(self):
"""Test with Content-Type header with additional informations.""" """Test with Content-Type header with additional informations."""
reply = FakeNetworkReply( reply = stubs.FakeNetworkReply(
headers={'Content-Type': 'image/example; encoding=UTF-8'}) headers={'Content-Type': 'image/example; encoding=UTF-8'})
mimetype, rest = httputils.parse_content_type(reply) mimetype, rest = http.parse_content_type(reply)
self.assertEqual(mimetype, 'image/example') self.assertEqual(mimetype, 'image/example')
self.assertEqual(rest, ' encoding=UTF-8') self.assertEqual(rest, ' encoding=UTF-8')

View File

@ -24,8 +24,8 @@ import unittest
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QStyle, QFrame from PyQt5.QtWidgets import QStyle, QFrame
import qutebrowser.utils.debug as debug from qutebrowser.utils import debug
from qutebrowser.test.stubs import FakeSignal from qutebrowser.test import stubs
class QEnumKeyTests(unittest.TestCase): class QEnumKeyTests(unittest.TestCase):
@ -123,7 +123,7 @@ class TestDebug(unittest.TestCase):
"""Test signal debug output functions.""" """Test signal debug output functions."""
def setUp(self): def setUp(self):
self.signal = FakeSignal() self.signal = stubs.FakeSignal()
def test_signal_name(self): def test_signal_name(self):
"""Test signal_name().""" """Test signal_name()."""

View File

@ -23,19 +23,19 @@ import os
import os.path import os.path
import unittest import unittest
import logging import logging
from unittest.mock import Mock from unittest import mock
from PyQt5.QtCore import QProcess from PyQt5.QtCore import QProcess
import qutebrowser.utils.editor as editorutils from qutebrowser.utils import editor
from qutebrowser.test.stubs import ConfigStub, FakeQProcess from qutebrowser.test import stubs
def setUpModule(): def setUpModule():
"""Disable logging and mock out some imports.""" """Disable logging and mock out some imports."""
logging.disable(logging.INFO) logging.disable(logging.INFO)
editorutils.message = Mock() editor.message = mock.Mock()
editorutils.QProcess = FakeQProcess editor.QProcess = stubs.FakeQProcess
def tearDownModule(): def tearDownModule():
@ -52,18 +52,18 @@ class ArgTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.editor = editorutils.ExternalEditor() self.editor = editor.ExternalEditor()
def test_simple_start_args(self): def test_simple_start_args(self):
"""Test starting editor without arguments.""" """Test starting editor without arguments."""
editorutils.config = ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}}) {'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}})
self.editor.edit("") self.editor.edit("")
self.editor.proc.start.assert_called_with("bin", []) self.editor.proc.start.assert_called_with("bin", [])
def test_start_args(self): def test_start_args(self):
"""Test starting editor with static arguments.""" """Test starting editor with static arguments."""
editorutils.config = ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin', 'foo', 'bar'], {'general': {'editor': ['bin', 'foo', 'bar'],
'editor-encoding': 'utf-8'}}) 'editor-encoding': 'utf-8'}})
self.editor.edit("") self.editor.edit("")
@ -71,7 +71,7 @@ class ArgTests(unittest.TestCase):
def test_placeholder(self): def test_placeholder(self):
"""Test starting editor with placeholder argument.""" """Test starting editor with placeholder argument."""
editorutils.config = ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin', 'foo', '{}', 'bar'], {'general': {'editor': ['bin', 'foo', '{}', 'bar'],
'editor-encoding': 'utf-8'}}) 'editor-encoding': 'utf-8'}})
self.editor.edit("") self.editor.edit("")
@ -81,7 +81,7 @@ class ArgTests(unittest.TestCase):
def test_in_arg_placeholder(self): def test_in_arg_placeholder(self):
"""Test starting editor with placeholder argument inside argument.""" """Test starting editor with placeholder argument inside argument."""
editorutils.config = ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin', 'foo{}bar'], {'general': {'editor': ['bin', 'foo{}bar'],
'editor-encoding': 'utf-8'}}) 'editor-encoding': 'utf-8'}})
self.editor.edit("") self.editor.edit("")
@ -100,8 +100,8 @@ class FileHandlingTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.editor = editorutils.ExternalEditor() self.editor = editor.ExternalEditor()
editorutils.config = ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}) {'general': {'editor': [''], 'editor-encoding': 'utf-8'}})
def test_file_handling_closed_ok(self): def test_file_handling_closed_ok(self):
@ -139,9 +139,9 @@ class TextModifyTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.editor = editorutils.ExternalEditor() self.editor = editor.ExternalEditor()
self.editor.editing_finished = Mock() self.editor.editing_finished = mock.Mock()
editorutils.config = ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}) {'general': {'editor': [''], 'editor-encoding': 'utf-8'}})
def _write(self, text): def _write(self, text):
@ -209,21 +209,21 @@ class ErrorMessageTests(unittest.TestCase):
# pylint: disable=maybe-no-member # pylint: disable=maybe-no-member
def setUp(self): def setUp(self):
self.editor = editorutils.ExternalEditor() self.editor = editor.ExternalEditor()
editorutils.config = ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}) {'general': {'editor': [''], 'editor-encoding': 'utf-8'}})
def test_proc_error(self): def test_proc_error(self):
"""Test on_proc_error.""" """Test on_proc_error."""
self.editor.edit("") self.editor.edit("")
self.editor.on_proc_error(QProcess.Crashed) self.editor.on_proc_error(QProcess.Crashed)
self.assertTrue(editorutils.message.error.called) self.assertTrue(editor.message.error.called)
def test_proc_return(self): def test_proc_return(self):
"""Test on_proc_finished with a bad exit status.""" """Test on_proc_finished with a bad exit status."""
self.editor.edit("") self.editor.edit("")
self.editor.on_proc_closed(1, QProcess.NormalExit) self.editor.on_proc_closed(1, QProcess.NormalExit)
self.assertTrue(editorutils.message.error.called) self.assertTrue(editor.message.error.called)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -26,7 +26,7 @@ import unittest
import argparse import argparse
import sys import sys
import qutebrowser.utils.log as log from qutebrowser.utils import log
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):

View File

@ -24,14 +24,14 @@ import sys
import shutil import shutil
import unittest import unittest
import os.path import os.path
from tempfile import mkdtemp import tempfile
from PyQt5.QtCore import QStandardPaths, QCoreApplication, Qt from PyQt5.QtCore import QStandardPaths, QCoreApplication, Qt
from PyQt5.QtGui import QColor from PyQt5.QtGui import QColor
import qutebrowser.utils.misc as utils from qutebrowser.utils import misc as utils
from qutebrowser.test.helpers import environ_set_temp, fake_keyevent from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.qt import QtValueError from qutebrowser.test import helpers
class Color(QColor): class Color(QColor):
@ -157,14 +157,14 @@ class GetStandardDirLinuxTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.temp_dir = mkdtemp() self.temp_dir = tempfile.mkdtemp()
self.app = QCoreApplication([]) self.app = QCoreApplication([])
self.app.setApplicationName('qutebrowser') self.app.setApplicationName('qutebrowser')
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_data_explicit(self): def test_data_explicit(self):
"""Test data dir with XDG_DATA_HOME explicitely set.""" """Test data dir with XDG_DATA_HOME explicitely set."""
with environ_set_temp('XDG_DATA_HOME', self.temp_dir): with helpers.environ_set_temp('XDG_DATA_HOME', self.temp_dir):
cur_dir = utils.get_standard_dir(QStandardPaths.DataLocation) cur_dir = utils.get_standard_dir(QStandardPaths.DataLocation)
self.assertEqual(cur_dir, os.path.join(self.temp_dir, self.assertEqual(cur_dir, os.path.join(self.temp_dir,
'qutebrowser')) 'qutebrowser'))
@ -173,7 +173,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_config_explicit(self): def test_config_explicit(self):
"""Test config dir with XDG_CONFIG_HOME explicitely set.""" """Test config dir with XDG_CONFIG_HOME explicitely set."""
with environ_set_temp('XDG_CONFIG_HOME', self.temp_dir): with helpers.environ_set_temp('XDG_CONFIG_HOME', self.temp_dir):
cur_dir = utils.get_standard_dir(QStandardPaths.ConfigLocation) cur_dir = utils.get_standard_dir(QStandardPaths.ConfigLocation)
self.assertEqual(cur_dir, os.path.join(self.temp_dir, self.assertEqual(cur_dir, os.path.join(self.temp_dir,
'qutebrowser')) 'qutebrowser'))
@ -182,7 +182,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_cache_explicit(self): def test_cache_explicit(self):
"""Test cache dir with XDG_CACHE_HOME explicitely set.""" """Test cache dir with XDG_CACHE_HOME explicitely set."""
with environ_set_temp('XDG_CACHE_HOME', self.temp_dir): with helpers.environ_set_temp('XDG_CACHE_HOME', self.temp_dir):
cur_dir = utils.get_standard_dir(QStandardPaths.CacheLocation) cur_dir = utils.get_standard_dir(QStandardPaths.CacheLocation)
self.assertEqual(cur_dir, os.path.join(self.temp_dir, self.assertEqual(cur_dir, os.path.join(self.temp_dir,
'qutebrowser')) 'qutebrowser'))
@ -191,7 +191,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_data(self): def test_data(self):
"""Test data dir with XDG_DATA_HOME not set.""" """Test data dir with XDG_DATA_HOME not set."""
with environ_set_temp('HOME', self.temp_dir): with helpers.environ_set_temp('HOME', self.temp_dir):
cur_dir = utils.get_standard_dir(QStandardPaths.DataLocation) cur_dir = utils.get_standard_dir(QStandardPaths.DataLocation)
self.assertEqual(cur_dir, os.path.join(self.temp_dir, '.local', self.assertEqual(cur_dir, os.path.join(self.temp_dir, '.local',
'share', 'qutebrowser')) 'share', 'qutebrowser'))
@ -200,7 +200,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_config(self): def test_config(self):
"""Test config dir with XDG_CONFIG_HOME not set.""" """Test config dir with XDG_CONFIG_HOME not set."""
with environ_set_temp('HOME', self.temp_dir): with helpers.environ_set_temp('HOME', self.temp_dir):
cur_dir = utils.get_standard_dir( cur_dir = utils.get_standard_dir(
QStandardPaths.ConfigLocation) QStandardPaths.ConfigLocation)
self.assertEqual(cur_dir, os.path.join(self.temp_dir, '.config', self.assertEqual(cur_dir, os.path.join(self.temp_dir, '.config',
@ -210,7 +210,7 @@ class GetStandardDirLinuxTests(unittest.TestCase):
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_cache(self): def test_cache(self):
"""Test cache dir with XDG_CACHE_HOME not set.""" """Test cache dir with XDG_CACHE_HOME not set."""
with environ_set_temp('HOME', self.temp_dir): with helpers.environ_set_temp('HOME', self.temp_dir):
cur_dir = utils.get_standard_dir(QStandardPaths.CacheLocation) cur_dir = utils.get_standard_dir(QStandardPaths.CacheLocation)
self.assertEqual(cur_dir, os.path.join(self.temp_dir, '.cache', self.assertEqual(cur_dir, os.path.join(self.temp_dir, '.cache',
'qutebrowser')) 'qutebrowser'))
@ -286,12 +286,12 @@ class InterpolateColorTests(unittest.TestCase):
def test_invalid_start(self): def test_invalid_start(self):
"""Test an invalid start color.""" """Test an invalid start color."""
with self.assertRaises(QtValueError): with self.assertRaises(qtutils.QtValueError):
utils.interpolate_color(Color(), self.white, 0) utils.interpolate_color(Color(), self.white, 0)
def test_invalid_end(self): def test_invalid_end(self):
"""Test an invalid end color.""" """Test an invalid end color."""
with self.assertRaises(QtValueError): with self.assertRaises(qtutils.QtValueError):
utils.interpolate_color(self.white, Color(), 0) utils.interpolate_color(self.white, Color(), 0)
def test_invalid_percentage(self): def test_invalid_percentage(self):
@ -464,29 +464,31 @@ class KeyEventToStringTests(unittest.TestCase):
def test_only_control(self): def test_only_control(self):
"""Test keyeevent when only control is pressed.""" """Test keyeevent when only control is pressed."""
evt = fake_keyevent(key=Qt.Key_Control, modifiers=Qt.ControlModifier) evt = helpers.fake_keyevent(key=Qt.Key_Control,
modifiers=Qt.ControlModifier)
self.assertIsNone(utils.keyevent_to_string(evt)) self.assertIsNone(utils.keyevent_to_string(evt))
def test_only_hyper_l(self): def test_only_hyper_l(self):
"""Test keyeevent when only Hyper_L is pressed.""" """Test keyeevent when only Hyper_L is pressed."""
evt = fake_keyevent(key=Qt.Key_Hyper_L, modifiers=Qt.MetaModifier) evt = helpers.fake_keyevent(key=Qt.Key_Hyper_L,
modifiers=Qt.MetaModifier)
self.assertIsNone(utils.keyevent_to_string(evt)) self.assertIsNone(utils.keyevent_to_string(evt))
def test_only_key(self): def test_only_key(self):
"""Test with a simple key pressed.""" """Test with a simple key pressed."""
evt = fake_keyevent(key=Qt.Key_A) evt = helpers.fake_keyevent(key=Qt.Key_A)
self.assertEqual(utils.keyevent_to_string(evt), 'A') self.assertEqual(utils.keyevent_to_string(evt), 'A')
def test_key_and_modifier(self): def test_key_and_modifier(self):
"""Test with key and modifier pressed.""" """Test with key and modifier pressed."""
evt = fake_keyevent(key=Qt.Key_A, modifiers=Qt.ControlModifier) evt = helpers.fake_keyevent(key=Qt.Key_A, modifiers=Qt.ControlModifier)
self.assertEqual(utils.keyevent_to_string(evt), 'Ctrl+A') self.assertEqual(utils.keyevent_to_string(evt), 'Ctrl+A')
def test_key_and_modifiers(self): def test_key_and_modifiers(self):
"""Test with key and multiple modifier pressed.""" """Test with key and multiple modifier pressed."""
evt = fake_keyevent(key=Qt.Key_A, evt = helpers.fake_keyevent(
modifiers=(Qt.ControlModifier | Qt.AltModifier | key=Qt.Key_A, modifiers=(Qt.ControlModifier | Qt.AltModifier |
Qt.MetaModifier | Qt.ShiftModifier)) Qt.MetaModifier | Qt.ShiftModifier))
self.assertEqual(utils.keyevent_to_string(evt), self.assertEqual(utils.keyevent_to_string(evt),
'Ctrl+Alt+Meta+Shift+A') 'Ctrl+Alt+Meta+Shift+A')

View File

@ -23,7 +23,7 @@ import sys
import argparse import argparse
import unittest import unittest
import qutebrowser.utils.qt as qt from qutebrowser.utils import qt
class CheckOverflowTests(unittest.TestCase): class CheckOverflowTests(unittest.TestCase):

View File

@ -21,12 +21,12 @@
import inspect import inspect
import unittest import unittest
from unittest.mock import Mock from unittest import mock
from PyQt5.QtWidgets import QLineEdit from PyQt5.QtWidgets import QLineEdit
import qutebrowser.utils.readline as readline from qutebrowser.utils import readline
from qutebrowser.test.stubs import FakeQApplication from qutebrowser.test import stubs
class NoneWidgetTests(unittest.TestCase): class NoneWidgetTests(unittest.TestCase):
@ -34,7 +34,7 @@ class NoneWidgetTests(unittest.TestCase):
"""Tests when the focused widget is None.""" """Tests when the focused widget is None."""
def setUp(self): def setUp(self):
readline.QApplication = FakeQApplication(None) readline.QApplication = stubs.FakeQApplication(None)
self.bridge = readline.ReadlineBridge() self.bridge = readline.ReadlineBridge()
def test_none(self): def test_none(self):
@ -50,9 +50,9 @@ class ReadlineBridgeTest(unittest.TestCase):
"""Tests for readline bridge.""" """Tests for readline bridge."""
def setUp(self): def setUp(self):
self.qle = Mock() self.qle = mock.Mock()
self.qle.__class__ = QLineEdit self.qle.__class__ = QLineEdit
readline.QApplication = FakeQApplication(self.qle) readline.QApplication = stubs.FakeQApplication(self.qle)
self.bridge = readline.ReadlineBridge() self.bridge = readline.ReadlineBridge()
def _set_selected_text(self, text): def _set_selected_text(self, text):

View File

@ -25,8 +25,8 @@ import unittest
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
import qutebrowser.utils.url as urlutils from qutebrowser.utils import url as urlutils
from qutebrowser.test.stubs import ConfigStub from qutebrowser.test import stubs
CONFIG = { CONFIG = {
@ -83,7 +83,7 @@ class SearchUrlTests(unittest.TestCase):
def setUp(self): def setUp(self):
self.config = urlutils.config self.config = urlutils.config
urlutils.config = ConfigStub(CONFIG) urlutils.config = stubs.ConfigStub(CONFIG)
def test_default_engine(self): def test_default_engine(self):
"""Test default search engine.""" """Test default search engine."""

View File

@ -23,9 +23,8 @@ import unittest
from PyQt5.QtCore import QRect, QPoint from PyQt5.QtCore import QRect, QPoint
import qutebrowser.utils.webelem as webelem from qutebrowser.utils import webelem
from qutebrowser.test.stubs import (FakeWebElement, FakeWebFrame, from qutebrowser.test import stubs
FakeChildrenFrame, ConfigStub)
class IsVisibleInvalidTests(unittest.TestCase): class IsVisibleInvalidTests(unittest.TestCase):
@ -37,7 +36,7 @@ class IsVisibleInvalidTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.frame = FakeWebFrame(QRect(0, 0, 100, 100)) self.frame = stubs.FakeWebFrame(QRect(0, 0, 100, 100))
def test_nullelem(self): def test_nullelem(self):
"""Passing an element with isNull() == True. """Passing an element with isNull() == True.
@ -45,7 +44,7 @@ class IsVisibleInvalidTests(unittest.TestCase):
geometry() and webFrame() should not be called, and ValueError should geometry() and webFrame() should not be called, and ValueError should
be raised. be raised.
""" """
elem = FakeWebElement(null=True) elem = stubs.FakeWebElement(null=True)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
webelem.is_visible(elem, self.frame) webelem.is_visible(elem, self.frame)
elem.isNull.assert_called_once_with() elem.isNull.assert_called_once_with()
@ -54,7 +53,7 @@ class IsVisibleInvalidTests(unittest.TestCase):
def test_invalid_invisible(self): def test_invalid_invisible(self):
"""Test elements with an invalid geometry which are invisible.""" """Test elements with an invalid geometry which are invisible."""
elem = FakeWebElement(QRect(0, 0, 0, 0), self.frame) elem = stubs.FakeWebElement(QRect(0, 0, 0, 0), self.frame)
self.assertFalse(elem.geometry().isValid()) self.assertFalse(elem.geometry().isValid())
self.assertEqual(elem.geometry().x(), 0) self.assertEqual(elem.geometry().x(), 0)
self.assertFalse(webelem.is_visible(elem, self.frame)) self.assertFalse(webelem.is_visible(elem, self.frame))
@ -65,7 +64,7 @@ class IsVisibleInvalidTests(unittest.TestCase):
This seems to happen sometimes in the real world, with real elements This seems to happen sometimes in the real world, with real elements
which *are* visible, but don't have a valid geometry. which *are* visible, but don't have a valid geometry.
""" """
elem = FakeWebElement(QRect(10, 10, 0, 0), self.frame) elem = stubs.FakeWebElement(QRect(10, 10, 0, 0), self.frame)
self.assertFalse(elem.geometry().isValid()) self.assertFalse(elem.geometry().isValid())
self.assertTrue(webelem.is_visible(elem, self.frame)) self.assertTrue(webelem.is_visible(elem, self.frame))
@ -79,16 +78,17 @@ class IsVisibleScrollTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.frame = FakeWebFrame(QRect(0, 0, 100, 100), scroll=QPoint(10, 10)) self.frame = stubs.FakeWebFrame(QRect(0, 0, 100, 100),
scroll=QPoint(10, 10))
def test_invisible(self): def test_invisible(self):
"""Test elements which should be invisible due to scrolling.""" """Test elements which should be invisible due to scrolling."""
elem = FakeWebElement(QRect(5, 5, 4, 4), self.frame) elem = stubs.FakeWebElement(QRect(5, 5, 4, 4), self.frame)
self.assertFalse(webelem.is_visible(elem, self.frame)) self.assertFalse(webelem.is_visible(elem, self.frame))
def test_visible(self): def test_visible(self):
"""Test elements which still should be visible after scrolling.""" """Test elements which still should be visible after scrolling."""
elem = FakeWebElement(QRect(10, 10, 1, 1), self.frame) elem = stubs.FakeWebElement(QRect(10, 10, 1, 1), self.frame)
self.assertTrue(webelem.is_visible(elem, self.frame)) self.assertTrue(webelem.is_visible(elem, self.frame))
@ -101,29 +101,30 @@ class IsVisibleCssTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.frame = FakeWebFrame(QRect(0, 0, 100, 100)) self.frame = stubs.FakeWebFrame(QRect(0, 0, 100, 100))
def test_visibility_visible(self): def test_visibility_visible(self):
"""Check that elements with "visibility = visible" are visible.""" """Check that elements with "visibility = visible" are visible."""
elem = FakeWebElement(QRect(0, 0, 10, 10), self.frame, elem = stubs.FakeWebElement(QRect(0, 0, 10, 10), self.frame,
visibility='visible') visibility='visible')
self.assertTrue(webelem.is_visible(elem, self.frame)) self.assertTrue(webelem.is_visible(elem, self.frame))
def test_visibility_hidden(self): def test_visibility_hidden(self):
"""Check that elements with "visibility = hidden" are not visible.""" """Check that elements with "visibility = hidden" are not visible."""
elem = FakeWebElement(QRect(0, 0, 10, 10), self.frame, elem = stubs.FakeWebElement(QRect(0, 0, 10, 10), self.frame,
visibility='hidden') visibility='hidden')
self.assertFalse(webelem.is_visible(elem, self.frame)) self.assertFalse(webelem.is_visible(elem, self.frame))
def test_display_inline(self): def test_display_inline(self):
"""Check that elements with "display = inline" are visible.""" """Check that elements with "display = inline" are visible."""
elem = FakeWebElement(QRect(0, 0, 10, 10), self.frame, elem = stubs.FakeWebElement(QRect(0, 0, 10, 10), self.frame,
display='inline') display='inline')
self.assertTrue(webelem.is_visible(elem, self.frame)) self.assertTrue(webelem.is_visible(elem, self.frame))
def test_display_none(self): def test_display_none(self):
"""Check that elements with "display = none" are not visible.""" """Check that elements with "display = none" are not visible."""
elem = FakeWebElement(QRect(0, 0, 10, 10), self.frame, display='none') elem = stubs.FakeWebElement(QRect(0, 0, 10, 10), self.frame,
display='none')
self.assertFalse(webelem.is_visible(elem, self.frame)) self.assertFalse(webelem.is_visible(elem, self.frame))
@ -158,12 +159,13 @@ class IsVisibleIframeTests(unittest.TestCase):
############################## ##############################
300, 0 300, 300 300, 0 300, 300
""" """
self.frame = FakeWebFrame(QRect(0, 0, 300, 300)) self.frame = stubs.FakeWebFrame(QRect(0, 0, 300, 300))
self.iframe = FakeWebFrame(QRect(0, 10, 100, 100), parent=self.frame) self.iframe = stubs.FakeWebFrame(QRect(0, 10, 100, 100),
self.elem1 = FakeWebElement(QRect(0, 0, 10, 10), self.iframe) parent=self.frame)
self.elem2 = FakeWebElement(QRect(20, 90, 10, 10), self.iframe) self.elem1 = stubs.FakeWebElement(QRect(0, 0, 10, 10), self.iframe)
self.elem3 = FakeWebElement(QRect(20, 150, 10, 10), self.iframe) self.elem2 = stubs.FakeWebElement(QRect(20, 90, 10, 10), self.iframe)
self.elem4 = FakeWebElement(QRect(30, 180, 10, 10), self.frame) self.elem3 = stubs.FakeWebElement(QRect(20, 150, 10, 10), self.iframe)
self.elem4 = stubs.FakeWebElement(QRect(30, 180, 10, 10), self.frame)
def test_not_scrolled(self): def test_not_scrolled(self):
"""Test base situation.""" """Test base situation."""
@ -210,17 +212,17 @@ class IsWritableTests(unittest.TestCase):
def test_writable(self): def test_writable(self):
"""Test a normal element.""" """Test a normal element."""
elem = FakeWebElement() elem = stubs.FakeWebElement()
self.assertTrue(webelem.is_writable(elem)) self.assertTrue(webelem.is_writable(elem))
def test_disabled(self): def test_disabled(self):
"""Test a disabled element.""" """Test a disabled element."""
elem = FakeWebElement(attributes=['disabled']) elem = stubs.FakeWebElement(attributes=['disabled'])
self.assertFalse(webelem.is_writable(elem)) self.assertFalse(webelem.is_writable(elem))
def test_readonly(self): def test_readonly(self):
"""Test a readonly element.""" """Test a readonly element."""
elem = FakeWebElement(attributes=['readonly']) elem = stubs.FakeWebElement(attributes=['readonly'])
self.assertFalse(webelem.is_writable(elem)) self.assertFalse(webelem.is_writable(elem))
@ -252,7 +254,7 @@ class GetChildFramesTests(unittest.TestCase):
def test_single_frame(self): def test_single_frame(self):
"""Test get_child_frames with a single frame without children.""" """Test get_child_frames with a single frame without children."""
frame = FakeChildrenFrame() frame = stubs.FakeChildrenFrame()
children = webelem.get_child_frames(frame) children = webelem.get_child_frames(frame)
self.assertEqual(len(children), 1) self.assertEqual(len(children), 1)
self.assertIs(children[0], frame) self.assertIs(children[0], frame)
@ -265,9 +267,9 @@ class GetChildFramesTests(unittest.TestCase):
/ \ / \
child1 o o child2 child1 o o child2
""" """
child1 = FakeChildrenFrame() child1 = stubs.FakeChildrenFrame()
child2 = FakeChildrenFrame() child2 = stubs.FakeChildrenFrame()
parent = FakeChildrenFrame([child1, child2]) parent = stubs.FakeChildrenFrame([child1, child2])
children = webelem.get_child_frames(parent) children = webelem.get_child_frames(parent)
self.assertEqual(len(children), 3) self.assertEqual(len(children), 3)
self.assertIs(children[0], parent) self.assertIs(children[0], parent)
@ -286,10 +288,10 @@ class GetChildFramesTests(unittest.TestCase):
/\ /\ /\ /\
o o o o second o o o o second
""" """
second = [FakeChildrenFrame() for _ in range(4)] second = [stubs.FakeChildrenFrame() for _ in range(4)]
first = [FakeChildrenFrame(second[0:2]), first = [stubs.FakeChildrenFrame(second[0:2]),
FakeChildrenFrame(second[2:4])] stubs.FakeChildrenFrame(second[2:4])]
root = FakeChildrenFrame(first) root = stubs.FakeChildrenFrame(first)
children = webelem.get_child_frames(root) children = webelem.get_child_frames(root)
self.assertEqual(len(children), 7) self.assertEqual(len(children), 7)
self.assertIs(children[0], root) self.assertIs(children[0], root)
@ -307,175 +309,189 @@ class IsEditableTests(unittest.TestCase):
def test_input_plain(self): def test_input_plain(self):
"""Test with plain input element.""" """Test with plain input element."""
elem = FakeWebElement(tagname='input') elem = stubs.FakeWebElement(tagname='input')
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_text(self): def test_input_text(self):
"""Test with text input element.""" """Test with text input element."""
elem = FakeWebElement(tagname='input', attributes={'type': 'text'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'text'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_text_caps(self): def test_input_text_caps(self):
"""Test with text input element with caps attributes.""" """Test with text input element with caps attributes."""
elem = FakeWebElement(tagname='INPUT', attributes={'TYPE': 'TEXT'}) elem = stubs.FakeWebElement(tagname='INPUT',
attributes={'TYPE': 'TEXT'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_email(self): def test_input_email(self):
"""Test with email input element.""" """Test with email input element."""
elem = FakeWebElement(tagname='input', attributes={'type': 'email'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'email'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_url(self): def test_input_url(self):
"""Test with url input element.""" """Test with url input element."""
elem = FakeWebElement(tagname='input', attributes={'type': 'url'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'url'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_tel(self): def test_input_tel(self):
"""Test with tel input element.""" """Test with tel input element."""
elem = FakeWebElement(tagname='input', attributes={'type': 'tel'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'tel'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_number(self): def test_input_number(self):
"""Test with number input element.""" """Test with number input element."""
elem = FakeWebElement(tagname='input', attributes={'type': 'number'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'number'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_password(self): def test_input_password(self):
"""Test with password input element.""" """Test with password input element."""
elem = FakeWebElement(tagname='input', attributes={'type': 'password'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'password'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_search(self): def test_input_search(self):
"""Test with search input element.""" """Test with search input element."""
elem = FakeWebElement(tagname='input', attributes={'type': 'search'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'search'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_input_button(self): def test_input_button(self):
"""Button should not be editable.""" """Button should not be editable."""
elem = FakeWebElement(tagname='input', attributes={'type': 'button'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'button'})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_input_checkbox(self): def test_input_checkbox(self):
"""Checkbox should not be editable.""" """Checkbox should not be editable."""
elem = FakeWebElement(tagname='input', attributes={'type': 'checkbox'}) elem = stubs.FakeWebElement(tagname='input',
attributes={'type': 'checkbox'})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_textarea(self): def test_textarea(self):
"""Test textarea element.""" """Test textarea element."""
elem = FakeWebElement(tagname='textarea') elem = stubs.FakeWebElement(tagname='textarea')
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_select(self): def test_select(self):
"""Test selectbox.""" """Test selectbox."""
elem = FakeWebElement(tagname='select') elem = stubs.FakeWebElement(tagname='select')
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_input_disabled(self): def test_input_disabled(self):
"""Test disabled input element.""" """Test disabled input element."""
elem = FakeWebElement(tagname='input', attributes={'disabled': None}) elem = stubs.FakeWebElement(tagname='input',
attributes={'disabled': None})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_input_readonly(self): def test_input_readonly(self):
"""Test readonly input element.""" """Test readonly input element."""
elem = FakeWebElement(tagname='input', attributes={'readonly': None}) elem = stubs.FakeWebElement(tagname='input',
attributes={'readonly': None})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_textarea_disabled(self): def test_textarea_disabled(self):
"""Test disabled textarea element.""" """Test disabled textarea element."""
elem = FakeWebElement(tagname='textarea', elem = stubs.FakeWebElement(tagname='textarea',
attributes={'disabled': None}) attributes={'disabled': None})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_textarea_readonly(self): def test_textarea_readonly(self):
"""Test readonly textarea element.""" """Test readonly textarea element."""
elem = FakeWebElement(tagname='textarea', elem = stubs.FakeWebElement(tagname='textarea',
attributes={'readonly': None}) attributes={'readonly': None})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_embed_true(self): def test_embed_true(self):
"""Test embed-element with insert-mode-on-plugins true.""" """Test embed-element with insert-mode-on-plugins true."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': True}}) {'insert-mode-on-plugins': True}})
elem = FakeWebElement(tagname='embed') elem = stubs.FakeWebElement(tagname='embed')
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_applet_true(self): def test_applet_true(self):
"""Test applet-element with insert-mode-on-plugins true.""" """Test applet-element with insert-mode-on-plugins true."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': True}}) {'insert-mode-on-plugins': True}})
elem = FakeWebElement(tagname='applet') elem = stubs.FakeWebElement(tagname='applet')
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_embed_false(self): def test_embed_false(self):
"""Test embed-element with insert-mode-on-plugins false.""" """Test embed-element with insert-mode-on-plugins false."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': False}}) {'insert-mode-on-plugins': False}})
elem = FakeWebElement(tagname='embed') elem = stubs.FakeWebElement(tagname='embed')
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_applet_false(self): def test_applet_false(self):
"""Test applet-element with insert-mode-on-plugins false.""" """Test applet-element with insert-mode-on-plugins false."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': False}}) {'insert-mode-on-plugins': False}})
elem = FakeWebElement(tagname='applet') elem = stubs.FakeWebElement(tagname='applet')
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_object_no_type(self): def test_object_no_type(self):
"""Test object-element without type.""" """Test object-element without type."""
elem = FakeWebElement(tagname='object') elem = stubs.FakeWebElement(tagname='object')
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_object_image(self): def test_object_image(self):
"""Test object-element with image type.""" """Test object-element with image type."""
elem = FakeWebElement(tagname='object', elem = stubs.FakeWebElement(tagname='object',
attributes={'type': 'image/gif'}) attributes={'type': 'image/gif'})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_object_application(self): def test_object_application(self):
"""Test object-element with application type.""" """Test object-element with application type."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': True}}) {'insert-mode-on-plugins': True}})
elem = FakeWebElement(tagname='object', elem = stubs.FakeWebElement(tagname='object',
attributes={'type': 'application/foo'}) attributes={'type': 'application/foo'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_object_application_false(self): def test_object_application_false(self):
"""Test object-element with application type but not ...-on-plugins.""" """Test object-element with application type but not ...-on-plugins."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': False}}) {'insert-mode-on-plugins': False}})
elem = FakeWebElement(tagname='object', elem = stubs.FakeWebElement(tagname='object',
attributes={'type': 'application/foo'}) attributes={'type': 'application/foo'})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_object_classid(self): def test_object_classid(self):
"""Test object-element with classid.""" """Test object-element with classid."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': True}}) {'insert-mode-on-plugins': True}})
elem = FakeWebElement(tagname='object', elem = stubs.FakeWebElement(tagname='object',
attributes={'type': 'foo', 'classid': 'foo'}) attributes={'type': 'foo',
'classid': 'foo'})
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_object_classid_false(self): def test_object_classid_false(self):
"""Test object-element with classid but not insert-mode-on-plugins.""" """Test object-element with classid but not insert-mode-on-plugins."""
webelem.config = ConfigStub({'input': webelem.config = stubs.ConfigStub({'input':
{'insert-mode-on-plugins': False}}) {'insert-mode-on-plugins': False}})
elem = FakeWebElement(tagname='object', elem = stubs.FakeWebElement(tagname='object',
attributes={'type': 'foo', 'classid': 'foo'}) attributes={'type': 'foo',
'classid': 'foo'})
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_div_empty(self): def test_div_empty(self):
"""Test div-element without class.""" """Test div-element without class."""
elem = FakeWebElement(tagname='div') elem = stubs.FakeWebElement(tagname='div')
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_div_noneditable(self): def test_div_noneditable(self):
"""Test div-element with non-editableclass.""" """Test div-element with non-editableclass."""
elem = FakeWebElement(tagname='div', classes='foo-kix-bar') elem = stubs.FakeWebElement(tagname='div', classes='foo-kix-bar')
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_div_xik(self): def test_div_xik(self):
"""Test div-element with xik class.""" """Test div-element with xik class."""
elem = FakeWebElement(tagname='div', classes='foo kix-foo') elem = stubs.FakeWebElement(tagname='div', classes='foo kix-foo')
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))
def test_div_xik_caps(self): def test_div_xik_caps(self):
@ -483,12 +499,13 @@ class IsEditableTests(unittest.TestCase):
This tests if classes are case sensitive as they should. This tests if classes are case sensitive as they should.
""" """
elem = FakeWebElement(tagname='div', classes='KIX-FOO') elem = stubs.FakeWebElement(tagname='div', classes='KIX-FOO')
self.assertFalse(webelem.is_editable(elem)) self.assertFalse(webelem.is_editable(elem))
def test_div_codemirror(self): def test_div_codemirror(self):
"""Test div-element with codemirror class.""" """Test div-element with codemirror class."""
elem = FakeWebElement(tagname='div', classes='foo CodeMirror-foo') elem = stubs.FakeWebElement(tagname='div',
classes='foo CodeMirror-foo')
self.assertTrue(webelem.is_editable(elem)) self.assertTrue(webelem.is_editable(elem))

View File

@ -21,7 +21,7 @@
import unittest import unittest
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import usertypes
# FIXME: Add some more tests, e.g. for is_int # FIXME: Add some more tests, e.g. for is_int
@ -35,7 +35,7 @@ class EnumTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.enum = enum('Enum', 'one', 'two') self.enum = usertypes.enum('Enum', 'one', 'two')
def test_values(self): def test_values(self):
"""Test if enum members resolve to the right values.""" """Test if enum members resolve to the right values."""
@ -54,7 +54,7 @@ class EnumTests(unittest.TestCase):
def test_start(self): def test_start(self):
"""Test the start= argument.""" """Test the start= argument."""
e = enum('Enum', 'three', 'four', start=3) e = usertypes.enum('Enum', 'three', 'four', start=3)
self.assertEqual(e.three.value, 3) self.assertEqual(e.three.value, 3)
self.assertEqual(e.four.value, 4) self.assertEqual(e.four.value, 4)

View File

@ -23,7 +23,7 @@
import unittest import unittest
from qutebrowser.utils.usertypes import NeighborList from qutebrowser.utils import usertypes
class InitTests(unittest.TestCase): class InitTests(unittest.TestCase):
@ -36,27 +36,27 @@ class InitTests(unittest.TestCase):
def test_empty(self): def test_empty(self):
"""Test constructing an empty NeighborList.""" """Test constructing an empty NeighborList."""
nl = NeighborList() nl = usertypes.NeighborList()
self.assertEqual(nl.items, []) self.assertEqual(nl.items, [])
def test_items(self): def test_items(self):
"""Test constructing an NeighborList with items.""" """Test constructing an NeighborList with items."""
nl = NeighborList([1, 2, 3]) nl = usertypes.NeighborList([1, 2, 3])
self.assertEqual(nl.items, [1, 2, 3]) self.assertEqual(nl.items, [1, 2, 3])
def test_len(self): def test_len(self):
"""Test len() on NeighborList.""" """Test len() on NeighborList."""
nl = NeighborList([1, 2, 3]) nl = usertypes.NeighborList([1, 2, 3])
self.assertEqual(len(nl), 3) self.assertEqual(len(nl), 3)
def test_repr(self): def test_repr(self):
"""Test repr() on NeighborList.""" """Test repr() on NeighborList."""
nl = NeighborList([1, 2, 3]) nl = usertypes.NeighborList([1, 2, 3])
self.assertEqual(repr(nl), 'NeighborList([1, 2, 3])') self.assertEqual(repr(nl), 'NeighborList([1, 2, 3])')
def test_contains(self): def test_contains(self):
"""Test 'in' on NeighborList.""" """Test 'in' on NeighborList."""
nl = NeighborList([1, 2, 3]) nl = usertypes.NeighborList([1, 2, 3])
self.assertIn(2, nl) self.assertIn(2, nl)
self.assertNotIn(4, nl) self.assertNotIn(4, nl)
@ -71,17 +71,17 @@ class DefaultTests(unittest.TestCase):
def test_simple(self): def test_simple(self):
"""Test default with a numeric argument.""" """Test default with a numeric argument."""
nl = NeighborList([1, 2, 3], default=2) nl = usertypes.NeighborList([1, 2, 3], default=2)
self.assertEqual(nl.idx, 1) self.assertEqual(nl.idx, 1)
def test_none(self): def test_none(self):
"""Test default 'None'.""" """Test default 'None'."""
nl = NeighborList([1, 2, None], default=None) nl = usertypes.NeighborList([1, 2, None], default=None)
self.assertEqual(nl.idx, 2) self.assertEqual(nl.idx, 2)
def test_unset(self): def test_unset(self):
"""Test unset default value.""" """Test unset default value."""
nl = NeighborList([1, 2, 3]) nl = usertypes.NeighborList([1, 2, 3])
self.assertIsNone(nl.idx) self.assertIsNone(nl.idx)
@ -94,7 +94,7 @@ class EmptyTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.nl = NeighborList() self.nl = usertypes.NeighborList()
def test_curitem(self): def test_curitem(self):
"""Test curitem with no item.""" """Test curitem with no item."""
@ -126,7 +126,7 @@ class ItemTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.nl = NeighborList([1, 2, 3, 4, 5], default=3) self.nl = usertypes.NeighborList([1, 2, 3, 4, 5], default=3)
def test_curitem(self): def test_curitem(self):
"""Test curitem().""" """Test curitem()."""
@ -183,11 +183,11 @@ class OneTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.nl = NeighborList([1], default=1) self.nl = usertypes.NeighborList([1], default=1)
def test_first_wrap(self): def test_first_wrap(self):
"""Test out of bounds previtem() with mode=wrap.""" """Test out of bounds previtem() with mode=wrap."""
self.nl._mode = NeighborList.Modes.wrap self.nl._mode = usertypes.NeighborList.Modes.wrap
self.nl.firstitem() self.nl.firstitem()
self.assertEqual(self.nl.idx, 0) self.assertEqual(self.nl.idx, 0)
self.assertEqual(self.nl.previtem(), 1) self.assertEqual(self.nl.previtem(), 1)
@ -195,7 +195,7 @@ class OneTests(unittest.TestCase):
def test_first_block(self): def test_first_block(self):
"""Test out of bounds previtem() with mode=block.""" """Test out of bounds previtem() with mode=block."""
self.nl._mode = NeighborList.Modes.block self.nl._mode = usertypes.NeighborList.Modes.block
self.nl.firstitem() self.nl.firstitem()
self.assertEqual(self.nl.idx, 0) self.assertEqual(self.nl.idx, 0)
self.assertEqual(self.nl.previtem(), 1) self.assertEqual(self.nl.previtem(), 1)
@ -203,7 +203,7 @@ class OneTests(unittest.TestCase):
def test_first_raise(self): def test_first_raise(self):
"""Test out of bounds previtem() with mode=raise.""" """Test out of bounds previtem() with mode=raise."""
self.nl._mode = NeighborList.Modes.exception self.nl._mode = usertypes.NeighborList.Modes.exception
self.nl.firstitem() self.nl.firstitem()
self.assertEqual(self.nl.idx, 0) self.assertEqual(self.nl.idx, 0)
with self.assertRaises(IndexError): with self.assertRaises(IndexError):
@ -212,7 +212,7 @@ class OneTests(unittest.TestCase):
def test_last_wrap(self): def test_last_wrap(self):
"""Test out of bounds nextitem() with mode=wrap.""" """Test out of bounds nextitem() with mode=wrap."""
self.nl._mode = NeighborList.Modes.wrap self.nl._mode = usertypes.NeighborList.Modes.wrap
self.nl.lastitem() self.nl.lastitem()
self.assertEqual(self.nl.idx, 0) self.assertEqual(self.nl.idx, 0)
self.assertEqual(self.nl.nextitem(), 1) self.assertEqual(self.nl.nextitem(), 1)
@ -220,7 +220,7 @@ class OneTests(unittest.TestCase):
def test_last_block(self): def test_last_block(self):
"""Test out of bounds nextitem() with mode=block.""" """Test out of bounds nextitem() with mode=block."""
self.nl._mode = NeighborList.Modes.block self.nl._mode = usertypes.NeighborList.Modes.block
self.nl.lastitem() self.nl.lastitem()
self.assertEqual(self.nl.idx, 0) self.assertEqual(self.nl.idx, 0)
self.assertEqual(self.nl.nextitem(), 1) self.assertEqual(self.nl.nextitem(), 1)
@ -228,7 +228,7 @@ class OneTests(unittest.TestCase):
def test_last_raise(self): def test_last_raise(self):
"""Test out of bounds nextitem() with mode=raise.""" """Test out of bounds nextitem() with mode=raise."""
self.nl._mode = NeighborList.Modes.exception self.nl._mode = usertypes.NeighborList.Modes.exception
self.nl.lastitem() self.nl.lastitem()
self.assertEqual(self.nl.idx, 0) self.assertEqual(self.nl.idx, 0)
with self.assertRaises(IndexError): with self.assertRaises(IndexError):
@ -245,8 +245,9 @@ class BlockTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.nl = NeighborList([1, 2, 3, 4, 5], default=3, self.nl = usertypes.NeighborList(
mode=NeighborList.Modes.block) [1, 2, 3, 4, 5], default=3,
mode=usertypes.NeighborList.Modes.block)
def test_first(self): def test_first(self):
"""Test ouf of bounds previtem().""" """Test ouf of bounds previtem()."""
@ -272,8 +273,8 @@ class WrapTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.nl = NeighborList([1, 2, 3, 4, 5], default=3, self.nl = usertypes.NeighborList(
mode=NeighborList.Modes.wrap) [1, 2, 3, 4, 5], default=3, mode=usertypes.NeighborList.Modes.wrap)
def test_first(self): def test_first(self):
"""Test ouf of bounds previtem().""" """Test ouf of bounds previtem()."""
@ -299,8 +300,9 @@ class RaiseTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.nl = NeighborList([1, 2, 3, 4, 5], default=3, self.nl = usertypes.NeighborList(
mode=NeighborList.Modes.exception) [1, 2, 3, 4, 5], default=3,
mode=usertypes.NeighborList.Modes.exception)
def test_first(self): def test_first(self):
"""Test ouf of bounds previtem().""" """Test ouf of bounds previtem()."""
@ -328,7 +330,7 @@ class SnapInTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
self.nl = NeighborList([20, 9, 1, 5]) self.nl = usertypes.NeighborList([20, 9, 1, 5])
def test_bigger(self): def test_bigger(self):
"""Test fuzzyval with snapping to a bigger value.""" """Test fuzzyval with snapping to a bigger value."""

View File

@ -21,15 +21,12 @@
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
import qutebrowser.config.config as config from qutebrowser.config import config, configdata
import qutebrowser.config.configdata as configdata from qutebrowser.commands import utils as cmdutils
import qutebrowser.commands.utils as cmdutils from qutebrowser.utils import usertypes
from qutebrowser.utils.log import completion as logger from qutebrowser.utils.log import completion as logger
from qutebrowser.models import completion as models
from qutebrowser.models.completionfilter import CompletionFilterModel as CFM from qutebrowser.models.completionfilter import CompletionFilterModel as CFM
from qutebrowser.models.completion import (
CommandCompletionModel, SettingSectionCompletionModel,
SettingOptionCompletionModel, SettingValueCompletionModel)
from qutebrowser.utils.usertypes import Completion
class Completer(QObject): class Completer(QObject):
@ -58,31 +55,32 @@ class Completer(QObject):
self.ignore_change = False self.ignore_change = False
self._models = { self._models = {
Completion.option: {}, usertypes.Completion.option: {},
Completion.value: {}, usertypes.Completion.value: {},
} }
self._init_command_completion() self._init_command_completion()
self._init_setting_completions() self._init_setting_completions()
def _init_command_completion(self): def _init_command_completion(self):
"""Initialize the command completion model.""" """Initialize the command completion model."""
self._models[Completion.command] = CFM( self._models[usertypes.Completion.command] = CFM(
CommandCompletionModel(self), self) models.CommandCompletionModel(self), self)
def _init_setting_completions(self): def _init_setting_completions(self):
"""Initialize setting completion models.""" """Initialize setting completion models."""
self._models[Completion.section] = CFM( self._models[usertypes.Completion.section] = CFM(
SettingSectionCompletionModel(self), self) models.SettingSectionCompletionModel(self), self)
self._models[Completion.option] = {} self._models[usertypes.Completion.option] = {}
self._models[Completion.value] = {} self._models[usertypes.Completion.value] = {}
for sectname in configdata.DATA: for sectname in configdata.DATA:
model = SettingOptionCompletionModel(sectname, self) model = models.SettingOptionCompletionModel(sectname, self)
self._models[Completion.option][sectname] = CFM(model, self) self._models[usertypes.Completion.option][sectname] = CFM(
model, self)
config.instance().changed.connect(model.on_config_changed) config.instance().changed.connect(model.on_config_changed)
self._models[Completion.value][sectname] = {} self._models[usertypes.Completion.value][sectname] = {}
for opt in configdata.DATA[sectname].keys(): for opt in configdata.DATA[sectname].keys():
model = SettingValueCompletionModel(sectname, opt, self) model = models.SettingValueCompletionModel(sectname, opt, self)
self._models[Completion.value][sectname][opt] = CFM( self._models[usertypes.Completion.value][sectname][opt] = CFM(
model, self) model, self)
config.instance().changed.connect(model.on_config_changed) config.instance().changed.connect(model.on_config_changed)
@ -95,7 +93,7 @@ class Completer(QObject):
""" """
if cursor_part == 0: if cursor_part == 0:
# '|' or 'set|' # '|' or 'set|'
return self._models[Completion.command] return self._models[usertypes.Completion.command]
# delegate completion to command # delegate completion to command
try: try:
completions = cmdutils.cmd_dict[parts[0]].completion completions = cmdutils.cmd_dict[parts[0]].completion
@ -115,10 +113,10 @@ class Completer(QObject):
return None return None
dbg_completions[idx] = '*' + dbg_completions[idx] + '*' dbg_completions[idx] = '*' + dbg_completions[idx] + '*'
logger.debug("completions: {}".format(', '.join(dbg_completions))) logger.debug("completions: {}".format(', '.join(dbg_completions)))
if completion == Completion.option: if completion == usertypes.Completion.option:
section = parts[cursor_part - 1] section = parts[cursor_part - 1]
model = self._models[completion].get(section) model = self._models[completion].get(section)
elif completion == Completion.value: elif completion == usertypes.Completion.value:
section = parts[cursor_part - 2] section = parts[cursor_part - 2]
option = parts[cursor_part - 1] option = parts[cursor_part - 1]
try: try:

View File

@ -23,13 +23,13 @@ import re
import pdb import pdb
import sys import sys
import types import types
from functools import wraps import functools
from PyQt5.QtCore import pyqtRemoveInputHook, QEvent, QCoreApplication from PyQt5.QtCore import pyqtRemoveInputHook, QEvent, QCoreApplication
from qutebrowser.utils.misc import elide, compact_text from qutebrowser.utils import misc as utils
from qutebrowser.utils.log import misc as logger from qutebrowser.utils.log import misc as logger
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import utils as cmdutils
@cmdutils.register(debug=True, name='debug-set-trace') @cmdutils.register(debug=True, name='debug-set-trace')
@ -89,7 +89,7 @@ def log_events(klass):
"""Class decorator to log Qt events.""" """Class decorator to log Qt events."""
old_event = klass.event old_event = klass.event
@wraps(old_event) @functools.wraps(old_event)
def new_event(self, e, *args, **kwargs): def new_event(self, e, *args, **kwargs):
"""Wrapper for event() which logs events.""" """Wrapper for event() which logs events."""
logger.debug("Event in {}: {}".format(klass.__name__, logger.debug("Event in {}: {}".format(klass.__name__,
@ -115,7 +115,7 @@ def trace_lines(do_trace):
if sys is not None: if sys is not None:
loc = '{}:{}'.format(frame.f_code.co_filename, frame.f_lineno) loc = '{}:{}'.format(frame.f_code.co_filename, frame.f_lineno)
if arg is not None: if arg is not None:
arg = compact_text(str(arg), 200) arg = utils.compact_text(str(arg), 200)
else: else:
arg = '' arg = ''
print("{:11} {:80} {}".format(event, loc, arg), file=sys.stderr) print("{:11} {:80} {}".format(event, loc, arg), file=sys.stderr)
@ -228,5 +228,6 @@ def dbg_signal(sig, args):
Return: Return:
A human-readable string representation of signal/args. A human-readable string representation of signal/args.
""" """
argstr = ', '.join([elide(str(a).replace('\n', ' '), 20) for a in args]) argstr = ', '.join([utils.elide(str(a).replace('\n', ' '), 20)
for a in args])
return '{}({})'.format(signal_name(sig), argstr) return '{}({})'.format(signal_name(sig), argstr)

View File

@ -26,9 +26,9 @@ import faulthandler
import traceback import traceback
import signal import signal
try: try:
from tkinter import Tk, messagebox # pylint: disable=import-error import tkinter # pylint: disable=import-error
except ImportError: except ImportError:
Tk = None tkinter = None
def _missing_str(name, debian=None, arch=None, windows=None, pip=None): def _missing_str(name, debian=None, arch=None, windows=None, pip=None):
@ -186,10 +186,10 @@ def check_pyqt_core():
text = text.replace('<b>', '') text = text.replace('<b>', '')
text = text.replace('</b>', '') text = text.replace('</b>', '')
text = text.replace('<br />', '\n') text = text.replace('<br />', '\n')
if Tk: if tkinter:
root = Tk() root = tkinter.Tk()
root.withdraw() root.withdraw()
messagebox.showerror("qutebrowser: Fatal error!", text) tkinter.messagebox.showerror("qutebrowser: Fatal error!", text)
else: else:
print(text, file=sys.stderr) print(text, file=sys.stderr)
if '--debug' in sys.argv: if '--debug' in sys.argv:

View File

@ -20,12 +20,12 @@
"""Launcher for an external editor.""" """Launcher for an external editor."""
import os import os
from tempfile import mkstemp import tempfile
from PyQt5.QtCore import pyqtSignal, QProcess, QObject from PyQt5.QtCore import pyqtSignal, QProcess, QObject
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.utils.message as message from qutebrowser.utils import message
from qutebrowser.utils.log import procs as logger from qutebrowser.utils.log import procs as logger
@ -109,7 +109,7 @@ class ExternalEditor(QObject):
if self.text is not None: if self.text is not None:
raise ValueError("Already editing a file!") raise ValueError("Already editing a file!")
self.text = text self.text = text
self.oshandle, self.filename = mkstemp(text=True) self.oshandle, self.filename = tempfile.mkstemp(text=True)
if text: if text:
encoding = config.get('general', 'editor-encoding') encoding = config.get('general', 'editor-encoding')
with open(self.filename, 'w', encoding=encoding) as f: with open(self.filename, 'w', encoding=encoding) as f:

View File

@ -21,7 +21,7 @@
import os.path import os.path
import qutebrowser.utils.rfc6266 as rfc6266 from qutebrowser.utils import rfc6266
from qutebrowser.utils.log import misc as logger from qutebrowser.utils.log import misc as logger
from PyQt5.QtNetwork import QNetworkRequest from PyQt5.QtNetwork import QNetworkRequest

View File

@ -24,9 +24,8 @@ import os
import sys import sys
import html as pyhtml import html as pyhtml
import logging import logging
from contextlib import contextmanager import contextlib
from logging import getLogger import collections
from collections import deque
from PyQt5.QtCore import (QtDebugMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg, from PyQt5.QtCore import (QtDebugMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg,
qInstallMessageHandler) qInstallMessageHandler)
@ -38,9 +37,9 @@ except ImportError:
colorama = None colorama = None
try: try:
# pylint: disable=import-error # pylint: disable=import-error
from colorlog import ColoredFormatter import colorlog
except ImportError: except ImportError:
ColoredFormatter = None colorlog = None
else: else:
# colorlog calls colorama.init() which we don't want, also it breaks our # colorlog calls colorama.init() which we don't want, also it breaks our
# sys.stdout/sys.stderr if they are None. Bugreports: # sys.stdout/sys.stderr if they are None. Bugreports:
@ -81,25 +80,25 @@ LOG_COLORS = {
# The different loggers used. # The different loggers used.
statusbar = getLogger('statusbar') statusbar = logging.getLogger('statusbar')
completion = getLogger('completion') completion = logging.getLogger('completion')
destroy = getLogger('destroy') destroy = logging.getLogger('destroy')
modes = getLogger('modes') modes = logging.getLogger('modes')
webview = getLogger('webview') webview = logging.getLogger('webview')
mouse = getLogger('mouse') mouse = logging.getLogger('mouse')
misc = getLogger('misc') misc = logging.getLogger('misc')
url = getLogger('url') url = logging.getLogger('url')
procs = getLogger('procs') procs = logging.getLogger('procs')
commands = getLogger('commands') commands = logging.getLogger('commands')
init = getLogger('init') init = logging.getLogger('init')
signals = getLogger('signals') signals = logging.getLogger('signals')
hints = getLogger('hints') hints = logging.getLogger('hints')
keyboard = getLogger('keyboard') keyboard = logging.getLogger('keyboard')
downloads = getLogger('downloads') downloads = logging.getLogger('downloads')
js = getLogger('js') # Javascript console messages js = logging.getLogger('js') # Javascript console messages
qt = getLogger('qt') # Warnings produced by Qt qt = logging.getLogger('qt') # Warnings produced by Qt
style = getLogger('style') style = logging.getLogger('style')
rfc6266 = getLogger('rfc6266') rfc6266 = logging.getLogger('rfc6266')
ram_handler = None ram_handler = None
@ -114,7 +113,7 @@ def init_log(args):
raise ValueError("Invalid log level: {}".format(args.loglevel)) raise ValueError("Invalid log level: {}".format(args.loglevel))
console, ram = _init_handlers(numeric_level, args.color, args.loglines) console, ram = _init_handlers(numeric_level, args.color, args.loglines)
root = getLogger() root = logging.getLogger()
if console is not None: if console is not None:
if args.logfilter is not None: if args.logfilter is not None:
console.addFilter(LogFilter(args.logfilter.split(','))) console.addFilter(LogFilter(args.logfilter.split(',')))
@ -126,7 +125,7 @@ def init_log(args):
qInstallMessageHandler(qt_message_handler) qInstallMessageHandler(qt_message_handler)
@contextmanager @contextlib.contextmanager
def disable_qt_msghandler(): def disable_qt_msghandler():
"""Contextmanager which temporarely disables the Qt message handler.""" """Contextmanager which temporarely disables the Qt message handler."""
old_handler = qInstallMessageHandler(None) old_handler = qInstallMessageHandler(None)
@ -191,10 +190,10 @@ def _init_formatters(level, color):
if sys.stderr is None: if sys.stderr is None:
return None, ram_formatter, html_formatter, False return None, ram_formatter, html_formatter, False
use_colorama = False use_colorama = False
if (ColoredFormatter is not None and (os.name == 'posix' or colorama) and if (colorlog is not None and (os.name == 'posix' or colorama) and
sys.stderr.isatty() and color): sys.stderr.isatty() and color):
console_formatter = ColoredFormatter(console_fmt_colored, DATEFMT, console_formatter = colorlog.ColoredFormatter(
log_colors=LOG_COLORS) console_fmt_colored, DATEFMT, log_colors=LOG_COLORS)
if colorama: if colorama:
use_colorama = True use_colorama = True
else: else:
@ -310,9 +309,9 @@ class RAMHandler(logging.Handler):
super().__init__() super().__init__()
self.html_formatter = None self.html_formatter = None
if capacity != -1: if capacity != -1:
self.data = deque(maxlen=capacity) self.data = collections.deque(maxlen=capacity)
else: else:
self.data = deque() self.data = collections.deque()
def emit(self, record): def emit(self, record):
self.data.append(record) self.data.append(record)

View File

@ -21,7 +21,7 @@
from PyQt5.QtCore import pyqtSignal, QCoreApplication, QObject, QTimer from PyQt5.QtCore import pyqtSignal, QCoreApplication, QObject, QTimer
from qutebrowser.utils.usertypes import PromptMode, Question from qutebrowser.utils import usertypes
from qutebrowser.utils.log import misc as logger from qutebrowser.utils.log import misc as logger
@ -64,7 +64,7 @@ def ask(message, mode, default=None):
Return: Return:
The answer the user gave or None if the prompt was cancelled. The answer the user gave or None if the prompt was cancelled.
""" """
q = Question() q = usertypes.Question()
q.text = message q.text = message
q.mode = mode q.mode = mode
q.default = default q.default = default
@ -75,9 +75,9 @@ def ask(message, mode, default=None):
def alert(message): def alert(message):
"""Display an alert which needs to be confirmed.""" """Display an alert which needs to be confirmed."""
q = Question() q = usertypes.Question()
q.text = message q.text = message
q.mode = PromptMode.alert q.mode = usertypes.PromptMode.alert
instance().ask(q, blocking=True) instance().ask(q, blocking=True)
q.deleteLater() q.deleteLater()
@ -91,10 +91,10 @@ def ask_async(message, mode, handler, default=None):
handler: The function to get called with the answer as argument. handler: The function to get called with the answer as argument.
default: The default value to display. default: The default value to display.
""" """
if not isinstance(mode, PromptMode): if not isinstance(mode, usertypes.PromptMode):
raise TypeError("Mode {} is no PromptMode member!".format(mode)) raise TypeError("Mode {} is no PromptMode member!".format(mode))
bridge = instance() bridge = instance()
q = Question(bridge) q = usertypes.Question(bridge)
q.text = message q.text = message
q.mode = mode q.mode = mode
q.default = default q.default = default
@ -113,9 +113,9 @@ def confirm_async(message, yes_action, no_action=None, default=None):
default: True/False to set a default value, or None. default: True/False to set a default value, or None.
""" """
bridge = instance() bridge = instance()
q = Question(bridge) q = usertypes.Question(bridge)
q.text = message q.text = message
q.mode = PromptMode.yesno q.mode = usertypes.PromptMode.yesno
q.default = default q.default = default
q.answered_yes.connect(yes_action) q.answered_yes.connect(yes_action)
if no_action is not None: if no_action is not None:
@ -152,7 +152,7 @@ class MessageBridge(QObject):
s_info = pyqtSignal(str, bool) s_info = pyqtSignal(str, bool)
s_set_text = pyqtSignal(str) s_set_text = pyqtSignal(str)
s_set_cmd_text = pyqtSignal(str) s_set_cmd_text = pyqtSignal(str)
s_question = pyqtSignal(Question, bool) s_question = pyqtSignal(usertypes.Question, bool)
def __repr__(self): def __repr__(self):
return '<{}>'.format(self.__class__.__name__) return '<{}>'.format(self.__class__.__name__)

View File

@ -25,17 +25,17 @@ import sys
import shlex import shlex
import os.path import os.path
import urllib.request import urllib.request
from urllib.parse import urljoin, urlencode import urllib.parse
from collections import OrderedDict import collections
from functools import reduce import functools
from contextlib import contextmanager import contextlib
from PyQt5.QtCore import QCoreApplication, QStandardPaths, Qt from PyQt5.QtCore import QCoreApplication, QStandardPaths, Qt
from PyQt5.QtGui import QKeySequence, QColor from PyQt5.QtGui import QKeySequence, QColor
from pkg_resources import resource_string import pkg_resources
import qutebrowser import qutebrowser
from qutebrowser.utils.qt import qt_version_check, qt_ensure_valid from qutebrowser.utils import qt as qtutils
def elide(text, length): def elide(text, length):
@ -81,7 +81,8 @@ def read_file(filename):
with open(fn, 'r', encoding='utf-8') as f: with open(fn, 'r', encoding='utf-8') as f:
return f.read() return f.read()
else: else:
return resource_string(qutebrowser.__name__, filename).decode('UTF-8') data = pkg_resources.resource_string(qutebrowser.__name__, filename)
return data.decode('UTF-8')
def dotted_getattr(obj, path): def dotted_getattr(obj, path):
@ -94,7 +95,7 @@ def dotted_getattr(obj, path):
Return: Return:
The object at path. The object at path.
""" """
return reduce(getattr, path.split('.'), obj) return functools.reduce(getattr, path.split('.'), obj)
def safe_shlex_split(s): def safe_shlex_split(s):
@ -134,8 +135,8 @@ def pastebin(text):
'title': "qutebrowser crash", 'title': "qutebrowser crash",
'name': "qutebrowser", 'name': "qutebrowser",
} }
encoded_data = urlencode(data).encode('utf-8') encoded_data = urllib.parse.urlencode(data).encode('utf-8')
create_url = urljoin(api_url, 'create') create_url = urllib.parse.urljoin(api_url, 'create')
headers = { headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
} }
@ -189,7 +190,7 @@ def actute_warning():
return return
# Qt >= 5.3 doesn't seem to be affected # Qt >= 5.3 doesn't seem to be affected
try: try:
if qt_version_check('5.3.0'): if qtutils.qt_version_check('5.3.0'):
return return
except ValueError: except ValueError:
pass pass
@ -246,8 +247,8 @@ def interpolate_color(start, end, percent, colorspace=QColor.Rgb):
Raise: Raise:
ValueError if invalid parameters are passed. ValueError if invalid parameters are passed.
""" """
qt_ensure_valid(start) qtutils.qt_ensure_valid(start)
qt_ensure_valid(end) qtutils.qt_ensure_valid(end)
out = QColor() out = QColor()
if colorspace == QColor.Rgb: if colorspace == QColor.Rgb:
a_c1, a_c2, a_c3, _alpha = start.getRgb() a_c1, a_c2, a_c3, _alpha = start.getRgb()
@ -270,7 +271,7 @@ def interpolate_color(start, end, percent, colorspace=QColor.Rgb):
else: else:
raise ValueError("Invalid colorspace!") raise ValueError("Invalid colorspace!")
out = out.convertTo(start.spec()) out = out.convertTo(start.spec())
qt_ensure_valid(out) qtutils.qt_ensure_valid(out)
return out return out
@ -400,7 +401,7 @@ def keyevent_to_string(e):
A name of the key (combination) as a string or A name of the key (combination) as a string or
None if only modifiers are pressed.. None if only modifiers are pressed..
""" """
modmask2str = OrderedDict([ modmask2str = collections.OrderedDict([
(Qt.ControlModifier, 'Ctrl'), (Qt.ControlModifier, 'Ctrl'),
(Qt.AltModifier, 'Alt'), (Qt.AltModifier, 'Alt'),
(Qt.MetaModifier, 'Meta'), (Qt.MetaModifier, 'Meta'),
@ -460,7 +461,7 @@ class FakeIOStream(io.TextIOBase):
return super().isatty() return super().isatty()
@contextmanager @contextlib.contextmanager
def fake_io(write_func): def fake_io(write_func):
"""Run code with stdout and stderr replaced by FakeIOStreams. """Run code with stdout and stderr replaced by FakeIOStreams.
@ -482,7 +483,7 @@ def fake_io(write_func):
sys.stderr = old_stderr sys.stderr = old_stderr
@contextmanager @contextlib.contextmanager
def disabled_excepthook(): def disabled_excepthook():
"""Run code with the exception hook temporarely disabled.""" """Run code with the exception hook temporarely disabled."""
old_excepthook = sys.excepthook old_excepthook = sys.excepthook

View File

@ -21,8 +21,8 @@
from PyQt5.QtWidgets import QApplication, QLineEdit from PyQt5.QtWidgets import QApplication, QLineEdit
import qutebrowser.commands.utils as cmd from qutebrowser.commands import utils as cmdutils
from qutebrowser.utils.usertypes import KeyMode from qutebrowser.utils import usertypes as typ
class ReadlineBridge: class ReadlineBridge:
@ -45,8 +45,8 @@ class ReadlineBridge:
else: else:
return None return None
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_backward_char(self): def rl_backward_char(self):
"""Move back a character. """Move back a character.
@ -56,8 +56,8 @@ class ReadlineBridge:
return return
self.widget.cursorBackward(False) self.widget.cursorBackward(False)
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_forward_char(self): def rl_forward_char(self):
"""Move forward a character. """Move forward a character.
@ -67,8 +67,8 @@ class ReadlineBridge:
return return
self.widget.cursorForward(False) self.widget.cursorForward(False)
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_backward_word(self): def rl_backward_word(self):
"""Move back to the start of the current or previous word. """Move back to the start of the current or previous word.
@ -78,8 +78,8 @@ class ReadlineBridge:
return return
self.widget.cursorWordBackward(False) self.widget.cursorWordBackward(False)
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_forward_word(self): def rl_forward_word(self):
"""Move forward to the end of the next word. """Move forward to the end of the next word.
@ -89,8 +89,8 @@ class ReadlineBridge:
return return
self.widget.cursorWordForward(False) self.widget.cursorWordForward(False)
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_beginning_of_line(self): def rl_beginning_of_line(self):
"""Move to the start of the line. """Move to the start of the line.
@ -100,8 +100,8 @@ class ReadlineBridge:
return return
self.widget.home(False) self.widget.home(False)
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_end_of_line(self): def rl_end_of_line(self):
"""Move to the end of the line. """Move to the end of the line.
@ -111,8 +111,8 @@ class ReadlineBridge:
return return
self.widget.end(False) self.widget.end(False)
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_unix_line_discard(self): def rl_unix_line_discard(self):
"""Remove chars backward from the cursor to the beginning of the line. """Remove chars backward from the cursor to the beginning of the line.
@ -124,8 +124,8 @@ class ReadlineBridge:
self.deleted[self.widget] = self.widget.selectedText() self.deleted[self.widget] = self.widget.selectedText()
self.widget.del_() self.widget.del_()
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_kill_line(self): def rl_kill_line(self):
"""Remove chars from the cursor to the end of the line. """Remove chars from the cursor to the end of the line.
@ -137,8 +137,8 @@ class ReadlineBridge:
self.deleted[self.widget] = self.widget.selectedText() self.deleted[self.widget] = self.widget.selectedText()
self.widget.del_() self.widget.del_()
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_unix_word_rubout(self): def rl_unix_word_rubout(self):
"""Remove chars from the cursor to the beginning of the word. """Remove chars from the cursor to the beginning of the word.
@ -150,8 +150,8 @@ class ReadlineBridge:
self.deleted[self.widget] = self.widget.selectedText() self.deleted[self.widget] = self.widget.selectedText()
self.widget.del_() self.widget.del_()
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_kill_word(self): def rl_kill_word(self):
"""Remove chars from the cursor to the end of the current word. """Remove chars from the cursor to the end of the current word.
@ -163,8 +163,8 @@ class ReadlineBridge:
self.deleted[self.widget] = self.widget.selectedText() self.deleted[self.widget] = self.widget.selectedText()
self.widget.del_() self.widget.del_()
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_yank(self): def rl_yank(self):
"""Paste the most recently deleted text. """Paste the most recently deleted text.
@ -174,8 +174,8 @@ class ReadlineBridge:
return return
self.widget.insert(self.deleted[self.widget]) self.widget.insert(self.deleted[self.widget])
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_delete_char(self): def rl_delete_char(self):
"""Delete the character after the cursor. """Delete the character after the cursor.
@ -185,8 +185,8 @@ class ReadlineBridge:
return return
self.widget.del_() self.widget.del_()
@cmd.register(instance='rl_bridge', hide=True, @cmdutils.register(instance='rl_bridge', hide=True,
modes=[KeyMode.command, KeyMode.prompt]) modes=[typ.KeyMode.command, typ.KeyMode.prompt])
def rl_backward_delete_char(self): def rl_backward_delete_char(self):
"""Delete the character before the cursor. """Delete the character before the cursor.

View File

@ -19,7 +19,7 @@
"""pyPEG parsing for the RFC 6266 (Content-Disposition) header. """ """pyPEG parsing for the RFC 6266 (Content-Disposition) header. """
from collections import namedtuple import collections
import urllib.parse import urllib.parse
import string import string
import re import re
@ -209,7 +209,7 @@ class ContentDispositionValue:
peg.optional(';')) peg.optional(';'))
LangTagged = namedtuple('LangTagged', 'string langtag') LangTagged = collections.namedtuple('LangTagged', 'string langtag')
class DuplicateParamError(Exception): class DuplicateParamError(Exception):

View File

@ -26,9 +26,9 @@ import urllib.parse
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from PyQt5.QtNetwork import QHostInfo from PyQt5.QtNetwork import QHostInfo
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.log import url as logger from qutebrowser.utils.log import url as logger
from qutebrowser.utils.misc import qt_ensure_valid
# FIXME: we probably could raise some exceptions on invalid URLs # FIXME: we probably could raise some exceptions on invalid URLs
@ -65,7 +65,7 @@ def _get_search_url(txt):
if not term: if not term:
raise FuzzyUrlError("No search term given") raise FuzzyUrlError("No search term given")
url = QUrl.fromUserInput(template.format(urllib.parse.quote(term))) url = QUrl.fromUserInput(template.format(urllib.parse.quote(term)))
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
return url return url
@ -143,7 +143,7 @@ def fuzzy_url(urlstr):
url = QUrl.fromUserInput(stripped) url = QUrl.fromUserInput(stripped)
logger.debug("Converting fuzzy term {} to URL -> {}".format( logger.debug("Converting fuzzy term {} to URL -> {}".format(
urlstr, url.toDisplayString())) urlstr, url.toDisplayString()))
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
return url return url

View File

@ -29,8 +29,8 @@ import enum as pyenum
from PyQt5.QtCore import pyqtSignal, QObject, QTimer from PyQt5.QtCore import pyqtSignal, QObject, QTimer
from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.log import misc as logger from qutebrowser.utils.log import misc as logger
from qutebrowser.utils.qt import check_overflow
_UNSET = object() _UNSET = object()
@ -372,13 +372,13 @@ class Timer(QTimer):
def setInterval(self, msec): def setInterval(self, msec):
"""Extend setInterval to check for overflows.""" """Extend setInterval to check for overflows."""
check_overflow(msec, 'int') qtutils.check_overflow(msec, 'int')
super().setInterval(msec) super().setInterval(msec)
def start(self, msec=None): def start(self, msec=None):
"""Extend start to check for overflows.""" """Extend start to check for overflows."""
if msec is not None: if msec is not None:
check_overflow(msec, 'int') qtutils.check_overflow(msec, 'int')
super().start(msec) super().start(msec)
else: else:
super().start() super().start()

View File

@ -21,10 +21,10 @@
from functools import partial from functools import partial
import qutebrowser.commands.utils as cmdutils from qutebrowser.utils import usertypes
from qutebrowser.utils.usertypes import Timer from qutebrowser.commands import runners
from qutebrowser.commands.exceptions import CommandError from qutebrowser.commands import utils as cmdutils
from qutebrowser.commands.runners import CommandRunner from qutebrowser.commands import exceptions as cmdexc
_timers = [] _timers = []
@ -34,7 +34,7 @@ _commandrunner = None
def init(): def init():
"""Initialize the global _commandrunner.""" """Initialize the global _commandrunner."""
global _commandrunner global _commandrunner
_commandrunner = CommandRunner() _commandrunner = runners.CommandRunner()
@cmdutils.register(nargs=(2, None)) @cmdutils.register(nargs=(2, None))
@ -46,15 +46,15 @@ def later(ms, *command):
command: The command/args to run. command: The command/args to run.
""" """
ms = int(ms) ms = int(ms)
timer = Timer(name='later') timer = usertypes.Timer(name='later')
timer.setSingleShot(True) timer.setSingleShot(True)
if ms < 0: if ms < 0:
raise CommandError("I can't run something in the past!") raise cmdexc.CommandError("I can't run something in the past!")
try: try:
timer.setInterval(ms) timer.setInterval(ms)
except OverflowError: except OverflowError:
raise CommandError("Numeric argument is too large for internal int " raise cmdexc.CommandError("Numeric argument is too large for internal "
"representation.") "int representation.")
_timers.append(timer) _timers.append(timer)
cmdline = ' '.join(command) cmdline = ' '.join(command)
timer.timeout.connect(partial(_commandrunner.run_safely, cmdline)) timer.timeout.connect(partial(_commandrunner.run_safely, cmdline))

View File

@ -29,7 +29,7 @@ from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, qVersion
from PyQt5.QtWebKit import qWebKitVersion from PyQt5.QtWebKit import qWebKitVersion
import qutebrowser import qutebrowser
from qutebrowser.utils.misc import read_file from qutebrowser.utils import misc as utils
from qutebrowser.utils.log import misc as logger from qutebrowser.utils.log import misc as logger
@ -91,7 +91,7 @@ def _git_str():
return commit return commit
# If that fails, check the git-commit-id file. # If that fails, check the git-commit-id file.
try: try:
return read_file('git-commit-id') return utils.read_file('git-commit-id')
except (FileNotFoundError, ImportError): except (FileNotFoundError, ImportError):
return None return None

View File

@ -30,13 +30,13 @@ Module attributes:
from PyQt5.QtCore import QRect, QUrl from PyQt5.QtCore import QRect, QUrl
from PyQt5.QtWebKit import QWebElement from PyQt5.QtWebKit import QWebElement
import qutebrowser.utils.log as log from qutebrowser.config import config
import qutebrowser.config.config as config from qutebrowser.utils import log, usertypes
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import misc as utils
from qutebrowser.utils.misc import compact_text
Group = enum('Group', 'all', 'links', 'images', 'url', 'prevnext', 'focus') Group = usertypes.enum('Group', 'all', 'links', 'images', 'url', 'prevnext',
'focus')
SELECTORS = { SELECTORS = {
@ -284,4 +284,4 @@ def focus_elem(frame):
def debug_text(elem): def debug_text(elem):
"""Get a text based on an element suitable for debug output.""" """Get a text based on an element suitable for debug output."""
return compact_text(elem.toOuterXml(), 500) return utils.compact_text(elem.toOuterXml(), 500)

View File

@ -26,13 +26,11 @@ subclasses to provide completions.
from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel
import qutebrowser.config.config as config from qutebrowser.commands import utils as cmdutils
import qutebrowser.commands.utils as cmdutils from qutebrowser.config import config, style
from qutebrowser.widgets.completiondelegate import CompletionItemDelegate from qutebrowser.widgets import completiondelegate
from qutebrowser.config.style import set_register_stylesheet from qutebrowser.utils import completer, usertypes
from qutebrowser.utils.completer import Completer from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.qt import qt_ensure_valid
from qutebrowser.utils.usertypes import KeyMode
class CompletionView(QTreeView): class CompletionView(QTreeView):
@ -94,12 +92,12 @@ class CompletionView(QTreeView):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.completer = Completer(self) self.completer = completer.Completer(self)
self.enabled = config.get('completion', 'show') self.enabled = config.get('completion', 'show')
self._delegate = CompletionItemDelegate(self) self._delegate = completiondelegate.CompletionItemDelegate(self)
self.setItemDelegate(self._delegate) self.setItemDelegate(self._delegate)
set_register_stylesheet(self) style.set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum)
self.setHeaderHidden(True) self.setHeaderHidden(True)
self.setIndentation(0) self.setIndentation(0)
@ -169,7 +167,7 @@ class CompletionView(QTreeView):
# No completion running at the moment, ignore keypress # No completion running at the moment, ignore keypress
return return
idx = self._next_idx(prev) idx = self._next_idx(prev)
qt_ensure_valid(idx) qtutils.qt_ensure_valid(idx)
self.selectionModel().setCurrentIndex( self.selectionModel().setCurrentIndex(
idx, QItemSelectionModel.ClearAndSelect | idx, QItemSelectionModel.ClearAndSelect |
QItemSelectionModel.Rows) QItemSelectionModel.Rows)
@ -212,13 +210,13 @@ class CompletionView(QTreeView):
selmod.clearCurrentIndex() selmod.clearCurrentIndex()
@cmdutils.register(instance='mainwindow.completion', hide=True, @cmdutils.register(instance='mainwindow.completion', hide=True,
modes=[KeyMode.command]) modes=[usertypes.KeyMode.command])
def completion_item_prev(self): def completion_item_prev(self):
"""Select the previous completion item.""" """Select the previous completion item."""
self._next_prev_item(prev=True) self._next_prev_item(prev=True)
@cmdutils.register(instance='mainwindow.completion', hide=True, @cmdutils.register(instance='mainwindow.completion', hide=True,
modes=[KeyMode.command]) modes=[usertypes.KeyMode.command])
def completion_item_next(self): def completion_item_next(self):
"""Select the next completion item.""" """Select the next completion item."""
self._next_prev_item(prev=False) self._next_prev_item(prev=False)

View File

@ -28,10 +28,9 @@ from PyQt5.QtCore import QRectF, QSize, Qt
from PyQt5.QtGui import (QIcon, QPalette, QTextDocument, QTextOption, from PyQt5.QtGui import (QIcon, QPalette, QTextDocument, QTextOption,
QTextCursor, QAbstractTextDocumentLayout) QTextCursor, QAbstractTextDocumentLayout)
import qutebrowser.config.config as config from qutebrowser.config import config, style
from qutebrowser.models.basecompletion import Role from qutebrowser.models import basecompletion
from qutebrowser.config.style import get_stylesheet from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.qt import qt_ensure_valid
class CompletionItemDelegate(QStyledItemDelegate): class CompletionItemDelegate(QStyledItemDelegate):
@ -99,12 +98,12 @@ class CompletionItemDelegate(QStyledItemDelegate):
text_rect_ = self._style.subElementRect( text_rect_ = self._style.subElementRect(
self._style.SE_ItemViewItemText, self._opt, self._opt.widget) self._style.SE_ItemViewItemText, self._opt, self._opt.widget)
qt_ensure_valid(text_rect_) qtutils.qt_ensure_valid(text_rect_)
margin = self._style.pixelMetric(QStyle.PM_FocusFrameHMargin, margin = self._style.pixelMetric(QStyle.PM_FocusFrameHMargin,
self._opt, self._opt.widget) + 1 self._opt, self._opt.widget) + 1
# remove width padding # remove width padding
text_rect = text_rect_.adjusted(margin, 0, -margin, 0) text_rect = text_rect_.adjusted(margin, 0, -margin, 0)
qt_ensure_valid(text_rect) qtutils.qt_ensure_valid(text_rect)
# move text upwards a bit # move text upwards a bit
if index.parent().isValid(): if index.parent().isValid():
text_rect.adjust(0, -1, 0, -1) text_rect.adjust(0, -1, 0, -1)
@ -189,7 +188,7 @@ class CompletionItemDelegate(QStyledItemDelegate):
self._doc.setHtml('<b>{}</b>'.format(html.escape(self._opt.text))) self._doc.setHtml('<b>{}</b>'.format(html.escape(self._opt.text)))
self._doc.setDefaultFont(self._opt.font) self._doc.setDefaultFont(self._opt.font)
self._doc.setDefaultTextOption(text_option) self._doc.setDefaultTextOption(text_option)
self._doc.setDefaultStyleSheet(get_stylesheet(""" self._doc.setDefaultStyleSheet(style.get_stylesheet("""
.highlight {{ .highlight {{
{color[completion.match.fg]} {color[completion.match.fg]}
}} }}
@ -197,7 +196,7 @@ class CompletionItemDelegate(QStyledItemDelegate):
self._doc.setDocumentMargin(2) self._doc.setDocumentMargin(2)
if index.column() == 0: if index.column() == 0:
marks = index.data(Role.marks) marks = index.data(basecompletion.Role.marks)
if marks is None: if marks is None:
return return
for mark in marks: for mark in marks:
@ -218,7 +217,7 @@ class CompletionItemDelegate(QStyledItemDelegate):
o.rect = self._style.subElementRect( o.rect = self._style.subElementRect(
self._style.SE_ItemViewItemFocusRect, self._opt, self._opt.widget) self._style.SE_ItemViewItemFocusRect, self._opt, self._opt.widget)
o.state |= QStyle.State_KeyboardFocusChange | QStyle.State_Item o.state |= QStyle.State_KeyboardFocusChange | QStyle.State_Item
qt_ensure_valid(o.rect) qtutils.qt_ensure_valid(o.rect)
if state & QStyle.State_Enabled: if state & QStyle.State_Enabled:
cg = QPalette.Normal cg = QPalette.Normal
else: else:
@ -254,7 +253,7 @@ class CompletionItemDelegate(QStyledItemDelegate):
docsize = self._doc.size().toSize() docsize = self._doc.size().toSize()
size = self._style.sizeFromContents(QStyle.CT_ItemViewItem, self._opt, size = self._style.sizeFromContents(QStyle.CT_ItemViewItem, self._opt,
docsize, self._opt.widget) docsize, self._opt.widget)
qt_ensure_valid(size) qtutils.qt_ensure_valid(size)
return size + QSize(10, 3) return size + QSize(10, 3)
def paint(self, painter, option, index): def paint(self, painter, option, index):

View File

@ -20,19 +20,18 @@
"""Debugging console.""" """Debugging console."""
import sys import sys
from code import InteractiveInterpreter import code
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
from PyQt5.QtWidgets import QTextEdit, QWidget, QVBoxLayout, QApplication from PyQt5.QtWidgets import QTextEdit, QWidget, QVBoxLayout, QApplication
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.models.cmdhistory import (History, HistoryEmptyError, from qutebrowser.models import cmdhistory
HistoryEndReachedError) from qutebrowser.utils import misc as utils
from qutebrowser.utils.misc import fake_io, disabled_excepthook from qutebrowser.widgets import misc
from qutebrowser.widgets.misc import CommandLineEdit
class ConsoleLineEdit(CommandLineEdit): class ConsoleLineEdit(misc.CommandLineEdit):
"""A QLineEdit which executes entered code and provides a history.""" """A QLineEdit which executes entered code and provides a history."""
@ -56,8 +55,8 @@ class ConsoleLineEdit(CommandLineEdit):
# console, not just the line edit. # console, not just the line edit.
'self': parent, 'self': parent,
} }
self._interpreter = InteractiveInterpreter(interpreter_locals) self._interpreter = code.InteractiveInterpreter(interpreter_locals)
self.history = History() self.history = cmdhistory.History()
self.returnPressed.connect(self.execute) self.returnPressed.connect(self.execute)
self.setText('') self.setText('')
@ -88,7 +87,7 @@ class ConsoleLineEdit(CommandLineEdit):
# same. # same.
# - We disable our exception hook, so exceptions from the console get # - We disable our exception hook, so exceptions from the console get
# printed and don't ooen a crashdialog. # printed and don't ooen a crashdialog.
with fake_io(self.write.emit), disabled_excepthook(): with utils.fake_io(self.write.emit), utils.disabled_excepthook():
self._more = self._interpreter.runsource(source, '<console>') self._more = self._interpreter.runsource(source, '<console>')
self.set_prompt(self.curprompt) self.set_prompt(self.curprompt)
if not self._more: if not self._more:
@ -101,7 +100,8 @@ class ConsoleLineEdit(CommandLineEdit):
item = self.history.start(self.text().strip()) item = self.history.start(self.text().strip())
else: else:
item = self.history.previtem() item = self.history.previtem()
except (HistoryEmptyError, HistoryEndReachedError): except (cmdhistory.HistoryEmptyError,
cmdhistory.HistoryEndReachedError):
return return
self.setText(item) self.setText(item)
@ -111,7 +111,7 @@ class ConsoleLineEdit(CommandLineEdit):
return return
try: try:
item = self.history.nextitem() item = self.history.nextitem()
except HistoryEndReachedError: except cmdhistory.HistoryEndReachedError:
return return
self.setText(item) self.setText(item)

View File

@ -21,17 +21,16 @@
import sys import sys
import traceback import traceback
from urllib.error import URLError import urllib.error
from getpass import getuser import getpass
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton, from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton,
QVBoxLayout, QHBoxLayout) QVBoxLayout, QHBoxLayout)
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.utils.misc as utils from qutebrowser.utils import version, log
import qutebrowser.utils.log as logutils from qutebrowser.utils import misc as utils
from qutebrowser.utils.version import version
class _CrashDialog(QDialog): class _CrashDialog(QDialog):
@ -124,11 +123,11 @@ class _CrashDialog(QDialog):
] ]
try: try:
self._crash_info.append(("Contact info", self._crash_info.append(("Contact info",
"User: {}".format(getuser()))) "User: {}".format(getpass.getuser())))
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
self._crash_info.append(("Contact info", "User: {}: {}".format( self._crash_info.append(("Contact info", "User: {}: {}".format(
e.__class__.__name__, e))) e.__class__.__name__, e)))
self._crash_info.append(("Version info", version())) self._crash_info.append(("Version info", version.version()))
try: try:
self._crash_info.append(("Config", self._crash_info.append(("Config",
config.instance().dump_userconfig())) config.instance().dump_userconfig()))
@ -156,7 +155,7 @@ class _CrashDialog(QDialog):
"""Paste the crash info into the pastebin.""" """Paste the crash info into the pastebin."""
try: try:
url = utils.pastebin(self._txt.toPlainText()) url = utils.pastebin(self._txt.toPlainText())
except (URLError, ValueError) as e: except (urllib.error.URLError, ValueError) as e:
self._url.setText('Error while reporting: {}: {}'.format( self._url.setText('Error while reporting: {}: {}'.format(
e.__class__.__name__, e)) e.__class__.__name__, e))
return return
@ -228,8 +227,7 @@ class ExceptionCrashDialog(_CrashDialog):
("Objects", self._objects), ("Objects", self._objects),
] ]
try: try:
self._crash_info.append(("Debug log", self._crash_info.append(("Debug log", log.ram_handler.dump_log()))
logutils.ram_handler.dump_log()))
except AttributeError as e: except AttributeError as e:
self._crash_info.append(("Debug log", "{}: {}".format( self._crash_info.append(("Debug log", "{}: {}".format(
e.__class__.__name__, e))) e.__class__.__name__, e)))
@ -245,8 +243,8 @@ class FatalCrashDialog(_CrashDialog):
_btn_pastebin: The pastebin button. _btn_pastebin: The pastebin button.
""" """
def __init__(self, log, parent=None): def __init__(self, text, parent=None):
self._log = log self._log = text
self._btn_ok = None self._btn_ok = None
self._btn_pastebin = None self._btn_pastebin = None
super().__init__(parent) super().__init__(parent)
@ -329,8 +327,7 @@ class ReportDialog(_CrashDialog):
("Objects", self._objects), ("Objects", self._objects),
] ]
try: try:
self._crash_info.append(("Debug log", self._crash_info.append(("Debug log", log.ram_handler.dump_log()))
logutils.ram_handler.dump_log()))
except AttributeError as e: except AttributeError as e:
self._crash_info.append(("Debug log", "{}: {}".format( self._crash_info.append(("Debug log", "{}: {}".format(
e.__class__.__name__, e))) e.__class__.__name__, e)))

View File

@ -22,9 +22,9 @@
from PyQt5.QtCore import pyqtSlot, QSize, Qt from PyQt5.QtCore import pyqtSlot, QSize, Qt
from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu
from qutebrowser.models.downloadmodel import DownloadModel, Role from qutebrowser.models import downloadmodel
from qutebrowser.config.style import set_register_stylesheet from qutebrowser.config import style
from qutebrowser.utils.qt import qt_ensure_valid from qutebrowser.utils import qt as qtutils
class DownloadView(QListView): class DownloadView(QListView):
@ -49,13 +49,13 @@ class DownloadView(QListView):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
set_register_stylesheet(self) style.set_register_stylesheet(self)
self.setResizeMode(QListView.Adjust) self.setResizeMode(QListView.Adjust)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
self.setFlow(QListView.LeftToRight) self.setFlow(QListView.LeftToRight)
self._menu = None self._menu = None
self._model = DownloadModel(self) self._model = downloadmodel.DownloadModel(self)
self._model.rowsInserted.connect(self.updateGeometry) self._model.rowsInserted.connect(self.updateGeometry)
self._model.rowsRemoved.connect(self.updateGeometry) self._model.rowsRemoved.connect(self.updateGeometry)
self.setModel(self._model) self.setModel(self._model)
@ -73,7 +73,7 @@ class DownloadView(QListView):
index = self.indexAt(point) index = self.indexAt(point)
if not index.isValid(): if not index.isValid():
return return
item = self.model().data(index, Role.item) item = self.model().data(index, downloadmodel.Role.item)
self._menu = QMenu(self) self._menu = QMenu(self)
cancel = self._menu.addAction("Cancel") cancel = self._menu.addAction("Cancel")
cancel.triggered.connect(item.cancel) cancel.triggered.connect(item.cancel)
@ -91,5 +91,5 @@ class DownloadView(QListView):
size = QSize(0, height + 2) size = QSize(0, height + 2)
else: else:
size = QSize(0, 0) size = QSize(0, 0)
qt_ensure_valid(size) qtutils.qt_ensure_valid(size)
return size return size

View File

@ -20,21 +20,17 @@
"""The main window of qutebrowser.""" """The main window of qutebrowser."""
import binascii import binascii
from base64 import b64decode import base64
from PyQt5.QtCore import pyqtSlot, QRect, QPoint, QCoreApplication, QTimer from PyQt5.QtCore import pyqtSlot, QRect, QPoint, QCoreApplication, QTimer
from PyQt5.QtWidgets import QWidget, QVBoxLayout from PyQt5.QtWidgets import QWidget, QVBoxLayout
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import utils as cmdutils
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.utils.message as message from qutebrowser.utils import message, log, usertypes
import qutebrowser.utils.log as log from qutebrowser.utils import qt as qtutils
from qutebrowser.widgets.statusbar.bar import StatusBar from qutebrowser.widgets import tabbedbrowser, completion, downloads
from qutebrowser.widgets.tabbedbrowser import TabbedBrowser from qutebrowser.widgets.statusbar import bar
from qutebrowser.widgets.completion import CompletionView
from qutebrowser.widgets.downloads import DownloadView
from qutebrowser.utils.usertypes import PromptMode
from qutebrowser.utils.qt import check_overflow
class MainWindow(QWidget): class MainWindow(QWidget):
@ -57,9 +53,9 @@ class MainWindow(QWidget):
self.setWindowTitle('qutebrowser') self.setWindowTitle('qutebrowser')
try: try:
stateconf = QCoreApplication.instance().stateconfig stateconf = QCoreApplication.instance().stateconfig
base64 = stateconf['geometry']['mainwindow'] data = stateconf['geometry']['mainwindow']
log.init.debug("Restoring mainwindow from {}".format(base64)) log.init.debug("Restoring mainwindow from {}".format(data))
geom = b64decode(base64, validate=True) geom = base64.b64decode(data, validate=True)
except (KeyError, binascii.Error) as e: except (KeyError, binascii.Error) as e:
log.init.warning("Error while reading geometry: {}: {}".format( log.init.warning("Error while reading geometry: {}: {}".format(
e.__class__.__name__, e)) e.__class__.__name__, e))
@ -81,17 +77,17 @@ class MainWindow(QWidget):
self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setContentsMargins(0, 0, 0, 0)
self._vbox.setSpacing(0) self._vbox.setSpacing(0)
self.downloadview = DownloadView() self.downloadview = downloads.DownloadView()
self._vbox.addWidget(self.downloadview) self._vbox.addWidget(self.downloadview)
self.downloadview.show() self.downloadview.show()
self.tabs = TabbedBrowser() self.tabs = tabbedbrowser.TabbedBrowser()
self.tabs.title_changed.connect(self.setWindowTitle) self.tabs.title_changed.connect(self.setWindowTitle)
self._vbox.addWidget(self.tabs) self._vbox.addWidget(self.tabs)
self.completion = CompletionView(self) self.completion = completion.CompletionView(self)
self.status = StatusBar() self.status = bar.StatusBar()
self._vbox.addWidget(self.status) self._vbox.addWidget(self.status)
# When we're here the statusbar might not even really exist yet, so # When we're here the statusbar might not even really exist yet, so
@ -139,7 +135,7 @@ class MainWindow(QWidget):
# hpoint now would be the bottom-left edge of the widget if it was on # hpoint now would be the bottom-left edge of the widget if it was on
# the top of the main window. # the top of the main window.
topleft_y = self.height() - self.status.height() - height topleft_y = self.height() - self.status.height() - height
topleft_y = check_overflow(topleft_y, 'int', fatal=False) topleft_y = qtutils.check_overflow(topleft_y, 'int', fatal=False)
topleft = QPoint(0, topleft_y) topleft = QPoint(0, topleft_y)
bottomright = self.status.geometry().topRight() bottomright = self.status.geometry().topRight()
rect = QRect(topleft, bottomright) rect = QRect(topleft, bottomright)
@ -178,7 +174,8 @@ class MainWindow(QWidget):
else: else:
text = "Close {} {}?".format( text = "Close {} {}?".format(
count, "tab" if count == 1 else "tabs") count, "tab" if count == 1 else "tabs")
confirmed = message.ask(text, PromptMode.yesno, default=True) confirmed = message.ask(text, usertypes.PromptMode.yesno,
default=True)
if confirmed: if confirmed:
e.accept() e.accept()
else: else:

View File

@ -23,7 +23,7 @@ from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QLineEdit from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtGui import QValidator from PyQt5.QtGui import QValidator
from qutebrowser.models.cmdhistory import History from qutebrowser.models import cmdhistory
class MinimalLineEditMixin: class MinimalLineEditMixin:
@ -55,7 +55,7 @@ class CommandLineEdit(QLineEdit):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.history = History() self.history = cmdhistory.History()
self._validator = _CommandValidator(self) self._validator = _CommandValidator(self)
self.setValidator(self._validator) self.setValidator(self._validator)
self.textEdited.connect(self.on_text_edited) self.textEdited.connect(self.on_text_edited)

View File

@ -19,27 +19,22 @@
"""The main statusbar widget.""" """The main statusbar widget."""
from collections import deque import collections
from datetime import datetime import datetime
from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt 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 from qutebrowser.keyinput import modeman
import qutebrowser.config.config as config from qutebrowser.config import config, style
from qutebrowser.utils import usertypes
from qutebrowser.utils.log import statusbar as logger from qutebrowser.utils.log import statusbar as logger
from qutebrowser.widgets.statusbar.command import Command from qutebrowser.widgets.statusbar import (command, progress, keystring,
from qutebrowser.widgets.statusbar.progress import Progress percentage, url, prompt)
from qutebrowser.widgets.statusbar.text import Text from qutebrowser.widgets.statusbar import text as textwidget
from qutebrowser.widgets.statusbar.keystring import KeyString
from qutebrowser.widgets.statusbar.percentage import Percentage
from qutebrowser.widgets.statusbar.url import UrlText
from qutebrowser.widgets.statusbar.prompt import Prompt
from qutebrowser.config.style import set_register_stylesheet, get_stylesheet
from qutebrowser.utils.usertypes import Timer, KeyMode, enum
PreviousWidget = enum('PreviousWidget', 'none', 'prompt', 'command') PreviousWidget = usertypes.enum('PreviousWidget', 'none', 'prompt', 'command')
class StatusBar(QWidget): class StatusBar(QWidget):
@ -128,7 +123,7 @@ class StatusBar(QWidget):
super().__init__(parent) super().__init__(parent)
self.setObjectName(self.__class__.__name__) self.setObjectName(self.__class__.__name__)
self.setAttribute(Qt.WA_StyledBackground) self.setAttribute(Qt.WA_StyledBackground)
set_register_stylesheet(self) style.set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
@ -143,18 +138,18 @@ class StatusBar(QWidget):
self._hbox.addLayout(self._stack) self._hbox.addLayout(self._stack)
self._stack.setContentsMargins(0, 0, 0, 0) self._stack.setContentsMargins(0, 0, 0, 0)
self.cmd = Command() self.cmd = command.Command()
self._stack.addWidget(self.cmd) self._stack.addWidget(self.cmd)
self.txt = Text() self.txt = textwidget.Text()
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 = collections.deque()
self._text_pop_timer = Timer(self, 'statusbar_text_pop') self._text_pop_timer = usertypes.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)
self.prompt = Prompt() self.prompt = prompt.Prompt()
self._stack.addWidget(self.prompt) self._stack.addWidget(self.prompt)
self._previous_widget = PreviousWidget.none self._previous_widget = PreviousWidget.none
@ -165,19 +160,19 @@ class StatusBar(QWidget):
self.prompt.hide_prompt.connect(self._hide_prompt_widget) self.prompt.hide_prompt.connect(self._hide_prompt_widget)
self._hide_prompt_widget() self._hide_prompt_widget()
self.keystring = KeyString() self.keystring = keystring.KeyString()
self._hbox.addWidget(self.keystring) self._hbox.addWidget(self.keystring)
self.url = UrlText() self.url = url.UrlText()
self._hbox.addWidget(self.url) self._hbox.addWidget(self.url)
self.percentage = Percentage() self.percentage = percentage.Percentage()
self._hbox.addWidget(self.percentage) self._hbox.addWidget(self.percentage)
# We add a parent to Progress here because it calls self.show() based # We add a parent to Progress here because it calls self.show() based
# on some signals, and if that happens before it's added to the layout, # on some signals, and if that happens before it's added to the layout,
# it will quickly blink up as independent window. # it will quickly blink up as independent window.
self.prog = Progress(self) self.prog = progress.Progress(self)
self._hbox.addWidget(self.prog) self._hbox.addWidget(self.prog)
def __repr__(self): def __repr__(self):
@ -198,7 +193,7 @@ class StatusBar(QWidget):
""" """
logger.debug("Setting error to {}".format(val)) logger.debug("Setting error to {}".format(val))
self._error = val self._error = val
self.setStyleSheet(get_stylesheet(self.STYLESHEET)) self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
if val: if val:
# If we got an error while command/prompt was shown, raise the text # If we got an error while command/prompt was shown, raise the text
# widget. # widget.
@ -219,7 +214,7 @@ class StatusBar(QWidget):
""" """
logger.debug("Setting prompt_active to {}".format(val)) logger.debug("Setting prompt_active to {}".format(val))
self._prompt_active = val self._prompt_active = val
self.setStyleSheet(get_stylesheet(self.STYLESHEET)) self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
@pyqtProperty(bool) @pyqtProperty(bool)
def insert_active(self): def insert_active(self):
@ -236,7 +231,7 @@ class StatusBar(QWidget):
""" """
logger.debug("Setting insert_active to {}".format(val)) logger.debug("Setting insert_active to {}".format(val))
self._insert_active = val self._insert_active = val
self.setStyleSheet(get_stylesheet(self.STYLESHEET)) self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
def _pop_text(self): def _pop_text(self):
"""Display a text in the statusbar and pop it from _text_queue.""" """Display a text in the statusbar and pop it from _text_queue."""
@ -316,7 +311,7 @@ class StatusBar(QWidget):
""" """
# FIXME probably using a QTime here would be easier. # FIXME probably using a QTime here would be easier.
logger.debug("Displaying text: {} (error={})".format(text, error)) logger.debug("Displaying text: {} (error={})".format(text, error))
now = datetime.now() now = datetime.datetime.now()
mindelta = config.get('ui', 'message-timeout') mindelta = config.get('ui', 'message-timeout')
delta = (None if self._last_text_time is None delta = (None if self._last_text_time is None
else now - self._last_text_time) else now - self._last_text_time)
@ -379,20 +374,20 @@ class StatusBar(QWidget):
"""Set a normal (persistent) text in the status bar.""" """Set a normal (persistent) text in the status bar."""
self.txt.normaltext = val self.txt.normaltext = val
@pyqtSlot(KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_entered(self, mode): def on_mode_entered(self, mode):
"""Mark certain modes in the commandline.""" """Mark certain modes in the commandline."""
if mode in modeman.instance().passthrough: if mode in modeman.instance().passthrough:
self.txt.normaltext = "-- {} MODE --".format(mode.name.upper()) self.txt.normaltext = "-- {} MODE --".format(mode.name.upper())
if mode == KeyMode.insert: if mode == usertypes.KeyMode.insert:
self.insert_active = True self.insert_active = True
@pyqtSlot(KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode): def on_mode_left(self, mode):
"""Clear marked mode.""" """Clear marked mode."""
if mode in modeman.instance().passthrough: if mode in modeman.instance().passthrough:
self.txt.normaltext = "" self.txt.normaltext = ""
if mode == KeyMode.insert: if mode == usertypes.KeyMode.insert:
self.insert_active = False self.insert_active = False
@pyqtSlot(str, str) @pyqtSlot(str, str)

View File

@ -22,19 +22,17 @@
from PyQt5.QtCore import pyqtSignal, pyqtSlot from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QSizePolicy, QApplication from PyQt5.QtWidgets import QSizePolicy, QApplication
import qutebrowser.keyinput.modeman as modeman from qutebrowser.keyinput import modeman, modeparsers
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import runners
from qutebrowser.widgets.misc import MinimalLineEditMixin, CommandLineEdit from qutebrowser.commands import utils as cmdutils
from qutebrowser.commands.runners import CommandRunner from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.keyinput.modeparsers import STARTCHARS from qutebrowser.widgets import misc
from qutebrowser.models import cmdhistory
from qutebrowser.utils import usertypes
from qutebrowser.utils.log import completion as logger from qutebrowser.utils.log import completion as logger
from qutebrowser.models.cmdhistory import (HistoryEmptyError,
HistoryEndReachedError)
from qutebrowser.commands.exceptions import CommandError
from qutebrowser.utils.usertypes import KeyMode
class Command(MinimalLineEditMixin, CommandLineEdit): class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
"""The commandline part of the statusbar. """The commandline part of the statusbar.
@ -76,8 +74,8 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
# for a possible fix. # for a possible fix.
def __init__(self, parent=None): def __init__(self, parent=None):
CommandLineEdit.__init__(self, parent) misc.CommandLineEdit.__init__(self, parent)
MinimalLineEditMixin.__init__(self) misc.MinimalLineEditMixin.__init__(self)
self.cursor_part = 0 self.cursor_part = 0
self.history.history = QApplication.instance().cmd_history.data self.history.history = QApplication.instance().cmd_history.data
self._empty_item_idx = None self._empty_item_idx = None
@ -92,7 +90,7 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
text = self.text() text = self.text()
if not text: if not text:
return '' return ''
elif text[0] in STARTCHARS: elif text[0] in modeparsers.STARTCHARS:
return text[0] return text[0]
else: else:
return '' return ''
@ -109,7 +107,7 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
# Text is only whitespace so we treat this as a single element with # Text is only whitespace so we treat this as a single element with
# the whitespace. # the whitespace.
return [text] return [text]
runner = CommandRunner() runner = runners.CommandRunner()
parts = runner.parse(text, fallback=True, alias_no_args=False) parts = runner.parse(text, fallback=True, alias_no_args=False)
if self._empty_item_idx is not None: if self._empty_item_idx is not None:
logger.debug("Empty element queued at {}, inserting.".format( logger.debug("Empty element queued at {}, inserting.".format(
@ -179,8 +177,9 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
strings: A list of strings to set. strings: A list of strings to set.
""" """
text = ' '.join(strings) text = ' '.join(strings)
if not text[0] in STARTCHARS: if not text[0] in modeparsers.STARTCHARS:
raise CommandError("Invalid command text '{}'.".format(text)) raise cmdexc.CommandError(
"Invalid command text '{}'.".format(text))
self.set_cmd_text(text) self.set_cmd_text(text)
@pyqtSlot(str, bool) @pyqtSlot(str, bool)
@ -215,7 +214,7 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
self.show_cmd.emit() self.show_cmd.emit()
@cmdutils.register(instance='mainwindow.status.cmd', hide=True, @cmdutils.register(instance='mainwindow.status.cmd', hide=True,
modes=[KeyMode.command]) modes=[usertypes.KeyMode.command])
def command_history_prev(self): def command_history_prev(self):
"""Go back in the commandline history.""" """Go back in the commandline history."""
try: try:
@ -223,26 +222,27 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
item = self.history.start(self.text().strip()) item = self.history.start(self.text().strip())
else: else:
item = self.history.previtem() item = self.history.previtem()
except (HistoryEmptyError, HistoryEndReachedError): except (cmdhistory.HistoryEmptyError,
cmdhistory.HistoryEndReachedError):
return return
if item: if item:
self.set_cmd_text(item) self.set_cmd_text(item)
@cmdutils.register(instance='mainwindow.status.cmd', hide=True, @cmdutils.register(instance='mainwindow.status.cmd', hide=True,
modes=[KeyMode.command]) modes=[usertypes.KeyMode.command])
def command_history_next(self): def command_history_next(self):
"""Go forward in the commandline history.""" """Go forward in the commandline history."""
if not self.history.browsing: if not self.history.browsing:
return return
try: try:
item = self.history.nextitem() item = self.history.nextitem()
except HistoryEndReachedError: except cmdhistory.HistoryEndReachedError:
return return
if item: if item:
self.set_cmd_text(item) self.set_cmd_text(item)
@cmdutils.register(instance='mainwindow.status.cmd', hide=True, @cmdutils.register(instance='mainwindow.status.cmd', hide=True,
modes=[KeyMode.command]) modes=[usertypes.KeyMode.command])
def command_accept(self): def command_accept(self):
"""Execute the command currently in the commandline. """Execute the command currently in the commandline.
@ -258,7 +258,7 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
} }
text = self.text() text = self.text()
self.history.append(text) self.history.append(text)
modeman.leave(KeyMode.command, 'cmd accept') modeman.leave(usertypes.KeyMode.command, 'cmd accept')
if text[0] in signals: if text[0] in signals:
signals[text[0]].emit(text.lstrip(text[0])) signals[text[0]].emit(text.lstrip(text[0]))
@ -271,7 +271,7 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
# here, but that's already done for us by cursorPositionChanged # here, but that's already done for us by cursorPositionChanged
# anyways, so we don't need to do it twice. # anyways, so we don't need to do it twice.
@pyqtSlot(KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode): def on_mode_left(self, mode):
"""Clear up when ommand mode was left. """Clear up when ommand mode was left.
@ -286,7 +286,7 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
clear_completion_selection: Always emitted. clear_completion_selection: Always emitted.
hide_completion: Always emitted so the completion is hidden. hide_completion: Always emitted so the completion is hidden.
""" """
if mode == KeyMode.command: if mode == usertypes.KeyMode.command:
self.setText('') self.setText('')
self.history.stop() self.history.stop()
self.hide_cmd.emit() self.hide_cmd.emit()
@ -295,14 +295,14 @@ class Command(MinimalLineEditMixin, CommandLineEdit):
def focusInEvent(self, e): def focusInEvent(self, e):
"""Extend focusInEvent to enter command mode.""" """Extend focusInEvent to enter command mode."""
modeman.maybe_enter(KeyMode.command, 'cmd focus') modeman.maybe_enter(usertypes.KeyMode.command, 'cmd focus')
super().focusInEvent(e) super().focusInEvent(e)
def setText(self, text): def setText(self, text):
"""Extend setText to set prefix and make sure the prompt is ok.""" """Extend setText to set prefix and make sure the prompt is ok."""
if not text: if not text:
pass pass
elif text[0] in STARTCHARS: elif text[0] in modeparsers.STARTCHARS:
super().set_prompt(text[0]) super().set_prompt(text[0])
else: else:
raise AssertionError("setText got called with invalid text " raise AssertionError("setText got called with invalid text "

View File

@ -19,10 +19,10 @@
"""Keychain string displayed in the statusbar.""" """Keychain string displayed in the statusbar."""
from qutebrowser.widgets.statusbar.textbase import TextBase from qutebrowser.widgets.statusbar import textbase
class KeyString(TextBase): class KeyString(textbase.TextBase):
"""Keychain string displayed in the statusbar.""" """Keychain string displayed in the statusbar."""

View File

@ -21,10 +21,10 @@
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot
from qutebrowser.widgets.statusbar.textbase import TextBase from qutebrowser.widgets.statusbar import textbase
class Percentage(TextBase): class Percentage(textbase.TextBase):
"""Reading percentage displayed in the statusbar.""" """Reading percentage displayed in the statusbar."""

View File

@ -22,8 +22,8 @@
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QProgressBar, QSizePolicy from PyQt5.QtWidgets import QProgressBar, QSizePolicy
from qutebrowser.widgets.webview import LoadStatus from qutebrowser.widgets import webview
from qutebrowser.config.style import set_register_stylesheet from qutebrowser.config import style
class Progress(QProgressBar): class Progress(QProgressBar):
@ -50,7 +50,7 @@ class Progress(QProgressBar):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
set_register_stylesheet(self) style.set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Ignored) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Ignored)
self.setTextVisible(False) self.setTextVisible(False)
self.hide() self.hide()
@ -72,7 +72,7 @@ class Progress(QProgressBar):
# sometimes. # sometimes.
return return
self.setValue(tab.progress) self.setValue(tab.progress)
if tab.load_status == LoadStatus.loading: if tab.load_status == webview.LoadStatus.loading:
self.show() self.show()
else: else:
self.hide() self.hide()

View File

@ -22,18 +22,17 @@
from PyQt5.QtCore import pyqtSignal from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit
from qutebrowser.widgets.misc import MinimalLineEditMixin from qutebrowser.widgets import misc
from qutebrowser.widgets.statusbar.textbase import TextBase from qutebrowser.widgets.statusbar import textbase, prompter
from qutebrowser.widgets.statusbar.prompter import Prompter
class PromptLineEdit(MinimalLineEditMixin, QLineEdit): class PromptLineEdit(misc.MinimalLineEditMixin, QLineEdit):
"""QLineEdit with a minimal stylesheet.""" """QLineEdit with a minimal stylesheet."""
def __init__(self, parent=None): def __init__(self, parent=None):
QLineEdit.__init__(self, parent) QLineEdit.__init__(self, parent)
MinimalLineEditMixin.__init__(self) misc.MinimalLineEditMixin.__init__(self)
class Prompt(QWidget): class Prompt(QWidget):
@ -60,13 +59,13 @@ class Prompt(QWidget):
self._hbox.setContentsMargins(0, 0, 0, 0) self._hbox.setContentsMargins(0, 0, 0, 0)
self._hbox.setSpacing(5) self._hbox.setSpacing(5)
self.txt = TextBase() self.txt = textbase.TextBase()
self._hbox.addWidget(self.txt) self._hbox.addWidget(self.txt)
self.lineedit = PromptLineEdit() self.lineedit = PromptLineEdit()
self._hbox.addWidget(self.lineedit) self._hbox.addWidget(self.lineedit)
self.prompter = Prompter(self) self.prompter = prompter.Prompter(self)
def __repr__(self): def __repr__(self):
return '<{}>'.format(self.__class__.__name__) return '<{}>'.format(self.__class__.__name__)

View File

@ -19,20 +19,21 @@
"""Manager for questions to be shown in the statusbar.""" """Manager for questions to be shown in the statusbar."""
from collections import namedtuple, deque import collections
from PyQt5.QtCore import pyqtSlot, QTimer from PyQt5.QtCore import pyqtSlot, QTimer
from PyQt5.QtWidgets import QLineEdit from PyQt5.QtWidgets import QLineEdit
import qutebrowser.keyinput.modeman as modeman from qutebrowser.keyinput import modeman
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import utils as cmdutils
from qutebrowser.utils.usertypes import PromptMode, Question, KeyMode from qutebrowser.utils import usertypes
from qutebrowser.utils.qt import EventLoop from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.log import statusbar as logger from qutebrowser.utils.log import statusbar as logger
PromptContext = namedtuple('PromptContext', ['question', 'text', 'input_text', PromptContext = collections.namedtuple('PromptContext',
'echo_mode', 'input_visible']) ['question', 'text', 'input_text',
'echo_mode', 'input_visible'])
class Prompter: class Prompter:
@ -67,7 +68,7 @@ class Prompter:
def __init__(self, prompt): def __init__(self, prompt):
self.question = None self.question = None
self._loops = [] self._loops = []
self._queue = deque() self._queue = collections.deque()
self._busy = False self._busy = False
self._prompt = prompt self._prompt = prompt
@ -124,7 +125,7 @@ class Prompter:
Raise: Raise:
ValueError if the set PromptMode is invalid. ValueError if the set PromptMode is invalid.
""" """
if self.question.mode == PromptMode.yesno: if self.question.mode == usertypes.PromptMode.yesno:
if self.question.default is None: if self.question.default is None:
suffix = "" suffix = ""
elif self.question.default: elif self.question.default:
@ -133,23 +134,23 @@ class Prompter:
suffix = " (no)" suffix = " (no)"
self._prompt.txt.setText(self.question.text + suffix) self._prompt.txt.setText(self.question.text + suffix)
self._prompt.lineedit.hide() self._prompt.lineedit.hide()
mode = KeyMode.yesno mode = usertypes.KeyMode.yesno
elif self.question.mode == PromptMode.text: elif self.question.mode == usertypes.PromptMode.text:
self._prompt.txt.setText(self.question.text) self._prompt.txt.setText(self.question.text)
if self.question.default: if self.question.default:
self._prompt.lineedit.setText(self.question.default) self._prompt.lineedit.setText(self.question.default)
self._prompt.lineedit.show() self._prompt.lineedit.show()
mode = KeyMode.prompt mode = usertypes.KeyMode.prompt
elif self.question.mode == PromptMode.user_pwd: elif self.question.mode == usertypes.PromptMode.user_pwd:
self._prompt.txt.setText(self.question.text) self._prompt.txt.setText(self.question.text)
if self.question.default: if self.question.default:
self._prompt.lineedit.setText(self.question.default) self._prompt.lineedit.setText(self.question.default)
self._prompt.lineedit.show() self._prompt.lineedit.show()
mode = KeyMode.prompt mode = usertypes.KeyMode.prompt
elif self.question.mode == PromptMode.alert: elif self.question.mode == usertypes.PromptMode.alert:
self._prompt.txt.setText(self.question.text + ' (ok)') self._prompt.txt.setText(self.question.text + ' (ok)')
self._prompt.lineedit.hide() self._prompt.lineedit.hide()
mode = KeyMode.prompt mode = usertypes.KeyMode.prompt
else: else:
raise ValueError("Invalid prompt mode!") raise ValueError("Invalid prompt mode!")
self._prompt.lineedit.setFocus() self._prompt.lineedit.setFocus()
@ -174,10 +175,10 @@ class Prompter:
else: else:
return False return False
@pyqtSlot(KeyMode) @pyqtSlot(usertypes.KeyMode)
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."""
if mode in (KeyMode.prompt, KeyMode.yesno): if mode in (usertypes.KeyMode.prompt, usertypes.KeyMode.yesno):
self._prompt.txt.setText('') self._prompt.txt.setText('')
self._prompt.lineedit.clear() self._prompt.lineedit.clear()
self._prompt.lineedit.setEchoMode(QLineEdit.Normal) self._prompt.lineedit.setEchoMode(QLineEdit.Normal)
@ -187,7 +188,8 @@ class Prompter:
self.question.cancel() self.question.cancel()
@cmdutils.register(instance='mainwindow.status.prompt.prompter', hide=True, @cmdutils.register(instance='mainwindow.status.prompt.prompter', hide=True,
modes=[KeyMode.prompt, KeyMode.yesno]) modes=[usertypes.KeyMode.prompt,
usertypes.KeyMode.yesno])
def prompt_accept(self): def prompt_accept(self):
"""Accept the current prompt. """Accept the current prompt.
@ -196,60 +198,60 @@ class Prompter:
This executes the next action depending on the question mode, e.g. asks This executes the next action depending on the question mode, e.g. asks
for the password or leaves the mode. for the password or leaves the mode.
""" """
if (self.question.mode == PromptMode.user_pwd and if (self.question.mode == usertypes.PromptMode.user_pwd and
self.question.user is None): self.question.user is None):
# User just entered an username # User just entered an username
self.question.user = self._prompt.lineedit.text() self.question.user = self._prompt.lineedit.text()
self._prompt.txt.setText("Password:") self._prompt.txt.setText("Password:")
self._prompt.lineedit.clear() self._prompt.lineedit.clear()
self._prompt.lineedit.setEchoMode(QLineEdit.Password) self._prompt.lineedit.setEchoMode(QLineEdit.Password)
elif self.question.mode == PromptMode.user_pwd: elif self.question.mode == usertypes.PromptMode.user_pwd:
# User just entered a password # User just entered a password
password = self._prompt.lineedit.text() password = self._prompt.lineedit.text()
self.question.answer = (self.question.user, password) self.question.answer = (self.question.user, password)
modeman.leave(KeyMode.prompt, 'prompt accept') modeman.leave(usertypes.KeyMode.prompt, 'prompt accept')
self.question.done() self.question.done()
elif self.question.mode == PromptMode.text: elif self.question.mode == usertypes.PromptMode.text:
# User just entered text. # User just entered text.
self.question.answer = self._prompt.lineedit.text() self.question.answer = self._prompt.lineedit.text()
modeman.leave(KeyMode.prompt, 'prompt accept') modeman.leave(usertypes.KeyMode.prompt, 'prompt accept')
self.question.done() self.question.done()
elif self.question.mode == PromptMode.yesno: elif self.question.mode == usertypes.PromptMode.yesno:
# User wants to accept the default of a yes/no question. # User wants to accept the default of a yes/no question.
self.question.answer = self.question.default self.question.answer = self.question.default
modeman.leave(KeyMode.yesno, 'yesno accept') modeman.leave(usertypes.KeyMode.yesno, 'yesno accept')
self.question.done() self.question.done()
elif self.question.mode == PromptMode.alert: elif self.question.mode == usertypes.PromptMode.alert:
# User acknowledged an alert # User acknowledged an alert
self.question.answer = None self.question.answer = None
modeman.leave(KeyMode.prompt, 'alert accept') modeman.leave(usertypes.KeyMode.prompt, 'alert accept')
self.question.done() self.question.done()
else: else:
raise ValueError("Invalid question mode!") raise ValueError("Invalid question mode!")
@cmdutils.register(instance='mainwindow.status.prompt.prompter', hide=True, @cmdutils.register(instance='mainwindow.status.prompt.prompter', hide=True,
modes=[KeyMode.yesno]) modes=[usertypes.KeyMode.yesno])
def prompt_yes(self): def prompt_yes(self):
"""Answer yes to a yes/no prompt.""" """Answer yes to a yes/no prompt."""
if self.question.mode != PromptMode.yesno: if self.question.mode != usertypes.PromptMode.yesno:
# We just ignore this if we don't have a yes/no question. # We just ignore this if we don't have a yes/no question.
return return
self.question.answer = True self.question.answer = True
modeman.leave(KeyMode.yesno, 'yesno accept') modeman.leave(usertypes.KeyMode.yesno, 'yesno accept')
self.question.done() self.question.done()
@cmdutils.register(instance='mainwindow.status.prompt.prompter', hide=True, @cmdutils.register(instance='mainwindow.status.prompt.prompter', hide=True,
modes=[KeyMode.yesno]) modes=[usertypes.KeyMode.yesno])
def prompt_no(self): def prompt_no(self):
"""Answer no to a yes/no prompt.""" """Answer no to a yes/no prompt."""
if self.question.mode != PromptMode.yesno: if self.question.mode != usertypes.PromptMode.yesno:
# We just ignore this if we don't have a yes/no question. # We just ignore this if we don't have a yes/no question.
return return
self.question.answer = False self.question.answer = False
modeman.leave(KeyMode.yesno, 'prompt accept') modeman.leave(usertypes.KeyMode.yesno, 'prompt accept')
self.question.done() self.question.done()
@pyqtSlot(Question, bool) @pyqtSlot(usertypes.Question, bool)
def ask_question(self, question, blocking): def ask_question(self, question, blocking):
"""Dispkay a question in the statusbar. """Dispkay a question in the statusbar.
@ -282,12 +284,12 @@ class Prompter:
try: try:
modeman.enter(mode, 'question asked') modeman.enter(mode, 'question asked')
except modeman.ModeLockedError: except modeman.ModeLockedError:
if modeman.instance().mode != KeyMode.prompt: if modeman.instance().mode != usertypes.KeyMode.prompt:
question.abort() question.abort()
return None return None
modeman.instance().locked = True modeman.instance().locked = True
if blocking: if blocking:
loop = EventLoop() loop = qtutils.EventLoop()
self._loops.append(loop) self._loops.append(loop)
loop.destroyed.connect(lambda: self._loops.remove(loop)) loop.destroyed.connect(lambda: self._loops.remove(loop))
question.completed.connect(loop.quit) question.completed.connect(loop.quit)

View File

@ -21,11 +21,11 @@
from PyQt5.QtCore import pyqtSlot from PyQt5.QtCore import pyqtSlot
import qutebrowser.config.config as config from qutebrowser.config import config
from qutebrowser.widgets.statusbar.textbase import TextBase from qutebrowser.widgets.statusbar import textbase
class Text(TextBase): class Text(textbase.TextBase):
"""Text displayed in the statusbar. """Text displayed in the statusbar.

View File

@ -23,7 +23,7 @@ from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QLabel, QSizePolicy from PyQt5.QtWidgets import QLabel, QSizePolicy
from PyQt5.QtGui import QPainter from PyQt5.QtGui import QPainter
from qutebrowser.utils.qt import qt_ensure_valid from qutebrowser.utils import qt as qtutils
class TextBase(QLabel): class TextBase(QLabel):
@ -79,7 +79,7 @@ class TextBase(QLabel):
"""Extend QLabel::resizeEvent to update the elided text afterwards.""" """Extend QLabel::resizeEvent to update the elided text afterwards."""
super().resizeEvent(e) super().resizeEvent(e)
size = e.size() size = e.size()
qt_ensure_valid(size) qtutils.qt_ensure_valid(size)
self._update_elided_text(size.width()) self._update_elided_text(size.width())
def paintEvent(self, e): def paintEvent(self, e):
@ -90,6 +90,6 @@ class TextBase(QLabel):
e.accept() e.accept()
painter = QPainter(self) painter = QPainter(self)
geom = self.geometry() geom = self.geometry()
qt_ensure_valid(geom) qtutils.qt_ensure_valid(geom)
painter.drawText(0, 0, geom.width(), geom.height(), painter.drawText(0, 0, geom.width(), geom.height(),
self.alignment(), self._elided_text) self.alignment(), self._elided_text)

View File

@ -21,17 +21,18 @@
from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt
from qutebrowser.widgets.webview import LoadStatus from qutebrowser.widgets import webview
from qutebrowser.widgets.statusbar.textbase import TextBase from qutebrowser.widgets.statusbar import textbase
from qutebrowser.config.style import set_register_stylesheet, get_stylesheet from qutebrowser.config import style
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import usertypes
# Note this has entries for success/error/warn from widgets.webview:LoadStatus # Note this has entries for success/error/warn from widgets.webview:LoadStatus
UrlType = enum('UrlType', 'success', 'error', 'warn', 'hover', 'normal') UrlType = usertypes.enum('UrlType', 'success', 'error', 'warn', 'hover',
'normal')
class UrlText(TextBase): class UrlText(textbase.TextBase):
"""URL displayed in the statusbar. """URL displayed in the statusbar.
@ -80,7 +81,7 @@ class UrlText(TextBase):
"""Override TextBase.__init__ to elide in the middle by default.""" """Override TextBase.__init__ to elide in the middle by default."""
super().__init__(parent, Qt.ElideMiddle) super().__init__(parent, Qt.ElideMiddle)
self.setObjectName(self.__class__.__name__) self.setObjectName(self.__class__.__name__)
set_register_stylesheet(self) style.set_register_stylesheet(self)
self._hover_url = None self._hover_url = None
self._normal_url = None self._normal_url = None
self._normal_url_type = UrlType.normal self._normal_url_type = UrlType.normal
@ -104,7 +105,7 @@ class UrlText(TextBase):
if not isinstance(val, UrlType): if not isinstance(val, UrlType):
raise TypeError("Type {} is no UrlType member!".format(val)) raise TypeError("Type {} is no UrlType member!".format(val))
self._urltype = val self._urltype = val
self.setStyleSheet(get_stylesheet(self.STYLESHEET)) self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
@property @property
def hover_url(self): def hover_url(self):
@ -164,8 +165,9 @@ class UrlText(TextBase):
Args: Args:
status_str: The LoadStatus as string. status_str: The LoadStatus as string.
""" """
status = LoadStatus[status_str] status = webview.LoadStatus[status_str]
if status in (LoadStatus.success, LoadStatus.error, LoadStatus.warn): if status in (webview.LoadStatus.success, webview.LoadStatus.error,
webview.LoadStatus.warn):
self.normal_url_type = UrlType[status_str] self.normal_url_type = UrlType[status_str]
else: else:
self.normal_url_type = UrlType.normal self.normal_url_type = UrlType.normal

View File

@ -19,29 +19,25 @@
"""The main tabbed browser widget.""" """The main tabbed browser widget."""
from functools import partial import functools
from PyQt5.QtWidgets import QSizePolicy from PyQt5.QtWidgets import QSizePolicy
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QSize, QTimer from PyQt5.QtCore import pyqtSignal, pyqtSlot, QSize, QTimer
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtWebKitWidgets import QWebPage from PyQt5.QtWebKitWidgets import QWebPage
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.commands.utils as cmdutils from qutebrowser.commands import utils as cmdutils
import qutebrowser.keyinput.modeman as modeman from qutebrowser.commands import exceptions as cmdexc
import qutebrowser.utils.log as log from qutebrowser.keyinput import modeman
import qutebrowser.utils.misc as utils from qutebrowser.widgets import tabwidget, webview
import qutebrowser.utils.message as message from qutebrowser.browser import signalfilter, commands
from qutebrowser.widgets.tabwidget import TabWidget from qutebrowser.utils import log, message, usertypes
from qutebrowser.widgets.webview import WebView from qutebrowser.utils import misc as utils
from qutebrowser.browser.signalfilter import SignalFilter from qutebrowser.utils import qt as qtutils
from qutebrowser.browser.commands import CommandDispatcher
from qutebrowser.utils.qt import qt_ensure_valid, QtValueError
from qutebrowser.commands.exceptions import CommandError
from qutebrowser.utils.usertypes import KeyMode
class TabbedBrowser(TabWidget): class TabbedBrowser(tabwidget.TabWidget):
"""A TabWidget with QWebViews inside. """A TabWidget with QWebViews inside.
@ -104,7 +100,7 @@ class TabbedBrowser(TabWidget):
quit = pyqtSignal() quit = pyqtSignal()
resized = pyqtSignal('QRect') resized = pyqtSignal('QRect')
got_cmd = pyqtSignal(str) got_cmd = pyqtSignal(str)
current_tab_changed = pyqtSignal(WebView) current_tab_changed = pyqtSignal(webview.WebView)
title_changed = pyqtSignal(str) title_changed = pyqtSignal(str)
def __init__(self, parent=None): def __init__(self, parent=None):
@ -116,8 +112,8 @@ class TabbedBrowser(TabWidget):
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self._tabs = [] self._tabs = []
self.url_stack = [] self.url_stack = []
self._filter = SignalFilter(self) self._filter = signalfilter.SignalFilter(self)
self.cmd = CommandDispatcher(self) self.cmd = commands.CommandDispatcher(self)
self.last_focused = None self.last_focused = None
self._now_focused = None self._now_focused = None
# FIXME adjust this to font size # FIXME adjust this to font size
@ -159,7 +155,8 @@ class TabbedBrowser(TabWidget):
self._filter.create(self.cur_url_text_changed, tab)) self._filter.create(self.cur_url_text_changed, tab))
tab.load_status_changed.connect( tab.load_status_changed.connect(
self._filter.create(self.cur_load_status_changed, tab)) self._filter.create(self.cur_load_status_changed, tab))
tab.url_text_changed.connect(partial(self.on_url_text_changed, tab)) tab.url_text_changed.connect(
functools.partial(self.on_url_text_changed, tab))
# hintmanager # hintmanager
tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated) tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated)
tab.hintmanager.download_get.connect(self.download_get) tab.hintmanager.download_get.connect(self.download_get)
@ -168,13 +165,18 @@ class TabbedBrowser(TabWidget):
# downloads # downloads
page.start_download.connect(self.start_download) page.start_download.connect(self.start_download)
# misc # misc
tab.titleChanged.connect(partial(self.on_title_changed, tab)) tab.titleChanged.connect(
tab.iconChanged.connect(partial(self.on_icon_changed, tab)) functools.partial(self.on_title_changed, tab))
tab.loadProgress.connect(partial(self.on_load_progress, tab)) tab.iconChanged.connect(
frame.loadFinished.connect(partial(self.on_load_finished, tab)) functools.partial(self.on_icon_changed, tab))
frame.loadStarted.connect(partial(self.on_load_started, tab)) tab.loadProgress.connect(
functools.partial(self.on_load_progress, tab))
frame.loadFinished.connect(
functools.partial(self.on_load_finished, tab))
frame.loadStarted.connect(
functools.partial(self.on_load_started, tab))
page.windowCloseRequested.connect( page.windowCloseRequested.connect(
partial(self.on_window_close_requested, tab)) functools.partial(self.on_window_close_requested, tab))
def cntwidget(self, count=None): def cntwidget(self, count=None):
"""Return a widget based on a count/idx. """Return a widget based on a count/idx.
@ -208,13 +210,13 @@ class TabbedBrowser(TabWidget):
""" """
url = self.currentWidget().cur_url url = self.currentWidget().cur_url
try: try:
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
except QtValueError as e: except qtutils.QtValueError as e:
msg = "Current URL is invalid" msg = "Current URL is invalid"
if e.reason: if e.reason:
msg += " ({})".format(e.reason) msg += " ({})".format(e.reason)
msg += "!" msg += "!"
raise CommandError(msg) raise cmdexc.CommandError(msg)
return url return url
def shutdown(self): def shutdown(self):
@ -264,7 +266,7 @@ class TabbedBrowser(TabWidget):
if tab is self.last_focused: if tab is self.last_focused:
self.last_focused = None self.last_focused = None
if not tab.cur_url.isEmpty(): if not tab.cur_url.isEmpty():
qt_ensure_valid(tab.cur_url) qtutils.qt_ensure_valid(tab.cur_url)
self.url_stack.append(tab.cur_url) self.url_stack.append(tab.cur_url)
tab.shutdown() tab.shutdown()
self._tabs.remove(tab) self._tabs.remove(tab)
@ -279,7 +281,7 @@ class TabbedBrowser(TabWidget):
url: The URL to open as QUrl. url: The URL to open as QUrl.
newtab: True to open URL in a new tab, False otherwise. newtab: True to open URL in a new tab, False otherwise.
""" """
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
if newtab: if newtab:
self.tabopen(url, background=False) self.tabopen(url, background=False)
else: else:
@ -295,7 +297,7 @@ class TabbedBrowser(TabWidget):
return return
self.close_tab(tab) self.close_tab(tab)
@pyqtSlot(WebView) @pyqtSlot(webview.WebView)
def on_window_close_requested(self, widget): def on_window_close_requested(self, widget):
"""Close a tab with a widget given.""" """Close a tab with a widget given."""
self.close_tab(widget) self.close_tab(widget)
@ -322,9 +324,9 @@ class TabbedBrowser(TabWidget):
The opened WebView instance. The opened WebView instance.
""" """
if url is not None: if url is not None:
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
log.webview.debug("Creating new tab with URL {}".format(url)) log.webview.debug("Creating new tab with URL {}".format(url))
tab = WebView(self) tab = webview.WebView(self)
self._connect_tab_signals(tab) self._connect_tab_signals(tab)
self._tabs.append(tab) self._tabs.append(tab)
if explicit: if explicit:
@ -440,10 +442,10 @@ class TabbedBrowser(TabWidget):
@pyqtSlot() @pyqtSlot()
def on_cur_load_started(self): def on_cur_load_started(self):
"""Leave insert/hint mode when loading started.""" """Leave insert/hint mode when loading started."""
modeman.maybe_leave(KeyMode.insert, 'load started') modeman.maybe_leave(usertypes.KeyMode.insert, 'load started')
modeman.maybe_leave(KeyMode.hint, 'load started') modeman.maybe_leave(usertypes.KeyMode.hint, 'load started')
@pyqtSlot(WebView, str) @pyqtSlot(webview.WebView, str)
def on_title_changed(self, tab, text): def on_title_changed(self, tab, text):
"""Set the title of a tab. """Set the title of a tab.
@ -470,7 +472,7 @@ class TabbedBrowser(TabWidget):
if idx == self.currentIndex(): if idx == self.currentIndex():
self.title_changed.emit('{} - qutebrowser'.format(text)) self.title_changed.emit('{} - qutebrowser'.format(text))
@pyqtSlot(WebView, str) @pyqtSlot(webview.WebView, str)
def on_url_text_changed(self, tab, url): def on_url_text_changed(self, tab, url):
"""Set the new URL as title if there's no title yet. """Set the new URL as title if there's no title yet.
@ -490,7 +492,7 @@ class TabbedBrowser(TabWidget):
if not self.tabText(idx): if not self.tabText(idx):
self.setTabText(idx, url) self.setTabText(idx, url)
@pyqtSlot(WebView) @pyqtSlot(webview.WebView)
def on_icon_changed(self, tab): def on_icon_changed(self, tab):
"""Set the icon of a tab. """Set the icon of a tab.
@ -512,10 +514,10 @@ class TabbedBrowser(TabWidget):
return return
self.setTabIcon(idx, tab.icon()) self.setTabIcon(idx, tab.icon())
@pyqtSlot(KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode): def on_mode_left(self, mode):
"""Give focus to current tab if command mode was left.""" """Give focus to current tab if command mode was left."""
if mode == KeyMode.command: if mode == usertypes.KeyMode.command:
self.currentWidget().setFocus() self.currentWidget().setFocus()
@pyqtSlot(int) @pyqtSlot(int)
@ -523,7 +525,7 @@ class TabbedBrowser(TabWidget):
"""Set last_focused and leave hinting mode when focus changed.""" """Set last_focused and leave hinting mode when focus changed."""
tab = self.widget(idx) tab = self.widget(idx)
tab.setFocus() tab.setFocus()
modeman.maybe_leave(KeyMode.hint, 'tab changed') modeman.maybe_leave(usertypes.KeyMode.hint, 'tab changed')
self.last_focused = self._now_focused self.last_focused = self._now_focused
self._now_focused = tab self._now_focused = tab
self.current_tab_changed.emit(tab) self.current_tab_changed.emit(tab)

View File

@ -32,8 +32,8 @@ from PyQt5.QtWidgets import (QTabWidget, QTabBar, QSizePolicy, QCommonStyle,
QApplication) QApplication)
from PyQt5.QtGui import QIcon, QPalette, QColor from PyQt5.QtGui import QIcon, QPalette, QColor
from qutebrowser.utils.qt import qt_ensure_valid from qutebrowser.utils import qt as qtutils
import qutebrowser.config.config as config from qutebrowser.config import config
PM_TabBarPadding = QStyle.PM_CustomBase PM_TabBarPadding = QStyle.PM_CustomBase
@ -211,7 +211,7 @@ class TabBar(QTabBar):
# If we *do* have enough space, tabs should occupy the whole window # If we *do* have enough space, tabs should occupy the whole window
# width. # width.
size = QSize(self.width() / self.count(), height) size = QSize(self.width() / self.count(), height)
qt_ensure_valid(size) qtutils.qt_ensure_valid(size)
return size return size
def paintEvent(self, _e): def paintEvent(self, _e):
@ -311,7 +311,7 @@ class TabBarStyle(QCommonStyle):
elif element == QStyle.CE_TabBarTabLabel: elif element == QStyle.CE_TabBarTabLabel:
text_rect, icon_rect = self._tab_layout(opt) text_rect, icon_rect = self._tab_layout(opt)
if not opt.icon.isNull(): if not opt.icon.isNull():
qt_ensure_valid(icon_rect) qtutils.qt_ensure_valid(icon_rect)
icon_mode = (QIcon.Normal if opt.state & QStyle.State_Enabled icon_mode = (QIcon.Normal if opt.state & QStyle.State_Enabled
else QIcon.Disabled) else QIcon.Disabled)
icon_state = (QIcon.On if opt.state & QStyle.State_Selected icon_state = (QIcon.On if opt.state & QStyle.State_Selected
@ -382,7 +382,7 @@ class TabBarStyle(QCommonStyle):
padding = self.pixelMetric(PM_TabBarPadding, opt) padding = self.pixelMetric(PM_TabBarPadding, opt)
icon_rect = QRect() icon_rect = QRect()
text_rect = QRect(opt.rect) text_rect = QRect(opt.rect)
qt_ensure_valid(text_rect) qtutils.qt_ensure_valid(text_rect)
indicator_width = config.get('tabs', 'indicator-width') indicator_width = config.get('tabs', 'indicator-width')
text_rect.adjust(padding, 0, 0, 0) text_rect.adjust(padding, 0, 0, 0)
if indicator_width != 0: if indicator_width != 0:
@ -419,5 +419,5 @@ class TabBarStyle(QCommonStyle):
text_rect.center().y() - tab_icon_size.height() / 2, text_rect.center().y() - tab_icon_size.height() / 2,
tab_icon_size.width(), tab_icon_size.height()) tab_icon_size.width(), tab_icon_size.height())
icon_rect = self._style.visualRect(opt.direction, opt.rect, icon_rect) icon_rect = self._style.visualRect(opt.direction, opt.rect, icon_rect)
qt_ensure_valid(icon_rect) qtutils.qt_ensure_valid(icon_rect)
return icon_rect return icon_rect

View File

@ -24,21 +24,17 @@ from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView, QWebPage from PyQt5.QtWebKitWidgets import QWebView, QWebPage
import qutebrowser.config.config as config from qutebrowser.config import config
import qutebrowser.keyinput.modeman as modeman from qutebrowser.keyinput import modeman
import qutebrowser.utils.message as message from qutebrowser.utils import message, webelem, log, usertypes
import qutebrowser.utils.webelem as webelem from qutebrowser.utils import misc as utils
import qutebrowser.utils.log as log from qutebrowser.utils import qt as qtutils
from qutebrowser.utils.misc import elide from qutebrowser.browser import webpage, hints
from qutebrowser.utils.qt import qt_ensure_valid from qutebrowser.commands import exceptions as cmdexc
from qutebrowser.browser.webpage import BrowserPage
from qutebrowser.browser.hints import HintManager
from qutebrowser.utils.usertypes import (NeighborList, ClickTarget, KeyMode,
enum)
from qutebrowser.commands.exceptions import CommandError
LoadStatus = enum('LoadStatus', 'none', 'success', 'error', 'warn', 'loading') LoadStatus = usertypes.enum('LoadStatus', 'none', 'success', 'error', 'warn',
'loading')
class WebView(QWebView): class WebView(QWebView):
@ -93,7 +89,7 @@ class WebView(QWebView):
self.statusbar_message = '' self.statusbar_message = ''
self._old_scroll_pos = (-1, -1) self._old_scroll_pos = (-1, -1)
self._open_target = None self._open_target = None
self.open_target = ClickTarget.normal self.open_target = usertypes.ClickTarget.normal
self._force_open_target = None self._force_open_target = None
self._zoom = None self._zoom = None
self._has_ssl_errors = False self._has_ssl_errors = False
@ -101,9 +97,9 @@ class WebView(QWebView):
self._cur_url = None self._cur_url = None
self.cur_url = QUrl() self.cur_url = QUrl()
self.progress = 0 self.progress = 0
self._page = BrowserPage(self) self._page = webpage.BrowserPage(self)
self.setPage(self._page) self.setPage(self._page)
self.hintmanager = HintManager(self) self.hintmanager = hints.HintManager(self)
self.hintmanager.mouse_event.connect(self.on_mouse_event) self.hintmanager.mouse_event.connect(self.on_mouse_event)
self.hintmanager.set_open_target.connect(self.set_force_open_target) self.hintmanager.set_open_target.connect(self.set_force_open_target)
self._page.linkHovered.connect(self.linkHovered) self._page.linkHovered.connect(self.linkHovered)
@ -120,7 +116,7 @@ class WebView(QWebView):
def __repr__(self): def __repr__(self):
url = self.url().toDisplayString() url = self.url().toDisplayString()
return "WebView(url='{}')".format(elide(url, 50)) return "WebView(url='{}')".format(utils.elide(url, 50))
@property @property
def open_target(self): def open_target(self):
@ -130,7 +126,7 @@ class WebView(QWebView):
@open_target.setter @open_target.setter
def open_target(self, val): def open_target(self, val):
"""Setter for open_target to do type checking.""" """Setter for open_target to do type checking."""
if not isinstance(val, ClickTarget): if not isinstance(val, usertypes.ClickTarget):
raise TypeError("Target {} is no ClickTarget member!".format(val)) raise TypeError("Target {} is no ClickTarget member!".format(val))
self._open_target = val self._open_target = val
@ -172,9 +168,10 @@ class WebView(QWebView):
def _init_neighborlist(self): def _init_neighborlist(self):
"""Initialize the _zoom neighborlist.""" """Initialize the _zoom neighborlist."""
self._zoom = NeighborList(config.get('ui', 'zoom-levels'), levels = config.get('ui', 'zoom-levels')
default=config.get('ui', 'default-zoom'), default = config.get('ui', 'default-zoom')
mode=NeighborList.Modes.block) self._zoom = usertypes.NeighborList(
levels, default, mode=usertypes.NeighborList.Modes.block)
def _mousepress_backforward(self, e): def _mousepress_backforward(self, e):
"""Handle back/forward mouse button presses. """Handle back/forward mouse button presses.
@ -186,13 +183,13 @@ class WebView(QWebView):
# Back button on mice which have it. # Back button on mice which have it.
try: try:
self.go_back() self.go_back()
except CommandError as ex: except cmdexc.CommandError as ex:
message.error(ex, immediately=True) message.error(ex, immediately=True)
elif e.button() == Qt.XButton2: elif e.button() == Qt.XButton2:
# Forward button on mice which have it. # Forward button on mice which have it.
try: try:
self.go_forward() self.go_forward()
except CommandError as ex: except cmdexc.CommandError as ex:
message.error(ex, immediately=True) message.error(ex, immediately=True)
def _mousepress_insertmode(self, e): def _mousepress_insertmode(self, e):
@ -233,11 +230,11 @@ class WebView(QWebView):
elif ((hitresult.isContentEditable() and webelem.is_writable(elem)) or elif ((hitresult.isContentEditable() and webelem.is_writable(elem)) or
webelem.is_editable(elem)): webelem.is_editable(elem)):
log.mouse.debug("Clicked editable element!") log.mouse.debug("Clicked editable element!")
modeman.maybe_enter(KeyMode.insert, 'click') modeman.maybe_enter(usertypes.KeyMode.insert, 'click')
else: else:
log.mouse.debug("Clicked non-editable element!") log.mouse.debug("Clicked non-editable element!")
if config.get('input', 'auto-leave-insert-mode'): if config.get('input', 'auto-leave-insert-mode'):
modeman.maybe_leave(KeyMode.insert, 'click') modeman.maybe_leave(usertypes.KeyMode.insert, 'click')
def mouserelease_insertmode(self): def mouserelease_insertmode(self):
"""If we have an insertmode check scheduled, handle it.""" """If we have an insertmode check scheduled, handle it."""
@ -247,11 +244,11 @@ class WebView(QWebView):
elem = webelem.focus_elem(self.page().currentFrame()) elem = webelem.focus_elem(self.page().currentFrame())
if webelem.is_editable(elem): if webelem.is_editable(elem):
log.mouse.debug("Clicked editable element (delayed)!") log.mouse.debug("Clicked editable element (delayed)!")
modeman.maybe_enter(KeyMode.insert, 'click-delayed') modeman.maybe_enter(usertypes.KeyMode.insert, 'click-delayed')
else: else:
log.mouse.debug("Clicked non-editable element (delayed)!") log.mouse.debug("Clicked non-editable element (delayed)!")
if config.get('input', 'auto-leave-insert-mode'): if config.get('input', 'auto-leave-insert-mode'):
modeman.maybe_leave(KeyMode.insert, 'click-delayed') modeman.maybe_leave(usertypes.KeyMode.insert, 'click-delayed')
def _mousepress_opentarget(self, e): def _mousepress_opentarget(self, e):
"""Set the open target when something was clicked. """Set the open target when something was clicked.
@ -267,13 +264,13 @@ class WebView(QWebView):
elif (e.button() == Qt.MidButton or elif (e.button() == Qt.MidButton or
e.modifiers() & Qt.ControlModifier): e.modifiers() & Qt.ControlModifier):
if config.get('tabs', 'background-tabs'): if config.get('tabs', 'background-tabs'):
self.open_target = ClickTarget.tab_bg self.open_target = usertypes.ClickTarget.tab_bg
else: else:
self.open_target = ClickTarget.tab self.open_target = usertypes.ClickTarget.tab
log.mouse.debug("Middle click, setting target: {}".format( log.mouse.debug("Middle click, setting target: {}".format(
self.open_target)) self.open_target))
else: else:
self.open_target = ClickTarget.normal self.open_target = usertypes.ClickTarget.normal
log.mouse.debug("Normal click, setting normal target") log.mouse.debug("Normal click, setting normal target")
def shutdown(self): def shutdown(self):
@ -304,7 +301,7 @@ class WebView(QWebView):
Emit: Emit:
titleChanged titleChanged
""" """
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
urlstr = url.toDisplayString() urlstr = url.toDisplayString()
log.webview.debug("New title: {}".format(urlstr)) log.webview.debug("New title: {}".format(urlstr))
self.titleChanged.emit(urlstr) self.titleChanged.emit(urlstr)
@ -321,7 +318,7 @@ class WebView(QWebView):
if fuzzyval: if fuzzyval:
self._zoom.fuzzyval = int(perc) self._zoom.fuzzyval = int(perc)
if perc < 0: if perc < 0:
raise CommandError("Can't zoom {}%!".format(perc)) raise cmdexc.CommandError("Can't zoom {}%!".format(perc))
self.setZoomFactor(float(perc) / 100) self.setZoomFactor(float(perc) / 100)
message.info("Zoom level: {}%".format(perc)) message.info("Zoom level: {}%".format(perc))
@ -349,19 +346,19 @@ class WebView(QWebView):
if self.page().history().canGoBack(): if self.page().history().canGoBack():
self.back() self.back()
else: else:
raise CommandError("At beginning of history.") raise cmdexc.CommandError("At beginning of history.")
def go_forward(self): def go_forward(self):
"""Go forward a page in the history.""" """Go forward a page in the history."""
if self.page().history().canGoForward(): if self.page().history().canGoForward():
self.forward() self.forward()
else: else:
raise CommandError("At end of history.") raise cmdexc.CommandError("At end of history.")
@pyqtSlot('QUrl') @pyqtSlot('QUrl')
def on_url_changed(self, url): def on_url_changed(self, url):
"""Update cur_url when URL has changed.""" """Update cur_url when URL has changed."""
qt_ensure_valid(url) qtutils.qt_ensure_valid(url)
self.cur_url = url self.cur_url = url
@pyqtSlot(str, str) @pyqtSlot(str, str)
@ -394,7 +391,7 @@ class WebView(QWebView):
self.load_status = LoadStatus.error self.load_status = LoadStatus.error
if not config.get('input', 'auto-insert-mode'): if not config.get('input', 'auto-insert-mode'):
return return
if modeman.instance().mode == KeyMode.insert or not ok: if modeman.instance().mode == usertypes.KeyMode.insert or not ok:
return return
frame = self.page().currentFrame() frame = self.page().currentFrame()
elem = frame.findFirstElement(':focus') elem = frame.findFirstElement(':focus')
@ -402,7 +399,7 @@ class WebView(QWebView):
if elem.isNull(): if elem.isNull():
log.webview.debug("Focused element is null!") log.webview.debug("Focused element is null!")
elif webelem.is_editable(elem): elif webelem.is_editable(elem):
modeman.maybe_enter(KeyMode.insert, 'load finished') modeman.maybe_enter(usertypes.KeyMode.insert, 'load finished')
@pyqtSlot(str) @pyqtSlot(str)
def set_force_open_target(self, target): def set_force_open_target(self, target):
@ -411,7 +408,7 @@ class WebView(QWebView):
Args: Args:
target: A string to set self._force_open_target to. target: A string to set self._force_open_target to.
""" """
t = getattr(ClickTarget, target) t = getattr(usertypes.ClickTarget, target)
log.webview.debug("Setting force target to {}/{}".format(target, t)) log.webview.debug("Setting force target to {}/{}".format(target, t))
self._force_open_target = t self._force_open_target = t

View File

@ -25,7 +25,7 @@ import os.path
import sys import sys
import glob import glob
import shutil import shutil
from fnmatch import fnmatch import fnmatch
recursive_lint = ('__pycache__', '*.pyc') recursive_lint = ('__pycache__', '*.pyc')
@ -47,11 +47,17 @@ def remove(path):
os.remove(path) os.remove(path)
for elem in lint: def main():
for f in glob.glob(elem): """Clean up lint in the current dir."""
remove(f) for elem in lint:
for f in glob.glob(elem):
remove(f)
for root, _dirs, _files in os.walk(os.getcwd()):
path = os.path.basename(root)
if any([fnmatch.fnmatch(path, e) for e in recursive_lint]):
remove(root)
for root, dirs, files in os.walk(os.getcwd()): if __name__ == '__main__':
if any([fnmatch(os.path.basename(root), e) for e in recursive_lint]): main()
remove(root)

View File

@ -27,12 +27,12 @@ Builds a standalone executable.
import os import os
import os.path import os.path
import sys import sys
from distutils.sysconfig import get_python_lib import distutils
from cx_Freeze import setup, Executable import cx_Freeze as cx
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
from scripts.setupcommon import setupdata, write_git_file from scripts import setupcommon
try: try:
@ -46,7 +46,8 @@ def get_egl_path():
"""Get the path for PyQt5's libEGL.dll.""" """Get the path for PyQt5's libEGL.dll."""
if not sys.platform.startswith('win'): if not sys.platform.startswith('win'):
return None return None
return os.path.join(get_python_lib(), r'PyQt5\libEGL.dll') return os.path.join(distutils.sysconfig.get_python_lib(),
r'PyQt5\libEGL.dll')
build_exe_options = { build_exe_options = {
'include_files': [ 'include_files': [
@ -69,20 +70,20 @@ bdist_msi_options = {
base = 'Win32GUI' if sys.platform.startswith('win') else None base = 'Win32GUI' if sys.platform.startswith('win') else None
executable = Executable('qutebrowser/__main__.py', base=base, executable = cx.Executable('qutebrowser/__main__.py', base=base,
targetName='qutebrowser.exe', targetName='qutebrowser.exe',
shortcutName='qutebrowser', shortcutName='qutebrowser',
shortcutDir='ProgramMenuFolder') shortcutDir='ProgramMenuFolder')
try: try:
write_git_file() setupcommon.write_git_file()
setup( cx.setup(
executables=[executable], executables=[executable],
options={ options={
'build_exe': build_exe_options, 'build_exe': build_exe_options,
'bdist_msi': bdist_msi_options, 'bdist_msi': bdist_msi_options,
}, },
**setupdata **setupcommon.setupdata
) )
finally: finally:
if BASEDIR is not None: if BASEDIR is not None:

View File

@ -27,18 +27,18 @@ import html
import shutil import shutil
import inspect import inspect
import subprocess import subprocess
from collections import Counter, OrderedDict import collections
from tempfile import mkstemp import tempfile
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
import qutebrowser import qutebrowser
# We import qutebrowser.app so all @cmdutils-register decorators are run. # We import qutebrowser.app so all @cmdutils-register decorators are run.
import qutebrowser.app import qutebrowser.app
import qutebrowser.commands.utils as cmdutils from qutebrowser import qutebrowser as qutequtebrowser
import qutebrowser.config.configdata as configdata from qutebrowser.commands import utils as cmdutils
import qutebrowser.qutebrowser as qutequtebrowser from qutebrowser.config import configdata
from qutebrowser.utils.usertypes import enum from qutebrowser.utils import usertypes
def _open_file(name, mode='w'): def _open_file(name, mode='w'):
@ -58,8 +58,9 @@ def _parse_docstring(func): # noqa
A (short_desc, long_desc, arg_descs) tuple. A (short_desc, long_desc, arg_descs) tuple.
""" """
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
State = enum('State', 'short', 'desc', # pylint: disable=invalid-name State = usertypes.enum('State', 'short', # pylint: disable=invalid-name
'desc_hidden', 'arg_start', 'arg_inside', 'misc') 'desc', 'desc_hidden', 'arg_start', 'arg_inside',
'misc')
doc = inspect.getdoc(func) doc = inspect.getdoc(func)
lines = doc.splitlines() lines = doc.splitlines()
@ -67,7 +68,7 @@ def _parse_docstring(func): # noqa
short_desc = [] short_desc = []
long_desc = [] long_desc = []
arg_descs = OrderedDict() arg_descs = collections.OrderedDict()
cur_arg_name = None cur_arg_name = None
for line in lines: for line in lines:
@ -385,7 +386,7 @@ def generate_settings(f):
def _get_authors(): def _get_authors():
"""Get a list of authors based on git commit logs.""" """Get a list of authors based on git commit logs."""
commits = subprocess.check_output(['git', 'log', '--format=%aN']) commits = subprocess.check_output(['git', 'log', '--format=%aN'])
cnt = Counter(commits.decode('utf-8').splitlines()) cnt = collections.Counter(commits.decode('utf-8').splitlines())
return sorted(cnt, key=lambda k: cnt[k]) return sorted(cnt, key=lambda k: cnt[k])
@ -442,7 +443,7 @@ def generate_manpage_resources(f):
def regenerate_authors(filename): def regenerate_authors(filename):
"""Re-generate the authors inside README based on the commits made.""" """Re-generate the authors inside README based on the commits made."""
oshandle, tmpname = mkstemp() oshandle, tmpname = tempfile.mkstemp()
with _open_file(filename, mode='r') as infile, \ with _open_file(filename, mode='r') as infile, \
_open_file(oshandle, mode='w') as temp: _open_file(oshandle, mode='w') as temp:
ignore = False ignore = False

View File

@ -20,18 +20,17 @@
"""Custom astroid checker for config calls.""" """Custom astroid checker for config calls."""
import astroid import astroid
from pylint.interfaces import IAstroidChecker from pylint import interfaces, checkers
from pylint.checkers import BaseChecker
from pylint.checkers import utils from pylint.checkers import utils
import qutebrowser.config.configdata as configdata from qutebrowser.config import configdata
class ConfigChecker(BaseChecker): class ConfigChecker(checkers.BaseChecker):
"""Custom astroid checker for config calls.""" """Custom astroid checker for config calls."""
__implements__ = IAstroidChecker __implements__ = interfaces.IAstroidChecker
name = 'config' name = 'config'
msgs = { msgs = {
'E0000': ('"%s -> %s" is no valid config option.', 'bad-config-call', 'E0000': ('"%s -> %s" is no valid config option.', 'bad-config-call',

View File

@ -18,15 +18,14 @@
"""Checker for CRLF in files.""" """Checker for CRLF in files."""
from pylint.interfaces import IRawChecker from pylint import interfaces, checkers
from pylint.checkers import BaseChecker
class CrlfChecker(BaseChecker): class CrlfChecker(checkers.BaseChecker):
"""Check for CRLF in files.""" """Check for CRLF in files."""
__implements__ = IRawChecker __implements__ = interfaces.IRawChecker
name = 'crlf' name = 'crlf'
msgs = {'W9001': ('Uses CRLFs', 'crlf', None)} msgs = {'W9001': ('Uses CRLFs', 'crlf', None)}

View File

@ -20,15 +20,14 @@
import os.path import os.path
from pylint.interfaces import IRawChecker from pylint import interfaces, checkers
from pylint.checkers import BaseChecker
class ModelineChecker(BaseChecker): class ModelineChecker(checkers.BaseChecker):
"""Check for vim modelines in files.""" """Check for vim modelines in files."""
__implements__ = IRawChecker __implements__ = interfaces.IRawChecker
name = 'modeline' name = 'modeline'
msgs = {'W9002': ('Does not have vim modeline', 'modeline-missing', None), msgs = {'W9002': ('Does not have vim modeline', 'modeline-missing', None),

View File

@ -20,16 +20,15 @@
"""Make sure open() has an encoding set.""" """Make sure open() has an encoding set."""
import astroid import astroid
from pylint.interfaces import IAstroidChecker from pylint import interfaces, checkers
from pylint.checkers import BaseChecker
from pylint.checkers import utils from pylint.checkers import utils
class OpenEncodingChecker(BaseChecker): class OpenEncodingChecker(checkers.BaseChecker):
"""Checker to check open() has an encoding set.""" """Checker to check open() has an encoding set."""
__implements__ = IAstroidChecker __implements__ = interfaces.IAstroidChecker
name = 'open-encoding' name = 'open-encoding'
msgs = { msgs = {

View File

@ -38,13 +38,13 @@ import logging
import tokenize import tokenize
import configparser import configparser
import argparse import argparse
from collections import OrderedDict import collections
from functools import partial import functools
from contextlib import contextmanager import contextlib
import colorama as col import colorama as col
import pep257 import pep257
from pkg_resources import load_entry_point, DistributionNotFound import pkg_resources as pkg
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
@ -59,7 +59,7 @@ config = configparser.ConfigParser()
config.read('.run_checks') config.read('.run_checks')
@contextmanager @contextlib.contextmanager
def _adjusted_pythonpath(name): def _adjusted_pythonpath(name):
"""Adjust PYTHONPATH for pylint.""" """Adjust PYTHONPATH for pylint."""
if name == 'pylint': if name == 'pylint':
@ -82,7 +82,7 @@ def _run_distutils(name, args):
"""Run a checker via its distutils entry point.""" """Run a checker via its distutils entry point."""
sys.argv = [name] + args sys.argv = [name] + args
try: try:
ep = load_entry_point(name, 'console_scripts', name) ep = pkg.load_entry_point(name, 'console_scripts', name)
ep() ep()
except SystemExit as e: except SystemExit as e:
return e.code return e.code
@ -114,7 +114,7 @@ def run(name, target=None):
with _adjusted_pythonpath(name): with _adjusted_pythonpath(name):
try: try:
status = _run_distutils(name, args) status = _run_distutils(name, args)
except DistributionNotFound: except pkg.DistributionNotFound:
status = _run_subprocess(name, args) status = _run_subprocess(name, args)
print() print()
return status return status
@ -244,23 +244,23 @@ def _get_args(checker):
def _get_checkers(): def _get_checkers():
"""Get a dict of checkers we need to execute.""" """Get a dict of checkers we need to execute."""
# "Static" checkers # "Static" checkers
checkers = OrderedDict([ checkers = collections.OrderedDict([
('global', OrderedDict([ ('global', collections.OrderedDict([
('unittest', check_unittest), ('unittest', check_unittest),
('git', check_git), ('git', check_git),
])), ])),
('setup', OrderedDict([ ('setup', collections.OrderedDict([
('pyroma', partial(run, 'pyroma')), ('pyroma', functools.partial(run, 'pyroma')),
('check-manifest', partial(run, 'check-manifest')), ('check-manifest', functools.partial(run, 'check-manifest')),
])), ])),
]) ])
# "Dynamic" checkers which exist once for each target. # "Dynamic" checkers which exist once for each target.
for target in config.get('DEFAULT', 'targets').split(','): for target in config.get('DEFAULT', 'targets').split(','):
checkers[target] = OrderedDict([ checkers[target] = collections.OrderedDict([
('pep257', partial(check_pep257, target)), ('pep257', functools.partial(check_pep257, target)),
('flake8', partial(run, 'flake8', target)), ('flake8', functools.partial(run, 'flake8', target)),
('vcs', partial(check_vcs_conflict, target)), ('vcs', functools.partial(check_vcs_conflict, target)),
('pylint', partial(run, 'pylint', target)), ('pylint', functools.partial(run, 'pylint', target)),
]) ])
return checkers return checkers
@ -279,7 +279,7 @@ def _checker_enabled(args, group, name):
def main(): def main():
"""Main entry point.""" """Main entry point."""
col.init() col.init()
exit_status = OrderedDict() exit_status = collections.OrderedDict()
exit_status_bool = {} exit_status_bool = {}
parser = argparse.ArgumentParser(description='Run various checkers.') parser = argparse.ArgumentParser(description='Run various checkers.')
parser.add_argument('-s', '--setup', help="Run additional setup checks", parser.add_argument('-s', '--setup', help="Run additional setup checks",

View File

@ -23,20 +23,20 @@
import sys import sys
import cProfile import cProfile
import os.path import os.path
from os import getcwd import os
from tempfile import mkdtemp import tempfile
from subprocess import call import subprocess
from shutil import rmtree import shutil
sys.path.insert(0, getcwd()) sys.path.insert(0, os.getcwd())
import qutebrowser.qutebrowser # pylint: disable=unused-import import qutebrowser.qutebrowser # pylint: disable=unused-import
tempdir = mkdtemp() tempdir = tempfile.mkdtemp()
if '--profile-keep' in sys.argv: if '--profile-keep' in sys.argv:
sys.argv.remove('--profile-keep') sys.argv.remove('--profile-keep')
profilefile = os.path.join(getcwd(), 'profile') profilefile = os.path.join(os.getcwd(), 'profile')
else: else:
profilefile = os.path.join(tempdir, 'profile') profilefile = os.path.join(tempdir, 'profile')
if '--profile-noconv' in sys.argv: if '--profile-noconv' in sys.argv:
@ -51,5 +51,6 @@ profiler.run('qutebrowser.qutebrowser.main()')
profiler.dump_stats(profilefile) profiler.dump_stats(profilefile)
if not noconv: if not noconv:
call(['pyprof2calltree', '-k', '-i', profilefile, '-o', callgraphfile]) subprocess.call(['pyprof2calltree', '-k', '-i', profilefile,
rmtree(tempdir) '-o', callgraphfile])
shutil.rmtree(tempdir)

View File

@ -20,7 +20,8 @@
"""Update 3rd-party files (currently only ez_setup.py).""" """Update 3rd-party files (currently only ez_setup.py)."""
from urllib.request import urlretrieve import urllib.request
urlretrieve('https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py', urllib.request.urlretrieve(
'scripts/ez_setup.py') 'https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py',
'scripts/ez_setup.py')

View File

@ -24,11 +24,11 @@
import os import os
import os.path import os.path
from scripts.setupcommon import setupdata, write_git_file from scripts import setupcommon as common
from scripts.ez_setup import use_setuptools from scripts import ez_setup
use_setuptools() ez_setup.use_setuptools()
from setuptools import setup, find_packages import setuptools
try: try:
@ -38,9 +38,9 @@ except NameError:
try: try:
write_git_file() common.write_git_file()
setup( setuptools.setup(
packages=find_packages(exclude=['qutebrowser.test']), packages=setuptools.find_packages(exclude=['qutebrowser.test']),
include_package_data=True, include_package_data=True,
package_data={'qutebrowser': ['html/*', 'git-commit-id']}, package_data={'qutebrowser': ['html/*', 'git-commit-id']},
entry_points={'gui_scripts': entry_points={'gui_scripts':
@ -51,7 +51,7 @@ try:
extras_require={'nice-debugging': ['colorlog', 'colorama'], extras_require={'nice-debugging': ['colorlog', 'colorama'],
'checks': ['flake8', 'pylint', 'check-manifest', 'checks': ['flake8', 'pylint', 'check-manifest',
'pyroma']}, 'pyroma']},
**setupdata **common.setupdata
) )
finally: finally:
if BASEDIR is not None: if BASEDIR is not None: