Move CommandError to api.cmdutils

This commit is contained in:
Florian Bruhin 2018-11-29 14:09:06 +01:00
parent f9858733c1
commit b7de287e7b
36 changed files with 302 additions and 249 deletions

View File

@ -407,7 +407,7 @@ Creating a new command is straightforward:
[source,python] [source,python]
---- ----
import qutebrowser.commands.cmdutils from qutebrowser.api import cmdutils
... ...
@ -429,7 +429,7 @@ selects which object registry (global, per-tab, etc.) to use. See the
There are also other arguments to customize the way the command is There are also other arguments to customize the way the command is
registered; see the class documentation for `register` in registered; see the class documentation for `register` in
`qutebrowser.commands.cmdutils` for details. `qutebrowser.api.cmdutils` for details.
The types of the function arguments are inferred based on their default values, The types of the function arguments are inferred based on their default values,
e.g., an argument `foo=True` will be converted to a flag `-f`/`--foo` in e.g., an argument `foo=True` will be converted to a flag `-f`/`--foo` in

View File

@ -0,0 +1,26 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""API for extensions.
This API currently isn't exposed to third-party extensions yet, but will be in
the future. Thus, care must be taken when adding new APIs here.
Code in qutebrowser.components only uses this API.
"""

View File

@ -27,6 +27,23 @@ from qutebrowser.utils import qtutils, log
from qutebrowser.commands import command, cmdexc from qutebrowser.commands import command, cmdexc
class CommandError(cmdexc.Error):
"""Raised when a command encounters an error while running.
If your command handler encounters an error and cannot continue, raise this
exception with an appropriate error message:
raise cmdexc.CommandError("Message")
The message will then be shown in the qutebrowser status bar.
Note that you should only raise this exception while a command handler is
run. Raising it at another point causes qutebrowser to crash due to an
unhandled exception.
"""
def check_overflow(arg: int, ctype: str) -> None: def check_overflow(arg: int, ctype: str) -> None:
"""Check if the given argument is in bounds for the given type. """Check if the given argument is in bounds for the given type.
@ -37,9 +54,8 @@ def check_overflow(arg: int, ctype: str) -> None:
try: try:
qtutils.check_overflow(arg, ctype) qtutils.check_overflow(arg, ctype)
except OverflowError: except OverflowError:
raise cmdexc.CommandError( raise CommandError("Numeric argument is too large for internal {} "
"Numeric argument is too large for internal {} " "representation.".format(ctype))
"representation.".format(ctype))
def check_exclusive(flags: typing.Iterable[bool], def check_exclusive(flags: typing.Iterable[bool],
@ -54,8 +70,7 @@ def check_exclusive(flags: typing.Iterable[bool],
""" """
if sum(1 for e in flags if e) > 1: if sum(1 for e in flags if e) > 1:
argstr = '/'.join('-' + e for e in names) argstr = '/'.join('-' + e for e in names)
raise cmdexc.CommandError("Only one of {} can be given!".format( raise CommandError("Only one of {} can be given!".format(argstr))
argstr))
class register: # noqa: N801,N806 pylint: disable=invalid-name class register: # noqa: N801,N806 pylint: disable=invalid-name

View File

@ -60,7 +60,8 @@ except ImportError:
import qutebrowser import qutebrowser
import qutebrowser.resources import qutebrowser.resources
from qutebrowser.completion.models import miscmodels from qutebrowser.completion.models import miscmodels
from qutebrowser.commands import cmdutils, runners, cmdexc from qutebrowser.commands import runners
from qutebrowser.api import cmdutils
from qutebrowser.config import config, websettings, configfiles, configinit from qutebrowser.config import config, websettings, configfiles, configinit
from qutebrowser.browser import (urlmarks, adblock, history, browsertab, from qutebrowser.browser import (urlmarks, adblock, history, browsertab,
qtnetworkdownloads, downloads, greasemonkey) qtnetworkdownloads, downloads, greasemonkey)
@ -619,10 +620,11 @@ class Quitter:
ok = self.restart(session='_restart') ok = self.restart(session='_restart')
except sessions.SessionError as e: except sessions.SessionError as e:
log.destroy.exception("Failed to save session!") log.destroy.exception("Failed to save session!")
raise cmdexc.CommandError("Failed to save session: {}!".format(e)) raise cmdutils.CommandError("Failed to save session: {}!"
.format(e))
except SyntaxError as e: except SyntaxError as e:
log.destroy.exception("Got SyntaxError") log.destroy.exception("Got SyntaxError")
raise cmdexc.CommandError("SyntaxError in {}:{}: {}".format( raise cmdutils.CommandError("SyntaxError in {}:{}: {}".format(
e.filename, e.lineno, e)) e.filename, e.lineno, e))
if ok: if ok:
self.shutdown(restart=True) self.shutdown(restart=True)
@ -684,7 +686,7 @@ class Quitter:
session: The name of the session to save. session: The name of the session to save.
""" """
if session is not None and not save: if session is not None and not save:
raise cmdexc.CommandError("Session name given without --save!") raise cmdutils.CommandError("Session name given without --save!")
if save: if save:
if session is None: if session is None:
session = sessions.default session = sessions.default

View File

@ -28,7 +28,7 @@ import zipfile
from qutebrowser.browser import downloads from qutebrowser.browser import downloads
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import objreg, standarddir, log, message from qutebrowser.utils import objreg, standarddir, log, message
from qutebrowser.commands import cmdutils from qutebrowser.api import cmdutils
def _guess_zip_filename(zf): def _guess_zip_filename(zf):

View File

@ -29,7 +29,8 @@ from PyQt5.QtWidgets import QApplication, QTabBar
from PyQt5.QtCore import pyqtSlot, Qt, QUrl, QEvent, QUrlQuery from PyQt5.QtCore import pyqtSlot, Qt, QUrl, QEvent, QUrlQuery
from PyQt5.QtPrintSupport import QPrintPreviewDialog from PyQt5.QtPrintSupport import QPrintPreviewDialog
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners from qutebrowser.commands import userscripts, runners
from qutebrowser.api import cmdutils
from qutebrowser.config import config, configdata from qutebrowser.config import config, configdata
from qutebrowser.browser import (urlmarks, browsertab, inspector, navigate, from qutebrowser.browser import (urlmarks, browsertab, inspector, navigate,
webelem, downloads) webelem, downloads)
@ -68,8 +69,8 @@ class CommandDispatcher:
"""Get a tabbed-browser from a new window.""" """Get a tabbed-browser from a new window."""
args = QApplication.instance().arguments() args = QApplication.instance().arguments()
if private and '--single-process' in args: if private and '--single-process' in args:
raise cmdexc.CommandError("Private windows are unavailable with " raise cmdutils.CommandError("Private windows are unavailable with "
"the single-process process model.") "the single-process process model.")
new_window = mainwindow.MainWindow(private=private) new_window = mainwindow.MainWindow(private=private)
new_window.show() new_window.show()
@ -97,7 +98,7 @@ class CommandDispatcher:
if e.reason: if e.reason:
msg += " ({})".format(e.reason) msg += " ({})".format(e.reason)
msg += "!" msg += "!"
raise cmdexc.CommandError(msg) raise cmdutils.CommandError(msg)
def _current_title(self): def _current_title(self):
"""Convenience method to get the current title.""" """Convenience method to get the current title."""
@ -107,7 +108,7 @@ class CommandDispatcher:
"""Get the currently active widget from a command.""" """Get the currently active widget from a command."""
widget = self._tabbed_browser.widget.currentWidget() widget = self._tabbed_browser.widget.currentWidget()
if widget is None: if widget is None:
raise cmdexc.CommandError("No WebView available yet!") raise cmdutils.CommandError("No WebView available yet!")
return widget return widget
def _open(self, url, tab=False, background=False, window=False, def _open(self, url, tab=False, background=False, window=False,
@ -166,10 +167,10 @@ class CommandDispatcher:
except KeyError: except KeyError:
if not show_error: if not show_error:
return return
raise cmdexc.CommandError("No last focused tab!") raise cmdutils.CommandError("No last focused tab!")
idx = self._tabbed_browser.widget.indexOf(tab) idx = self._tabbed_browser.widget.indexOf(tab)
if idx == -1: if idx == -1:
raise cmdexc.CommandError("Last focused tab vanished!") raise cmdutils.CommandError("Last focused tab vanished!")
self._set_current_index(idx) self._set_current_index(idx)
def _get_selection_override(self, prev, next_, opposite): def _get_selection_override(self, prev, next_, opposite):
@ -197,7 +198,7 @@ class CommandDispatcher:
elif conf_selection == QTabBar.SelectRightTab: elif conf_selection == QTabBar.SelectRightTab:
return QTabBar.SelectLeftTab return QTabBar.SelectLeftTab
elif conf_selection == QTabBar.SelectPreviousTab: elif conf_selection == QTabBar.SelectPreviousTab:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"-o is not supported with 'tabs.select_on_remove' set to " "-o is not supported with 'tabs.select_on_remove' set to "
"'last-used'!") "'last-used'!")
else: # pragma: no cover else: # pragma: no cover
@ -339,7 +340,7 @@ class CommandDispatcher:
try: try:
return urlutils.fuzzy_url(url, force_search=force_search) return urlutils.fuzzy_url(url, force_search=force_search)
except urlutils.InvalidUrlError as e: except urlutils.InvalidUrlError as e:
# We don't use cmdexc.CommandError here as this can be # We don't use cmdutils.CommandError here as this can be
# called async from edit_url # called async from edit_url
message.error(str(e)) message.error(str(e))
return None return None
@ -444,7 +445,7 @@ class CommandDispatcher:
else: else:
tab.printing.show_dialog() tab.printing.show_dialog()
except browsertab.WebTabError as e: except browsertab.WebTabError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
def tab_clone(self, bg=False, window=False): def tab_clone(self, bg=False, window=False):
@ -464,7 +465,7 @@ class CommandDispatcher:
try: try:
history = curtab.history.serialize() history = curtab.history.serialize()
except browsertab.WebTabError as e: except browsertab.WebTabError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
# The new tab could be in a new tabbed_browser (e.g. because of # The new tab could be in a new tabbed_browser (e.g. because of
# tabs.tabs_are_windows being set) # tabs.tabs_are_windows being set)
@ -504,7 +505,8 @@ class CommandDispatcher:
tabbed_browser, tab = self._resolve_buffer_index(index) tabbed_browser, tab = self._resolve_buffer_index(index)
if tabbed_browser is self._tabbed_browser: if tabbed_browser is self._tabbed_browser:
raise cmdexc.CommandError("Can't take a tab from the same window") raise cmdutils.CommandError("Can't take a tab from the same "
"window")
self._open(tab.url(), tab=True) self._open(tab.url(), tab=True)
if not keep: if not keep:
@ -528,18 +530,18 @@ class CommandDispatcher:
win_id = count - 1 win_id = count - 1
if win_id == self._win_id: if win_id == self._win_id:
raise cmdexc.CommandError("Can't give a tab to the same window") raise cmdutils.CommandError("Can't give a tab to the same window")
if win_id is None: if win_id is None:
if self._count() < 2 and not keep: if self._count() < 2 and not keep:
raise cmdexc.CommandError("Cannot detach from a window with " raise cmdutils.CommandError("Cannot detach from a window with "
"only one tab") "only one tab")
tabbed_browser = self._new_tabbed_browser( tabbed_browser = self._new_tabbed_browser(
private=self._tabbed_browser.is_private) private=self._tabbed_browser.is_private)
else: else:
if win_id not in objreg.window_registry: if win_id not in objreg.window_registry:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"There's no window with id {}!".format(win_id)) "There's no window with id {}!".format(win_id))
tabbed_browser = objreg.get('tabbed-browser', scope='window', tabbed_browser = objreg.get('tabbed-browser', scope='window',
@ -555,9 +557,9 @@ class CommandDispatcher:
history = self._current_widget().history history = self._current_widget().history
# Catch common cases before e.g. cloning tab # Catch common cases before e.g. cloning tab
if not forward and not history.can_go_back(): if not forward and not history.can_go_back():
raise cmdexc.CommandError("At beginning of history.") raise cmdutils.CommandError("At beginning of history.")
elif forward and not history.can_go_forward(): elif forward and not history.can_go_forward():
raise cmdexc.CommandError("At end of history.") raise cmdutils.CommandError("At end of history.")
if tab or bg or window: if tab or bg or window:
widget = self.tab_clone(bg, window) widget = self.tab_clone(bg, window)
@ -570,7 +572,7 @@ class CommandDispatcher:
else: else:
widget.history.back(count) widget.history.back(count)
except browsertab.WebTabError as e: except browsertab.WebTabError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True) @cmdutils.argument('count', count=True)
@ -663,7 +665,7 @@ class CommandDispatcher:
raise ValueError("Got called with invalid value {} for " raise ValueError("Got called with invalid value {} for "
"`where'.".format(where)) "`where'.".format(where))
except navigate.Error as e: except navigate.Error as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True) @cmdutils.argument('count', count=True)
@ -709,9 +711,9 @@ class CommandDispatcher:
func = funcs[direction] func = funcs[direction]
except KeyError: except KeyError:
expected_values = ', '.join(sorted(funcs)) expected_values = ', '.join(sorted(funcs))
raise cmdexc.CommandError("Invalid value {!r} for direction - " raise cmdutils.CommandError("Invalid value {!r} for direction - "
"expected one of: {}".format( "expected one of: {}".format(
direction, expected_values)) direction, expected_values))
if direction in ['top', 'bottom']: if direction in ['top', 'bottom']:
func() func()
@ -794,7 +796,7 @@ class CommandDispatcher:
try: try:
tab.scroller.delta_page(count * x, count * y) tab.scroller.delta_page(count * x, count * y)
except OverflowError: except OverflowError:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"Numeric argument is too large for internal int " "Numeric argument is too large for internal int "
"representation.") "representation.")
@ -901,7 +903,7 @@ class CommandDispatcher:
try: try:
perc = tab.zoom.offset(count) perc = tab.zoom.offset(count)
except ValueError as e: except ValueError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
if not quiet: if not quiet:
message.info("Zoom level: {}%".format(int(perc)), replace=True) message.info("Zoom level: {}%".format(int(perc)), replace=True)
@ -918,7 +920,7 @@ class CommandDispatcher:
try: try:
perc = tab.zoom.offset(-count) perc = tab.zoom.offset(-count)
except ValueError as e: except ValueError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
if not quiet: if not quiet:
message.info("Zoom level: {}%".format(int(perc)), replace=True) message.info("Zoom level: {}%".format(int(perc)), replace=True)
@ -940,8 +942,8 @@ class CommandDispatcher:
try: try:
zoom = int(zoom.rstrip('%')) zoom = int(zoom.rstrip('%'))
except ValueError: except ValueError:
raise cmdexc.CommandError("zoom: Invalid int value {}" raise cmdutils.CommandError("zoom: Invalid int value {}"
.format(zoom)) .format(zoom))
level = count if count is not None else zoom level = count if count is not None else zoom
if level is None: if level is None:
@ -951,7 +953,7 @@ class CommandDispatcher:
try: try:
tab.zoom.set_factor(float(level) / 100) tab.zoom.set_factor(float(level) / 100)
except ValueError: except ValueError:
raise cmdexc.CommandError("Can't zoom {}%!".format(level)) raise cmdutils.CommandError("Can't zoom {}%!".format(level))
if not quiet: if not quiet:
message.info("Zoom level: {}%".format(int(level)), replace=True) message.info("Zoom level: {}%".format(int(level)), replace=True)
@ -1000,7 +1002,7 @@ class CommandDispatcher:
try: try:
self._tabbed_browser.undo() self._tabbed_browser.undo()
except IndexError: except IndexError:
raise cmdexc.CommandError("Nothing to undo!") raise cmdutils.CommandError("Nothing to undo!")
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True) @cmdutils.argument('count', count=True)
@ -1061,7 +1063,7 @@ class CommandDispatcher:
index = model.data(model.first_item()) index = model.data(model.first_item())
index_parts = index.split('/', 1) index_parts = index.split('/', 1)
else: else:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"No matching tab for: {}".format(index)) "No matching tab for: {}".format(index))
if len(index_parts) == 2: if len(index_parts) == 2:
@ -1072,18 +1074,18 @@ class CommandDispatcher:
active_win = objreg.get('app').activeWindow() active_win = objreg.get('app').activeWindow()
if active_win is None: if active_win is None:
# Not sure how you enter a command without an active window... # Not sure how you enter a command without an active window...
raise cmdexc.CommandError( raise cmdutils.CommandError(
"No window specified and couldn't find active window!") "No window specified and couldn't find active window!")
win_id = active_win.win_id win_id = active_win.win_id
if win_id not in objreg.window_registry: if win_id not in objreg.window_registry:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"There's no window with id {}!".format(win_id)) "There's no window with id {}!".format(win_id))
tabbed_browser = objreg.get('tabbed-browser', scope='window', tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id) window=win_id)
if not 0 < idx <= tabbed_browser.widget.count(): if not 0 < idx <= tabbed_browser.widget.count():
raise cmdexc.CommandError( raise cmdutils.CommandError(
"There's no tab with index {}!".format(idx)) "There's no tab with index {}!".format(idx))
return (tabbed_browser, tabbed_browser.widget.widget(idx-1)) return (tabbed_browser, tabbed_browser.widget.widget(idx-1))
@ -1158,7 +1160,7 @@ class CommandDispatcher:
if 1 <= index <= self._count(): if 1 <= index <= self._count():
self._set_current_index(index - 1) self._set_current_index(index - 1)
else: else:
raise cmdexc.CommandError("There's no tab with index {}!".format( raise cmdutils.CommandError("There's no tab with index {}!".format(
index)) index))
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
@ -1200,8 +1202,8 @@ class CommandDispatcher:
new_idx = 0 new_idx = 0
if not 0 <= new_idx < self._count(): if not 0 <= new_idx < self._count():
raise cmdexc.CommandError("Can't move tab to position {}!".format( raise cmdutils.CommandError("Can't move tab to position {}!"
new_idx + 1)) .format(new_idx + 1))
cur_idx = self._current_index() cur_idx = self._current_index()
cmdutils.check_overflow(cur_idx, 'int') cmdutils.check_overflow(cur_idx, 'int')
@ -1232,8 +1234,8 @@ class CommandDispatcher:
try: try:
cmd, *args = shlex.split(cmdline) cmd, *args = shlex.split(cmdline)
except ValueError as e: except ValueError as e:
raise cmdexc.CommandError("Error while splitting command: " raise cmdutils.CommandError("Error while splitting command: "
"{}".format(e)) "{}".format(e))
args = runners.replace_variables(self._win_id, args) args = runners.replace_variables(self._win_id, args)
@ -1252,7 +1254,7 @@ class CommandDispatcher:
try: try:
runner = self._run_userscript(s, cmd, args, verbose, count) runner = self._run_userscript(s, cmd, args, verbose, count)
runner.finished.connect(_on_proc_finished) runner.finished.connect(_on_proc_finished)
except cmdexc.CommandError as e: except cmdutils.CommandError as e:
message.error(str(e)) message.error(str(e))
# ~ expansion is handled by the userscript module. # ~ expansion is handled by the userscript module.
@ -1312,7 +1314,7 @@ class CommandDispatcher:
runner = userscripts.run_async( runner = userscripts.run_async(
tab, cmd, *args, win_id=self._win_id, env=env, verbose=verbose) tab, cmd, *args, win_id=self._win_id, env=env, verbose=verbose)
except userscripts.Error as e: except userscripts.Error as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
return runner return runner
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
@ -1336,7 +1338,7 @@ class CommandDispatcher:
try: try:
url = objreg.get('quickmark-manager').get(name) url = objreg.get('quickmark-manager').get(name)
except urlmarks.Error as e: except urlmarks.Error as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
self._open(url, tab, bg, window) self._open(url, tab, bg, window)
@cmdutils.register(instance='command-dispatcher', scope='window', @cmdutils.register(instance='command-dispatcher', scope='window',
@ -1356,11 +1358,12 @@ class CommandDispatcher:
try: try:
name = quickmark_manager.get_by_qurl(url) name = quickmark_manager.get_by_qurl(url)
except urlmarks.DoesNotExistError as e: except urlmarks.DoesNotExistError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
try: try:
quickmark_manager.delete(name) quickmark_manager.delete(name)
except KeyError: except KeyError:
raise cmdexc.CommandError("Quickmark '{}' not found!".format(name)) raise cmdutils.CommandError("Quickmark '{}' not found!"
.format(name))
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
def bookmark_add(self, url=None, title=None, toggle=False): def bookmark_add(self, url=None, title=None, toggle=False):
@ -1382,8 +1385,8 @@ class CommandDispatcher:
already exists. already exists.
""" """
if url and not title: if url and not title:
raise cmdexc.CommandError('Title must be provided if url has ' raise cmdutils.CommandError('Title must be provided if url has '
'been provided') 'been provided')
bookmark_manager = objreg.get('bookmark-manager') bookmark_manager = objreg.get('bookmark-manager')
if not url: if not url:
url = self._current_url() url = self._current_url()
@ -1391,13 +1394,13 @@ class CommandDispatcher:
try: try:
url = urlutils.fuzzy_url(url) url = urlutils.fuzzy_url(url)
except urlutils.InvalidUrlError as e: except urlutils.InvalidUrlError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
if not title: if not title:
title = self._current_title() title = self._current_title()
try: try:
was_added = bookmark_manager.add(url, title, toggle=toggle) was_added = bookmark_manager.add(url, title, toggle=toggle)
except urlmarks.Error as e: except urlmarks.Error as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
else: else:
msg = "Bookmarked {}" if was_added else "Removed bookmark {}" msg = "Bookmarked {}" if was_added else "Removed bookmark {}"
message.info(msg.format(url.toDisplayString())) message.info(msg.format(url.toDisplayString()))
@ -1419,7 +1422,7 @@ class CommandDispatcher:
try: try:
qurl = urlutils.fuzzy_url(url) qurl = urlutils.fuzzy_url(url)
except urlutils.InvalidUrlError as e: except urlutils.InvalidUrlError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
self._open(qurl, tab, bg, window) self._open(qurl, tab, bg, window)
if delete: if delete:
self.bookmark_del(url) self.bookmark_del(url)
@ -1440,7 +1443,7 @@ class CommandDispatcher:
try: try:
objreg.get('bookmark-manager').delete(url) objreg.get('bookmark-manager').delete(url)
except KeyError: except KeyError:
raise cmdexc.CommandError("Bookmark '{}' not found!".format(url)) raise cmdutils.CommandError("Bookmark '{}' not found!".format(url))
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
def follow_selected(self, *, tab=False): def follow_selected(self, *, tab=False):
@ -1452,7 +1455,7 @@ class CommandDispatcher:
try: try:
self._current_widget().caret.follow_selected(tab=tab) self._current_widget().caret.follow_selected(tab=tab)
except browsertab.WebTabError as e: except browsertab.WebTabError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
@cmdutils.register(instance='command-dispatcher', name='inspector', @cmdutils.register(instance='command-dispatcher', name='inspector',
scope='window') scope='window')
@ -1474,7 +1477,7 @@ class CommandDispatcher:
else: else:
tab.data.inspector.toggle(page) tab.data.inspector.toggle(page)
except inspector.WebInspectorError as e: except inspector.WebInspectorError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
def download(self, url=None, *, mhtml_=False, dest=None): def download(self, url=None, *, mhtml_=False, dest=None):
@ -1491,7 +1494,7 @@ class CommandDispatcher:
if dest is not None: if dest is not None:
dest = downloads.transform_path(dest) dest = downloads.transform_path(dest)
if dest is None: if dest is None:
raise cmdexc.CommandError("Invalid target filename") raise cmdutils.CommandError("Invalid target filename")
target = downloads.FileDownloadTarget(dest) target = downloads.FileDownloadTarget(dest)
tab = self._current_widget() tab = self._current_widget()
@ -1499,8 +1502,8 @@ class CommandDispatcher:
if url: if url:
if mhtml_: if mhtml_:
raise cmdexc.CommandError("Can only download the current page" raise cmdutils.CommandError("Can only download the current "
" as mhtml.") "page as mhtml.")
url = urlutils.qurl_from_user_input(url) url = urlutils.qurl_from_user_input(url)
urlutils.raise_cmdexc_if_invalid(url) urlutils.raise_cmdexc_if_invalid(url)
download_manager.get(url, user_agent=user_agent, target=target) download_manager.get(url, user_agent=user_agent, target=target)
@ -1512,7 +1515,7 @@ class CommandDispatcher:
try: try:
webengine_download_manager.get_mhtml(tab, target) webengine_download_manager.get_mhtml(tab, target)
except browsertab.UnsupportedOperationError as e: except browsertab.UnsupportedOperationError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
else: else:
download_manager.get_mhtml(tab, target) download_manager.get_mhtml(tab, target)
else: else:
@ -1544,12 +1547,12 @@ class CommandDispatcher:
tab = self._current_widget() tab = self._current_widget()
try: try:
current_url = self._current_url() current_url = self._current_url()
except cmdexc.CommandError as e: except cmdutils.CommandError as e:
message.error(str(e)) message.error(str(e))
return return
if current_url.scheme() == 'view-source' or tab.data.viewing_source: if current_url.scheme() == 'view-source' or tab.data.viewing_source:
raise cmdexc.CommandError("Already viewing source!") raise cmdutils.CommandError("Already viewing source!")
if edit: if edit:
ed = editor.ExternalEditor(self._tabbed_browser) ed = editor.ExternalEditor(self._tabbed_browser)
@ -1613,13 +1616,13 @@ class CommandDispatcher:
elif topic.startswith(':'): elif topic.startswith(':'):
command = topic[1:] command = topic[1:]
if command not in objects.commands: if command not in objects.commands:
raise cmdexc.CommandError("Invalid command {}!".format( raise cmdutils.CommandError("Invalid command {}!".format(
command)) command))
path = 'commands.html#{}'.format(command) path = 'commands.html#{}'.format(command)
elif topic in configdata.DATA: elif topic in configdata.DATA:
path = 'settings.html#{}'.format(topic) path = 'settings.html#{}'.format(topic)
else: else:
raise cmdexc.CommandError("Invalid help topic {}!".format(topic)) raise cmdutils.CommandError("Invalid help topic {}!".format(topic))
url = QUrl('qute://help/{}'.format(path)) url = QUrl('qute://help/{}'.format(path))
self._open(url, tab, bg, window) self._open(url, tab, bg, window)
@ -1637,7 +1640,7 @@ class CommandDispatcher:
window: Open in a new window. window: Open in a new window.
""" """
if level.upper() not in log.LOG_LEVELS: if level.upper() not in log.LOG_LEVELS:
raise cmdexc.CommandError("Invalid log level {}!".format(level)) raise cmdutils.CommandError("Invalid log level {}!".format(level))
if plain: if plain:
url = QUrl('qute://plainlog?level={}'.format(level)) url = QUrl('qute://plainlog?level={}'.format(level))
else: else:
@ -1839,7 +1842,7 @@ class CommandDispatcher:
window_options = self._tabbed_browser.search_options window_options = self._tabbed_browser.search_options
if window_text is None: if window_text is None:
raise cmdexc.CommandError("No search done yet.") raise cmdutils.CommandError("No search done yet.")
self.set_mark("'") self.set_mark("'")
@ -1873,7 +1876,7 @@ class CommandDispatcher:
window_options = self._tabbed_browser.search_options window_options = self._tabbed_browser.search_options
if window_text is None: if window_text is None:
raise cmdexc.CommandError("No search done yet.") raise cmdutils.CommandError("No search done yet.")
self.set_mark("'") self.set_mark("'")
@ -2070,7 +2073,7 @@ class CommandDispatcher:
try: try:
tab.action.run_string(action) tab.action.run_string(action)
except browsertab.WebTabError as e: except browsertab.WebTabError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
@cmdutils.register(instance='command-dispatcher', scope='window', @cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0, no_cmd_split=True) maxsplit=0, no_cmd_split=True)
@ -2121,13 +2124,13 @@ class CommandDispatcher:
with open(path, 'r', encoding='utf-8') as f: with open(path, 'r', encoding='utf-8') as f:
js_code = f.read() js_code = f.read()
except OSError as e: except OSError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
widget = self._current_widget() widget = self._current_widget()
try: try:
widget.run_js_async(js_code, callback=jseval_cb, world=world) widget.run_js_async(js_code, callback=jseval_cb, world=world)
except browsertab.WebTabError as e: except browsertab.WebTabError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
@cmdutils.register(instance='command-dispatcher', scope='window') @cmdutils.register(instance='command-dispatcher', scope='window')
def fake_key(self, keystring, global_=False): def fake_key(self, keystring, global_=False):
@ -2144,7 +2147,7 @@ class CommandDispatcher:
try: try:
sequence = keyutils.KeySequence.parse(keystring) sequence = keyutils.KeySequence.parse(keystring)
except keyutils.KeyParseError as e: except keyutils.KeyParseError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
for keyinfo in sequence: for keyinfo in sequence:
press_event = keyinfo.to_event(QEvent.KeyPress) press_event = keyinfo.to_event(QEvent.KeyPress)
@ -2153,7 +2156,7 @@ class CommandDispatcher:
if global_: if global_:
window = QApplication.focusWindow() window = QApplication.focusWindow()
if window is None: if window is None:
raise cmdexc.CommandError("No focused window!") raise cmdutils.CommandError("No focused window!")
QApplication.postEvent(window, press_event) QApplication.postEvent(window, press_event)
QApplication.postEvent(window, release_event) QApplication.postEvent(window, release_event)
else: else:
@ -2266,4 +2269,4 @@ class CommandDispatcher:
try: try:
tab.audio.toggle_muted(override=True) tab.audio.toggle_muted(override=True)
except browsertab.WebTabError as e: except browsertab.WebTabError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)

View File

@ -33,7 +33,7 @@ from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
QTimer, QAbstractListModel, QUrl) QTimer, QAbstractListModel, QUrl)
from qutebrowser.browser import pdfjs from qutebrowser.browser import pdfjs
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.api import cmdutils
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import (usertypes, standarddir, utils, message, log, from qutebrowser.utils import (usertypes, standarddir, utils, message, log,
qtutils, objreg) qtutils, objreg)
@ -1009,8 +1009,8 @@ class DownloadModel(QAbstractListModel):
count: The index of the download count: The index of the download
""" """
if not count: if not count:
raise cmdexc.CommandError("There's no download!") raise cmdutils.CommandError("There's no download!")
raise cmdexc.CommandError("There's no download {}!".format(count)) raise cmdutils.CommandError("There's no download {}!".format(count))
@cmdutils.register(instance='download-model', scope='window') @cmdutils.register(instance='download-model', scope='window')
@cmdutils.argument('count', count=True) @cmdutils.argument('count', count=True)
@ -1034,8 +1034,8 @@ class DownloadModel(QAbstractListModel):
if download.done: if download.done:
if not count: if not count:
count = len(self) count = len(self)
raise cmdexc.CommandError("Download {} is already done!" raise cmdutils.CommandError("Download {} is already done!"
.format(count)) .format(count))
download.cancel() download.cancel()
@cmdutils.register(instance='download-model', scope='window') @cmdutils.register(instance='download-model', scope='window')
@ -1053,7 +1053,8 @@ class DownloadModel(QAbstractListModel):
if not download.successful: if not download.successful:
if not count: if not count:
count = len(self) count = len(self)
raise cmdexc.CommandError("Download {} is not done!".format(count)) raise cmdutils.CommandError("Download {} is not done!"
.format(count))
download.delete() download.delete()
download.remove() download.remove()
log.downloads.debug("deleted download {}".format(download)) log.downloads.debug("deleted download {}".format(download))
@ -1080,7 +1081,8 @@ class DownloadModel(QAbstractListModel):
if not download.successful: if not download.successful:
if not count: if not count:
count = len(self) count = len(self)
raise cmdexc.CommandError("Download {} is not done!".format(count)) raise cmdutils.CommandError("Download {} is not done!"
.format(count))
download.open_file(cmdline) download.open_file(cmdline)
@cmdutils.register(instance='download-model', scope='window') @cmdutils.register(instance='download-model', scope='window')
@ -1097,12 +1099,12 @@ class DownloadModel(QAbstractListModel):
except IndexError: except IndexError:
self._raise_no_download(count) self._raise_no_download(count)
if download.successful or not download.done: if download.successful or not download.done:
raise cmdexc.CommandError("Download {} did not fail!".format( raise cmdutils.CommandError("Download {} did not fail!"
count)) .format(count))
else: else:
to_retry = [d for d in self if d.done and not d.successful] to_retry = [d for d in self if d.done and not d.successful]
if not to_retry: if not to_retry:
raise cmdexc.CommandError("No failed downloads!") raise cmdutils.CommandError("No failed downloads!")
else: else:
download = to_retry[0] download = to_retry[0]
download.try_retry() download.try_retry()
@ -1137,8 +1139,8 @@ class DownloadModel(QAbstractListModel):
if not download.done: if not download.done:
if not count: if not count:
count = len(self) count = len(self)
raise cmdexc.CommandError("Download {} is not done!" raise cmdutils.CommandError("Download {} is not done!"
.format(count)) .format(count))
download.remove() download.remove()
def running_downloads(self): def running_downloads(self):

View File

@ -32,7 +32,7 @@ from PyQt5.QtCore import pyqtSignal, QObject, QUrl
from qutebrowser.utils import (log, standarddir, jinja, objreg, utils, from qutebrowser.utils import (log, standarddir, jinja, objreg, utils,
javascript, urlmatch, version, usertypes) javascript, urlmatch, version, usertypes)
from qutebrowser.commands import cmdutils from qutebrowser.api import cmdutils
from qutebrowser.browser import downloads from qutebrowser.browser import downloads
from qutebrowser.misc import objects from qutebrowser.misc import objects

View File

@ -34,7 +34,8 @@ from PyQt5.QtWidgets import QLabel
from qutebrowser.config import config, configexc from qutebrowser.config import config, configexc
from qutebrowser.keyinput import modeman, modeparsers from qutebrowser.keyinput import modeman, modeparsers
from qutebrowser.browser import webelem from qutebrowser.browser import webelem
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners from qutebrowser.commands import userscripts, runners
from qutebrowser.api import cmdutils
from qutebrowser.utils import usertypes, log, qtutils, message, objreg, utils from qutebrowser.utils import usertypes, log, qtutils, message, objreg, utils
@ -563,12 +564,12 @@ class HintManager(QObject):
if target in [Target.userscript, Target.spawn, Target.run, if target in [Target.userscript, Target.spawn, Target.run,
Target.fill]: Target.fill]:
if not args: if not args:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"'args' is required with target userscript/spawn/run/" "'args' is required with target userscript/spawn/run/"
"fill.") "fill.")
else: else:
if args: if args:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"'args' is only allowed with target userscript/spawn.") "'args' is only allowed with target userscript/spawn.")
def _filter_matches(self, filterstr, elemstr): def _filter_matches(self, filterstr, elemstr):
@ -705,7 +706,7 @@ class HintManager(QObject):
window=self._win_id) window=self._win_id)
tab = tabbed_browser.widget.currentWidget() tab = tabbed_browser.widget.currentWidget()
if tab is None: if tab is None:
raise cmdexc.CommandError("No WebView available yet!") raise cmdutils.CommandError("No WebView available yet!")
mode_manager = objreg.get('mode-manager', scope='window', mode_manager = objreg.get('mode-manager', scope='window',
window=self._win_id) window=self._win_id)
@ -722,8 +723,8 @@ class HintManager(QObject):
pass pass
else: else:
name = target.name.replace('_', '-') name = target.name.replace('_', '-')
raise cmdexc.CommandError("Rapid hinting makes no sense with " raise cmdutils.CommandError("Rapid hinting makes no sense "
"target {}!".format(name)) "with target {}!".format(name))
self._check_args(target, *args) self._check_args(target, *args)
self._context = HintContext() self._context = HintContext()
@ -736,7 +737,7 @@ class HintManager(QObject):
try: try:
self._context.baseurl = tabbed_browser.current_url() self._context.baseurl = tabbed_browser.current_url()
except qtutils.QtValueError: except qtutils.QtValueError:
raise cmdexc.CommandError("No URL set for this page yet!") raise cmdutils.CommandError("No URL set for this page yet!")
self._context.args = list(args) self._context.args = list(args)
self._context.group = group self._context.group = group
@ -744,7 +745,7 @@ class HintManager(QObject):
selector = webelem.css_selector(self._context.group, selector = webelem.css_selector(self._context.group,
self._context.baseurl) self._context.baseurl)
except webelem.Error as e: except webelem.Error as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
self._context.tab.elements.find_css(selector, self._start_cb, self._context.tab.elements.find_css(selector, self._start_cb,
only_visible=True) only_visible=True)
@ -758,7 +759,7 @@ class HintManager(QObject):
try: try:
opt.typ.to_py(mode) opt.typ.to_py(mode)
except configexc.ValidationError as e: except configexc.ValidationError as e:
raise cmdexc.CommandError("Invalid mode: {}".format(e)) raise cmdutils.CommandError("Invalid mode: {}".format(e))
return mode return mode
def current_mode(self): def current_mode(self):
@ -960,13 +961,13 @@ class HintManager(QObject):
""" """
if keystring is None: if keystring is None:
if self._context.to_follow is None: if self._context.to_follow is None:
raise cmdexc.CommandError("No hint to follow") raise cmdutils.CommandError("No hint to follow")
elif select: elif select:
raise cmdexc.CommandError("Can't use --select without hint.") raise cmdutils.CommandError("Can't use --select without hint.")
else: else:
keystring = self._context.to_follow keystring = self._context.to_follow
elif keystring not in self._context.labels: elif keystring not in self._context.labels:
raise cmdexc.CommandError("No hint {}!".format(keystring)) raise cmdutils.CommandError("No hint {}!".format(keystring))
if select: if select:
self.handle_partial_key(keystring) self.handle_partial_key(keystring)

View File

@ -27,7 +27,7 @@ from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal
from PyQt5.QtWidgets import QProgressDialog, QApplication from PyQt5.QtWidgets import QProgressDialog, QApplication
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.commands import cmdutils, cmdexc from qutebrowser.api import cmdutils
from qutebrowser.utils import utils, objreg, log, usertypes, message, qtutils from qutebrowser.utils import utils, objreg, log, usertypes, message, qtutils
from qutebrowser.misc import objects, sql from qutebrowser.misc import objects, sql
@ -365,7 +365,8 @@ class WebHistory(sql.SqlTable):
f.write('\n'.join(lines)) f.write('\n'.join(lines))
message.info("Dumped history to {}".format(dest)) message.info("Dumped history to {}".format(dest))
except OSError as e: except OSError as e:
raise cmdexc.CommandError('Could not write history: {}'.format(e)) raise cmdutils.CommandError('Could not write history: {}'
.format(e))
def init(parent=None): def init(parent=None):

View File

@ -35,7 +35,7 @@ from PyQt5.QtCore import pyqtSignal, QUrl, QObject
from qutebrowser.utils import (message, usertypes, qtutils, urlutils, from qutebrowser.utils import (message, usertypes, qtutils, urlutils,
standarddir, objreg, log) standarddir, objreg, log)
from qutebrowser.commands import cmdutils from qutebrowser.api import cmdutils
from qutebrowser.misc import lineparser from qutebrowser.misc import lineparser
@ -166,7 +166,7 @@ class QuickmarkManager(UrlMarkManager):
url: The url to add as quickmark. url: The url to add as quickmark.
name: The name for the new quickmark. name: The name for the new quickmark.
""" """
# We don't raise cmdexc.CommandError here as this can be called async # We don't raise cmdutils.CommandError here as this can be called async
# via prompt_save. # via prompt_save.
if not name: if not name:
message.error("Can't set mark with empty name!") message.error("Can't set mark with empty name!")

View File

@ -28,11 +28,6 @@ class Error(Exception):
"""Base class for all cmdexc errors.""" """Base class for all cmdexc errors."""
class CommandError(Error):
"""Raised when a command encounters an error while running."""
class NoSuchCommandError(Error): class NoSuchCommandError(Error):
"""Raised when a command wasn't found.""" """Raised when a command wasn't found."""

View File

@ -25,6 +25,7 @@ import re
import attr import attr
from PyQt5.QtCore import pyqtSlot, QUrl, QObject from PyQt5.QtCore import pyqtSlot, QUrl, QObject
from qutebrowser.api import cmdutils
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.commands import cmdexc from qutebrowser.commands import cmdexc
from qutebrowser.utils import message, objreg, qtutils, usertypes, utils from qutebrowser.utils import message, objreg, qtutils, usertypes, utils
@ -53,7 +54,7 @@ def _current_url(tabbed_browser):
if e.reason: if e.reason:
msg += " ({})".format(e.reason) msg += " ({})".format(e.reason)
msg += "!" msg += "!"
raise cmdexc.CommandError(msg) raise cmdutils.CommandError(msg)
def replace_variables(win_id, arglist): def replace_variables(win_id, arglist):
@ -93,7 +94,7 @@ def replace_variables(win_id, arglist):
# "{url}" from clipboard is not expanded) # "{url}" from clipboard is not expanded)
args.append(repl_pattern.sub(repl_cb, arg)) args.append(repl_pattern.sub(repl_cb, arg))
except utils.ClipboardError as e: except utils.ClipboardError as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
return args return args

View File

@ -29,7 +29,7 @@ from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.completion import completiondelegate from qutebrowser.completion import completiondelegate
from qutebrowser.utils import utils, usertypes, debug, log, objreg from qutebrowser.utils import utils, usertypes, debug, log, objreg
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.api import cmdutils
class CompletionView(QTreeView): class CompletionView(QTreeView):
@ -251,8 +251,8 @@ class CompletionView(QTreeView):
status.command_history_prev() status.command_history_prev()
return return
else: else:
raise cmdexc.CommandError("Can't combine --history with " raise cmdutils.CommandError("Can't combine --history with "
"{}!".format(which)) "{}!".format(which))
if not self._active: if not self._active:
return return
@ -394,7 +394,7 @@ class CompletionView(QTreeView):
"""Delete the current completion item.""" """Delete the current completion item."""
index = self.currentIndex() index = self.currentIndex()
if not index.isValid(): if not index.isValid():
raise cmdexc.CommandError("No item selected!") raise cmdutils.CommandError("No item selected!")
self.model().delete_cur_item(index) self.model().delete_cur_item(index)
@cmdutils.register(instance='completion', @cmdutils.register(instance='completion',
@ -411,6 +411,6 @@ class CompletionView(QTreeView):
if not text: if not text:
index = self.currentIndex() index = self.currentIndex()
if not index.isValid(): if not index.isValid():
raise cmdexc.CommandError("No item selected!") raise cmdutils.CommandError("No item selected!")
text = self.model().data(index) text = self.model().data(index)
utils.set_clipboard(text, selection=sel) utils.set_clipboard(text, selection=sel)

View File

@ -22,7 +22,7 @@
from PyQt5.QtCore import Qt, QModelIndex, QAbstractItemModel from PyQt5.QtCore import Qt, QModelIndex, QAbstractItemModel
from qutebrowser.utils import log, qtutils from qutebrowser.utils import log, qtutils
from qutebrowser.commands import cmdexc from qutebrowser.api import cmdutils
class CompletionModel(QAbstractItemModel): class CompletionModel(QAbstractItemModel):
@ -224,7 +224,7 @@ class CompletionModel(QAbstractItemModel):
cat = self._cat_from_idx(parent) cat = self._cat_from_idx(parent)
assert cat, "CompletionView sent invalid index for deletion" assert cat, "CompletionView sent invalid index for deletion"
if not cat.delete_func: if not cat.delete_func:
raise cmdexc.CommandError("Cannot delete this item.") raise cmdutils.CommandError("Cannot delete this item.")
data = [cat.data(cat.index(index.row(), i)) data = [cat.data(cat.index(index.row(), i))
for i in range(cat.columnCount())] for i in range(cat.columnCount())]

View File

@ -24,7 +24,7 @@ import contextlib
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.api import cmdutils
from qutebrowser.completion.models import configmodel from qutebrowser.completion.models import configmodel
from qutebrowser.utils import objreg, message, standarddir, urlmatch from qutebrowser.utils import objreg, message, standarddir, urlmatch
from qutebrowser.config import configtypes, configexc, configfiles, configdata from qutebrowser.config import configtypes, configexc, configfiles, configdata
@ -46,7 +46,7 @@ class ConfigCommands:
try: try:
yield yield
except configexc.Error as e: except configexc.Error as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
def _parse_pattern(self, pattern): def _parse_pattern(self, pattern):
"""Parse a pattern string argument to a pattern.""" """Parse a pattern string argument to a pattern."""
@ -56,15 +56,15 @@ class ConfigCommands:
try: try:
return urlmatch.UrlPattern(pattern) return urlmatch.UrlPattern(pattern)
except urlmatch.ParseError as e: except urlmatch.ParseError as e:
raise cmdexc.CommandError("Error while parsing {}: {}" raise cmdutils.CommandError("Error while parsing {}: {}"
.format(pattern, str(e))) .format(pattern, str(e)))
def _parse_key(self, key): def _parse_key(self, key):
"""Parse a key argument.""" """Parse a key argument."""
try: try:
return keyutils.KeySequence.parse(key) return keyutils.KeySequence.parse(key)
except keyutils.KeyParseError as e: except keyutils.KeyParseError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
def _print_value(self, option, pattern): def _print_value(self, option, pattern):
"""Print the value of the given option.""" """Print the value of the given option."""
@ -105,8 +105,8 @@ class ConfigCommands:
return return
if option.endswith('!'): if option.endswith('!'):
raise cmdexc.CommandError("Toggling values was moved to the " raise cmdutils.CommandError("Toggling values was moved to the "
":config-cycle command") ":config-cycle command")
pattern = self._parse_pattern(pattern) pattern = self._parse_pattern(pattern)
@ -213,8 +213,8 @@ class ConfigCommands:
values = ['true', 'false'] values = ['true', 'false']
if len(values) < 2: if len(values) < 2:
raise cmdexc.CommandError("Need at least two values for " raise cmdutils.CommandError("Need at least two values for "
"non-boolean settings.") "non-boolean settings.")
# Use the next valid value from values, or the first if the current # Use the next valid value from values, or the first if the current
# value does not appear in the list # value does not appear in the list
@ -263,8 +263,8 @@ class ConfigCommands:
opt = self._config.get_opt(option) opt = self._config.get_opt(option)
valid_list_types = (configtypes.List, configtypes.ListOrValue) valid_list_types = (configtypes.List, configtypes.ListOrValue)
if not isinstance(opt.typ, valid_list_types): if not isinstance(opt.typ, valid_list_types):
raise cmdexc.CommandError(":config-list-add can only be used for " raise cmdutils.CommandError(":config-list-add can only be used "
"lists") "for lists")
with self._handle_config_error(): with self._handle_config_error():
option_value = self._config.get_mutable_obj(option) option_value = self._config.get_mutable_obj(option)
@ -286,16 +286,16 @@ class ConfigCommands:
""" """
opt = self._config.get_opt(option) opt = self._config.get_opt(option)
if not isinstance(opt.typ, configtypes.Dict): if not isinstance(opt.typ, configtypes.Dict):
raise cmdexc.CommandError(":config-dict-add can only be used for " raise cmdutils.CommandError(":config-dict-add can only be used "
"dicts") "for dicts")
with self._handle_config_error(): with self._handle_config_error():
option_value = self._config.get_mutable_obj(option) option_value = self._config.get_mutable_obj(option)
if key in option_value and not replace: if key in option_value and not replace:
raise cmdexc.CommandError("{} already exists in {} - use " raise cmdutils.CommandError("{} already exists in {} - use "
"--replace to overwrite!" "--replace to overwrite!"
.format(key, option)) .format(key, option))
option_value[key] = value option_value[key] = value
self._config.update_mutables(save_yaml=not temp) self._config.update_mutables(save_yaml=not temp)
@ -313,15 +313,15 @@ class ConfigCommands:
opt = self._config.get_opt(option) opt = self._config.get_opt(option)
valid_list_types = (configtypes.List, configtypes.ListOrValue) valid_list_types = (configtypes.List, configtypes.ListOrValue)
if not isinstance(opt.typ, valid_list_types): if not isinstance(opt.typ, valid_list_types):
raise cmdexc.CommandError(":config-list-remove can only be used " raise cmdutils.CommandError(":config-list-remove can only be used "
"for lists") "for lists")
with self._handle_config_error(): with self._handle_config_error():
option_value = self._config.get_mutable_obj(option) option_value = self._config.get_mutable_obj(option)
if value not in option_value: if value not in option_value:
raise cmdexc.CommandError("{} is not in {}!".format(value, raise cmdutils.CommandError("{} is not in {}!".format(
option)) value, option))
option_value.remove(value) option_value.remove(value)
@ -339,15 +339,15 @@ class ConfigCommands:
""" """
opt = self._config.get_opt(option) opt = self._config.get_opt(option)
if not isinstance(opt.typ, configtypes.Dict): if not isinstance(opt.typ, configtypes.Dict):
raise cmdexc.CommandError(":config-dict-remove can only be used " raise cmdutils.CommandError(":config-dict-remove can only be used "
"for dicts") "for dicts")
with self._handle_config_error(): with self._handle_config_error():
option_value = self._config.get_mutable_obj(option) option_value = self._config.get_mutable_obj(option)
if key not in option_value: if key not in option_value:
raise cmdexc.CommandError("{} is not in {}!".format(key, raise cmdutils.CommandError("{} is not in {}!".format(
option)) key, option))
del option_value[key] del option_value[key]
@ -383,7 +383,7 @@ class ConfigCommands:
try: try:
configfiles.read_config_py(filename) configfiles.read_config_py(filename)
except configexc.ConfigFileErrors as e: except configexc.ConfigFileErrors as e:
raise cmdexc.CommandError(e) raise cmdutils.CommandError(e)
@cmdutils.register(instance='config-commands') @cmdutils.register(instance='config-commands')
def config_edit(self, no_source=False): def config_edit(self, no_source=False):
@ -395,7 +395,7 @@ class ConfigCommands:
def on_file_updated(): def on_file_updated():
"""Source the new config when editing finished. """Source the new config when editing finished.
This can't use cmdexc.CommandError as it's run async. This can't use cmdutils.CommandError as it's run async.
""" """
try: try:
configfiles.read_config_py(filename) configfiles.read_config_py(filename)
@ -426,8 +426,8 @@ class ConfigCommands:
filename = os.path.expanduser(filename) filename = os.path.expanduser(filename)
if os.path.exists(filename) and not force: if os.path.exists(filename) and not force:
raise cmdexc.CommandError("{} already exists - use --force to " raise cmdutils.CommandError("{} already exists - use --force to "
"overwrite!".format(filename)) "overwrite!".format(filename))
if defaults: if defaults:
options = [(None, opt, opt.default) options = [(None, opt, opt.default)
@ -447,4 +447,4 @@ class ConfigCommands:
try: try:
writer.write(filename) writer.write(filename)
except OSError as e: except OSError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))

View File

@ -19,7 +19,8 @@
"""Keyboard macro system.""" """Keyboard macro system."""
from qutebrowser.commands import cmdexc, cmdutils, runners from qutebrowser.commands import runners
from qutebrowser.api import cmdutils
from qutebrowser.keyinput import modeman from qutebrowser.keyinput import modeman
from qutebrowser.utils import message, objreg, usertypes from qutebrowser.utils import message, objreg, usertypes
@ -89,12 +90,12 @@ class MacroRecorder:
"""Run a recorded macro.""" """Run a recorded macro."""
if register == '@': if register == '@':
if self._last_register is None: if self._last_register is None:
raise cmdexc.CommandError("No previous macro") raise cmdutils.CommandError("No previous macro")
register = self._last_register register = self._last_register
self._last_register = register self._last_register = register
if register not in self._macros: if register not in self._macros:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"No macro recorded in '{}'!".format(register)) "No macro recorded in '{}'!".format(register))
commandrunner = runners.CommandRunner(win_id) commandrunner = runners.CommandRunner(win_id)

View File

@ -27,7 +27,7 @@ from PyQt5.QtWidgets import QApplication
from qutebrowser.keyinput import modeparsers from qutebrowser.keyinput import modeparsers
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.api import cmdutils
from qutebrowser.utils import usertypes, log, objreg, utils from qutebrowser.utils import usertypes, log, objreg, utils
INPUT_MODES = [usertypes.KeyMode.insert, usertypes.KeyMode.passthrough] INPUT_MODES = [usertypes.KeyMode.insert, usertypes.KeyMode.passthrough]
@ -282,11 +282,11 @@ class ModeManager(QObject):
try: try:
m = usertypes.KeyMode[mode] m = usertypes.KeyMode[mode]
except KeyError: except KeyError:
raise cmdexc.CommandError("Mode {} does not exist!".format(mode)) raise cmdutils.CommandError("Mode {} does not exist!".format(mode))
if m in [usertypes.KeyMode.hint, usertypes.KeyMode.command, if m in [usertypes.KeyMode.hint, usertypes.KeyMode.command,
usertypes.KeyMode.yesno, usertypes.KeyMode.prompt]: usertypes.KeyMode.yesno, usertypes.KeyMode.prompt]:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"Mode {} can't be entered manually!".format(mode)) "Mode {} can't be entered manually!".format(mode))
self.enter(m, 'command') self.enter(m, 'command')

View File

@ -28,7 +28,8 @@ from PyQt5.QtCore import (pyqtSlot, QRect, QPoint, QTimer, Qt,
QCoreApplication, QEventLoop) QCoreApplication, QEventLoop)
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QSizePolicy from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QSizePolicy
from qutebrowser.commands import runners, cmdutils from qutebrowser.commands import runners
from qutebrowser.api import cmdutils
from qutebrowser.config import config, configfiles from qutebrowser.config import config, configfiles
from qutebrowser.utils import (message, log, usertypes, qtutils, objreg, utils, from qutebrowser.utils import (message, log, usertypes, qtutils, objreg, utils,
jinja) jinja)

View File

@ -34,7 +34,7 @@ from qutebrowser.browser import downloads
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import usertypes, log, utils, qtutils, objreg, message from qutebrowser.utils import usertypes, log, utils, qtutils, objreg, message
from qutebrowser.keyinput import modeman from qutebrowser.keyinput import modeman
from qutebrowser.commands import cmdutils, cmdexc from qutebrowser.api import cmdutils
from qutebrowser.qt import sip from qutebrowser.qt import sip
@ -384,7 +384,7 @@ class PromptContainer(QWidget):
try: try:
done = self._prompt.accept(value) done = self._prompt.accept(value)
except Error as e: except Error as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
if done: if done:
message.global_bridge.prompt_done.emit(self._prompt.KEY_MODE) message.global_bridge.prompt_done.emit(self._prompt.KEY_MODE)
question.done() question.done()

View File

@ -25,7 +25,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize
from PyQt5.QtWidgets import QSizePolicy from PyQt5.QtWidgets import QSizePolicy
from qutebrowser.keyinput import modeman, modeparsers from qutebrowser.keyinput import modeman, modeparsers
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.api import cmdutils
from qutebrowser.misc import cmdhistory, editor from qutebrowser.misc import cmdhistory, editor
from qutebrowser.misc import miscwidgets as misc from qutebrowser.misc import miscwidgets as misc
from qutebrowser.utils import usertypes, log, objreg, message, utils from qutebrowser.utils import usertypes, log, objreg, message, utils
@ -137,11 +137,11 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
text += ' ' text += ' '
if append: if append:
if not self.text(): if not self.text():
raise cmdexc.CommandError("No current text!") raise cmdutils.CommandError("No current text!")
text = self.text() + text text = self.text() + text
if not text or text[0] not in modeparsers.STARTCHARS: if not text or text[0] not in modeparsers.STARTCHARS:
raise cmdexc.CommandError( raise cmdutils.CommandError(
"Invalid command text '{}'.".format(text)) "Invalid command text '{}'.".format(text))
if run_on_count and count is not None: if run_on_count and count is not None:
self.got_cmd[str, int].emit(text, count) self.got_cmd[str, int].emit(text, count)

View File

@ -37,7 +37,7 @@ import attr
from PyQt5.QtCore import (pyqtSlot, qInstallMessageHandler, QObject, from PyQt5.QtCore import (pyqtSlot, qInstallMessageHandler, QObject,
QSocketNotifier, QTimer, QUrl) QSocketNotifier, QTimer, QUrl)
from qutebrowser.commands import cmdutils from qutebrowser.api import cmdutils
from qutebrowser.misc import earlyinit, crashdialog, ipc from qutebrowser.misc import earlyinit, crashdialog, ipc
from qutebrowser.utils import usertypes, standarddir, log, objreg, debug, utils from qutebrowser.utils import usertypes, standarddir, log, objreg, debug, utils

View File

@ -21,7 +21,7 @@
from PyQt5.QtWidgets import QApplication, QLineEdit from PyQt5.QtWidgets import QApplication, QLineEdit
from qutebrowser.commands import cmdutils from qutebrowser.api import cmdutils
from qutebrowser.utils import usertypes as typ from qutebrowser.utils import usertypes as typ
from qutebrowser.utils import utils from qutebrowser.utils import utils

View File

@ -25,7 +25,7 @@ import collections
from PyQt5.QtCore import pyqtSlot, QObject, QTimer from PyQt5.QtCore import pyqtSlot, QObject, QTimer
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.commands import cmdutils from qutebrowser.api import cmdutils
from qutebrowser.utils import utils, log, message, usertypes from qutebrowser.utils import utils, log, message, usertypes

View File

@ -31,7 +31,7 @@ import yaml
from qutebrowser.utils import (standarddir, objreg, qtutils, log, message, from qutebrowser.utils import (standarddir, objreg, qtutils, log, message,
utils) utils)
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.api import cmdutils
from qutebrowser.config import config, configfiles from qutebrowser.config import config, configfiles
from qutebrowser.completion.models import miscmodels from qutebrowser.completion.models import miscmodels
from qutebrowser.mainwindow import mainwindow from qutebrowser.mainwindow import mainwindow
@ -480,16 +480,17 @@ class SessionManager(QObject):
delete: Delete the saved session once it has loaded. delete: Delete the saved session once it has loaded.
""" """
if name.startswith('_') and not force: if name.startswith('_') and not force:
raise cmdexc.CommandError("{} is an internal session, use --force " raise cmdutils.CommandError("{} is an internal session, use "
"to load anyways.".format(name)) "--force to load anyways."
.format(name))
old_windows = list(objreg.window_registry.values()) old_windows = list(objreg.window_registry.values())
try: try:
self.load(name, temp=temp) self.load(name, temp=temp)
except SessionNotFoundError: except SessionNotFoundError:
raise cmdexc.CommandError("Session {} not found!".format(name)) raise cmdutils.CommandError("Session {} not found!".format(name))
except SessionError as e: except SessionError as e:
raise cmdexc.CommandError("Error while loading session: {}" raise cmdutils.CommandError("Error while loading session: {}"
.format(e)) .format(e))
else: else:
if clear: if clear:
for win in old_windows: for win in old_windows:
@ -499,9 +500,8 @@ class SessionManager(QObject):
self.delete(name) self.delete(name)
except SessionError as e: except SessionError as e:
log.sessions.exception("Error while deleting session!") log.sessions.exception("Error while deleting session!")
raise cmdexc.CommandError( raise cmdutils.CommandError("Error while deleting "
"Error while deleting session: {}" "session: {}".format(e))
.format(e))
else: else:
log.sessions.debug( log.sessions.debug(
"Loaded & deleted session {}.".format(name)) "Loaded & deleted session {}.".format(name))
@ -531,11 +531,12 @@ class SessionManager(QObject):
if (not isinstance(name, Sentinel) and if (not isinstance(name, Sentinel) and
name.startswith('_') and name.startswith('_') and
not force): not force):
raise cmdexc.CommandError("{} is an internal session, use --force " raise cmdutils.CommandError("{} is an internal session, use "
"to save anyways.".format(name)) "--force to save anyways."
.format(name))
if current: if current:
if self._current is None: if self._current is None:
raise cmdexc.CommandError("No session loaded currently!") raise cmdutils.CommandError("No session loaded currently!")
name = self._current name = self._current
assert not name.startswith('_') assert not name.startswith('_')
try: try:
@ -545,8 +546,8 @@ class SessionManager(QObject):
else: else:
name = self.save(name, with_private=with_private) name = self.save(name, with_private=with_private)
except SessionError as e: except SessionError as e:
raise cmdexc.CommandError("Error while saving session: {}" raise cmdutils.CommandError("Error while saving session: {}"
.format(e)) .format(e))
else: else:
if quiet: if quiet:
log.sessions.debug("Saved session {}.".format(name)) log.sessions.debug("Saved session {}.".format(name))
@ -564,15 +565,16 @@ class SessionManager(QObject):
underline). underline).
""" """
if name.startswith('_') and not force: if name.startswith('_') and not force:
raise cmdexc.CommandError("{} is an internal session, use --force " raise cmdutils.CommandError("{} is an internal session, use "
"to delete anyways.".format(name)) "--force to delete anyways."
.format(name))
try: try:
self.delete(name) self.delete(name)
except SessionNotFoundError: except SessionNotFoundError:
raise cmdexc.CommandError("Session {} not found!".format(name)) raise cmdutils.CommandError("Session {} not found!".format(name))
except SessionError as e: except SessionError as e:
log.sessions.exception("Error while deleting session!") log.sessions.exception("Error while deleting session!")
raise cmdexc.CommandError("Error while deleting session: {}" raise cmdutils.CommandError("Error while deleting session: {}"
.format(e)) .format(e))
else: else:
log.sessions.debug("Deleted session {}.".format(name)) log.sessions.debug("Deleted session {}.".format(name))

View File

@ -35,7 +35,8 @@ from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
from qutebrowser.browser import qutescheme from qutebrowser.browser import qutescheme
from qutebrowser.utils import log, objreg, usertypes, message, debug, utils from qutebrowser.utils import log, objreg, usertypes, message, debug, utils
from qutebrowser.commands import cmdutils, runners, cmdexc from qutebrowser.commands import runners
from qutebrowser.api import cmdutils
from qutebrowser.config import config, configdata from qutebrowser.config import config, configdata
from qutebrowser.misc import consolewidget from qutebrowser.misc import consolewidget
from qutebrowser.utils.version import pastebin_version from qutebrowser.utils.version import pastebin_version
@ -52,7 +53,7 @@ def later(ms: int, command: str, win_id: int) -> None:
command: The command to run, with optional args. command: The command to run, with optional args.
""" """
if ms < 0: if ms < 0:
raise cmdexc.CommandError("I can't run something in the past!") raise cmdutils.CommandError("I can't run something in the past!")
commandrunner = runners.CommandRunner(win_id) commandrunner = runners.CommandRunner(win_id)
app = objreg.get('app') app = objreg.get('app')
timer = usertypes.Timer(name='later', parent=app) timer = usertypes.Timer(name='later', parent=app)
@ -61,8 +62,8 @@ def later(ms: int, command: str, win_id: int) -> None:
try: try:
timer.setInterval(ms) timer.setInterval(ms)
except OverflowError: except OverflowError:
raise cmdexc.CommandError("Numeric argument is too large for " raise cmdutils.CommandError("Numeric argument is too large for "
"internal int representation.") "internal int representation.")
timer.timeout.connect( timer.timeout.connect(
functools.partial(commandrunner.run_safely, command)) functools.partial(commandrunner.run_safely, command))
timer.timeout.connect(timer.deleteLater) timer.timeout.connect(timer.deleteLater)
@ -87,7 +88,7 @@ def repeat(times: int, command: str, win_id: int, count: int = None) -> None:
times *= count times *= count
if times < 0: if times < 0:
raise cmdexc.CommandError("A negative count doesn't make sense.") raise cmdutils.CommandError("A negative count doesn't make sense.")
commandrunner = runners.CommandRunner(win_id) commandrunner = runners.CommandRunner(win_id)
for _ in range(times): for _ in range(times):
commandrunner.run_safely(command) commandrunner.run_safely(command)
@ -227,12 +228,12 @@ def debug_trace(expr=""):
expr: What to trace, passed to hunter. expr: What to trace, passed to hunter.
""" """
if hunter is None: if hunter is None:
raise cmdexc.CommandError("You need to install 'hunter' to use this " raise cmdutils.CommandError("You need to install 'hunter' to use this "
"command!") "command!")
try: try:
eval('hunter.trace({})'.format(expr)) eval('hunter.trace({})'.format(expr))
except Exception as e: except Exception as e:
raise cmdexc.CommandError("{}: {}".format(e.__class__.__name__, e)) raise cmdutils.CommandError("{}: {}".format(e.__class__.__name__, e))
@cmdutils.register(maxsplit=0, debug=True, no_cmd_split=True) @cmdutils.register(maxsplit=0, debug=True, no_cmd_split=True)
@ -251,7 +252,7 @@ def debug_pyeval(s, file=False, quiet=False):
with open(path, 'r', encoding='utf-8') as f: with open(path, 'r', encoding='utf-8') as f:
s = f.read() s = f.read()
except OSError as e: except OSError as e:
raise cmdexc.CommandError(str(e)) raise cmdutils.CommandError(str(e))
try: try:
exec(s) exec(s)
out = "No error" out = "No error"
@ -297,7 +298,7 @@ def repeat_command(win_id, count=None):
""" """
mode_manager = objreg.get('mode-manager', scope='window', window=win_id) mode_manager = objreg.get('mode-manager', scope='window', window=win_id)
if mode_manager.mode not in runners.last_command: if mode_manager.mode not in runners.last_command:
raise cmdexc.CommandError("You didn't do anything yet.") raise cmdutils.CommandError("You didn't do anything yet.")
cmd = runners.last_command[mode_manager.mode] cmd = runners.last_command[mode_manager.mode]
commandrunner = runners.CommandRunner(win_id) commandrunner = runners.CommandRunner(win_id)
commandrunner.run(cmd[0], count if count is not None else cmd[1]) commandrunner.run(cmd[0], count if count is not None else cmd[1])
@ -311,7 +312,7 @@ def log_capacity(capacity: int) -> None:
capacity: Number of lines for the log. capacity: Number of lines for the log.
""" """
if capacity < 0: if capacity < 0:
raise cmdexc.CommandError("Can't set a negative log capacity!") raise cmdutils.CommandError("Can't set a negative log capacity!")
else: else:
assert log.ram_handler is not None assert log.ram_handler is not None
log.ram_handler.change_log_capacity(capacity) log.ram_handler.change_log_capacity(capacity)
@ -341,17 +342,17 @@ def debug_log_filter(filters: str) -> None:
clear any existing filters. clear any existing filters.
""" """
if log.console_filter is None: if log.console_filter is None:
raise cmdexc.CommandError("No log.console_filter. Not attached " raise cmdutils.CommandError("No log.console_filter. Not attached "
"to a console?") "to a console?")
if filters.strip().lower() == 'none': if filters.strip().lower() == 'none':
log.console_filter.names = None log.console_filter.names = None
return return
if not set(filters.split(',')).issubset(log.LOGGER_NAMES): if not set(filters.split(',')).issubset(log.LOGGER_NAMES):
raise cmdexc.CommandError("filters: Invalid value {} - expected one " raise cmdutils.CommandError("filters: Invalid value {} - expected one "
"of: {}".format(filters, "of: {}".format(
', '.join(log.LOGGER_NAMES))) filters, ', '.join(log.LOGGER_NAMES)))
log.console_filter.names = filters.split(',') log.console_filter.names = filters.split(',')

View File

@ -29,9 +29,9 @@ import urllib.parse
from PyQt5.QtCore import QUrl, QUrlQuery from PyQt5.QtCore import QUrl, QUrlQuery
from PyQt5.QtNetwork import QHostInfo, QHostAddress, QNetworkProxy from PyQt5.QtNetwork import QHostInfo, QHostAddress, QNetworkProxy
from qutebrowser.api import cmdutils
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import log, qtutils, message, utils from qutebrowser.utils import log, qtutils, message, utils
from qutebrowser.commands import cmdexc
from qutebrowser.browser.network import pac from qutebrowser.browser.network import pac
@ -361,7 +361,7 @@ def invalid_url_error(url, action):
def raise_cmdexc_if_invalid(url): def raise_cmdexc_if_invalid(url):
"""Check if the given QUrl is invalid, and if so, raise a CommandError.""" """Check if the given QUrl is invalid, and if so, raise a CommandError."""
if not url.isValid(): if not url.isValid():
raise cmdexc.CommandError(get_errstring(url)) raise cmdutils.CommandError(get_errstring(url))
def get_path_if_valid(pathstr, cwd=None, relative=False, check_exists=False): def get_path_if_valid(pathstr, cwd=None, relative=False, check_exists=False):

View File

@ -53,8 +53,8 @@ MsgType = enum.Enum('MsgType', 'insufficent_coverage, perfect_file')
PERFECT_FILES = [ PERFECT_FILES = [
(None, (None,
'commands/cmdexc.py'), 'commands/cmdexc.py'),
('tests/unit/commands/test_cmdutils.py', ('tests/unit/api/test_cmdutils.py',
'commands/cmdutils.py'), 'api/cmdutils.py'),
('tests/unit/commands/test_argparser.py', ('tests/unit/commands/test_argparser.py',
'commands/argparser.py'), 'commands/argparser.py'),

View File

@ -19,7 +19,7 @@
# pylint: disable=unused-variable # pylint: disable=unused-variable
"""Tests for qutebrowser.commands.cmdutils.""" """Tests for qutebrowser.api.cmdutils."""
import sys import sys
import logging import logging
@ -30,7 +30,8 @@ import enum
import pytest import pytest
from qutebrowser.misc import objects from qutebrowser.misc import objects
from qutebrowser.commands import cmdexc, argparser, command, cmdutils from qutebrowser.commands import cmdexc, argparser, command
from qutebrowser.api import cmdutils
from qutebrowser.utils import usertypes from qutebrowser.utils import usertypes
@ -59,7 +60,7 @@ class TestCheckOverflow:
def test_bad(self): def test_bad(self):
int32_max = 2 ** 31 - 1 int32_max = 2 ** 31 - 1
with pytest.raises(cmdexc.CommandError, match="Numeric argument is " with pytest.raises(cmdutils.CommandError, match="Numeric argument is "
"too large for internal int representation."): "too large for internal int representation."):
cmdutils.check_overflow(int32_max + 1, 'int') cmdutils.check_overflow(int32_max + 1, 'int')
@ -71,7 +72,7 @@ class TestCheckExclusive:
cmdutils.check_exclusive(flags, []) cmdutils.check_exclusive(flags, [])
def test_bad(self): def test_bad(self):
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match="Only one of -x/-y/-z can be given!"): match="Only one of -x/-y/-z can be given!"):
cmdutils.check_exclusive([True, True], 'xyz') cmdutils.check_exclusive([True, True], 'xyz')

View File

@ -26,7 +26,7 @@ from PyQt5.QtCore import QUrl
from qutebrowser.browser import history from qutebrowser.browser import history
from qutebrowser.utils import objreg, urlutils, usertypes from qutebrowser.utils import objreg, urlutils, usertypes
from qutebrowser.commands import cmdexc from qutebrowser.api import cmdutils
from qutebrowser.misc import sql from qutebrowser.misc import sql
@ -324,7 +324,7 @@ class TestDump:
def test_nonexistent(self, web_history, tmpdir): def test_nonexistent(self, web_history, tmpdir):
histfile = tmpdir / 'nonexistent' / 'history' histfile = tmpdir / 'nonexistent' / 'history'
with pytest.raises(cmdexc.CommandError): with pytest.raises(cmdutils.CommandError):
web_history.debug_dump_history(str(histfile)) web_history.debug_dump_history(str(histfile))

View File

@ -26,7 +26,8 @@ from PyQt5.QtCore import QObject
from PyQt5.QtGui import QStandardItemModel from PyQt5.QtGui import QStandardItemModel
from qutebrowser.completion import completer from qutebrowser.completion import completer
from qutebrowser.commands import command, cmdutils from qutebrowser.commands import command
from qutebrowser.api import cmdutils
class FakeCompletionModel(QStandardItemModel): class FakeCompletionModel(QStandardItemModel):

View File

@ -28,7 +28,7 @@ from PyQt5.QtCore import QModelIndex
from qutebrowser.completion.models import completionmodel, listcategory from qutebrowser.completion.models import completionmodel, listcategory
from qutebrowser.utils import qtutils from qutebrowser.utils import qtutils
from qutebrowser.commands import cmdexc from qutebrowser.api import cmdutils
@hypothesis.given(strategies.lists( @hypothesis.given(strategies.lists(
@ -102,7 +102,7 @@ def test_delete_cur_item_no_func():
model.rowsRemoved.connect(callback) model.rowsRemoved.connect(callback)
model.add_category(cat) model.add_category(cat)
parent = model.index(0, 0) parent = model.index(0, 0)
with pytest.raises(cmdexc.CommandError): with pytest.raises(cmdutils.CommandError):
model.delete_cur_item(model.index(0, 0, parent)) model.delete_cur_item(model.index(0, 0, parent))
callback.assert_not_called() callback.assert_not_called()

View File

@ -25,7 +25,7 @@ import pytest
from qutebrowser.completion import completionwidget from qutebrowser.completion import completionwidget
from qutebrowser.completion.models import completionmodel, listcategory from qutebrowser.completion.models import completionmodel, listcategory
from qutebrowser.commands import cmdexc from qutebrowser.api import cmdutils
@pytest.fixture @pytest.fixture
@ -241,7 +241,7 @@ def test_completion_item_del_no_selection(completionview):
cat = listcategory.ListCategory('', [('foo',)], delete_func=func) cat = listcategory.ListCategory('', [('foo',)], delete_func=func)
model.add_category(cat) model.add_category(cat)
completionview.set_model(model) completionview.set_model(model)
with pytest.raises(cmdexc.CommandError, match='No item selected!'): with pytest.raises(cmdutils.CommandError, match='No item selected!'):
completionview.completion_item_del() completionview.completion_item_del()
func.assert_not_called() func.assert_not_called()

View File

@ -26,7 +26,7 @@ import pytest
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from qutebrowser.config import configcommands, configutils from qutebrowser.config import configcommands, configutils
from qutebrowser.commands import cmdexc from qutebrowser.api import cmdutils
from qutebrowser.utils import usertypes, urlmatch from qutebrowser.utils import usertypes, urlmatch
from qutebrowser.keyinput import keyutils from qutebrowser.keyinput import keyutils
from qutebrowser.misc import objects from qutebrowser.misc import objects
@ -108,7 +108,7 @@ class TestSet:
monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebKit) monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebKit)
option = 'content.javascript.enabled' option = 'content.javascript.enabled'
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match=('Error while parsing http://: Pattern ' match=('Error while parsing http://: Pattern '
'without host')): 'without host')):
commands.set(0, option, 'false', pattern='http://') commands.set(0, option, 'false', pattern='http://')
@ -118,7 +118,7 @@ class TestSet:
Should show an error as patterns are unsupported. Should show an error as patterns are unsupported.
""" """
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match='does not support URL patterns'): match='does not support URL patterns'):
commands.set(0, 'colors.statusbar.normal.bg', '#abcdef', commands.set(0, 'colors.statusbar.normal.bg', '#abcdef',
pattern='*://*') pattern='*://*')
@ -165,7 +165,7 @@ class TestSet:
Should show an error. Should show an error.
""" """
with pytest.raises(cmdexc.CommandError, match="No option 'foo'"): with pytest.raises(cmdutils.CommandError, match="No option 'foo'"):
commands.set(0, 'foo', 'bar') commands.set(0, 'foo', 'bar')
def test_set_invalid_value(self, commands): def test_set_invalid_value(self, commands):
@ -173,13 +173,13 @@ class TestSet:
Should show an error. Should show an error.
""" """
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match="Invalid value 'blah' - must be a boolean!"): match="Invalid value 'blah' - must be a boolean!"):
commands.set(0, 'auto_save.session', 'blah') commands.set(0, 'auto_save.session', 'blah')
def test_set_wrong_backend(self, commands, monkeypatch): def test_set_wrong_backend(self, commands, monkeypatch):
monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebEngine) monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebEngine)
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match="The hints.find_implementation setting is " match="The hints.find_implementation setting is "
"not available with the QtWebEngine backend!"): "not available with the QtWebEngine backend!"):
commands.set(0, 'hints.find_implementation', 'javascript') commands.set(0, 'hints.find_implementation', 'javascript')
@ -190,7 +190,7 @@ class TestSet:
Should show an error. Should show an error.
See https://github.com/qutebrowser/qutebrowser/issues/1109 See https://github.com/qutebrowser/qutebrowser/issues/1109
""" """
with pytest.raises(cmdexc.CommandError, match="No option '?'"): with pytest.raises(cmdutils.CommandError, match="No option '?'"):
commands.set(win_id=0, option='?') commands.set(win_id=0, option='?')
def test_toggle(self, commands): def test_toggle(self, commands):
@ -198,7 +198,7 @@ class TestSet:
Should show an nicer error. Should show an nicer error.
""" """
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match="Toggling values was moved to the " match="Toggling values was moved to the "
":config-cycle command"): ":config-cycle command"):
commands.set(win_id=0, option='javascript.enabled!') commands.set(win_id=0, option='javascript.enabled!')
@ -208,7 +208,7 @@ class TestSet:
Should show an error. Should show an error.
""" """
with pytest.raises(cmdexc.CommandError, match="No option 'foo'"): with pytest.raises(cmdutils.CommandError, match="No option 'foo'"):
commands.set(win_id=0, option='foo?') commands.set(win_id=0, option='foo?')
@ -267,7 +267,7 @@ class TestCycle:
Should show an error. Should show an error.
""" """
assert config_stub.val.url.auto_search == 'naive' assert config_stub.val.url.auto_search == 'naive'
with pytest.raises(cmdexc.CommandError, match="Need at least " with pytest.raises(cmdutils.CommandError, match="Need at least "
"two values for non-boolean settings."): "two values for non-boolean settings."):
commands.config_cycle(*args) commands.config_cycle(*args)
assert config_stub.val.url.auto_search == 'naive' assert config_stub.val.url.auto_search == 'naive'
@ -301,14 +301,14 @@ class TestAdd:
def test_list_add_non_list(self, commands): def test_list_add_non_list(self, commands):
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match=":config-list-add can only be used for lists"): match=":config-list-add can only be used for lists"):
commands.config_list_add('history_gap_interval', 'value') commands.config_list_add('history_gap_interval', 'value')
@pytest.mark.parametrize('value', ['', None, 42]) @pytest.mark.parametrize('value', ['', None, 42])
def test_list_add_invalid_values(self, commands, value): def test_list_add_invalid_values(self, commands, value):
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match="Invalid value '{}'".format(value)): match="Invalid value '{}'".format(value)):
commands.config_list_add('content.host_blocking.whitelist', value) commands.config_list_add('content.host_blocking.whitelist', value)
@ -337,20 +337,20 @@ class TestAdd:
assert str(config_stub.get(name)[key]) == value assert str(config_stub.get(name)[key]) == value
else: else:
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match="w already exists in aliases - use --replace to " match="w already exists in aliases - use --replace to "
"overwrite!"): "overwrite!"):
commands.config_dict_add(name, key, value, replace=False) commands.config_dict_add(name, key, value, replace=False)
def test_dict_add_non_dict(self, commands): def test_dict_add_non_dict(self, commands):
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match=":config-dict-add can only be used for dicts"): match=":config-dict-add can only be used for dicts"):
commands.config_dict_add('history_gap_interval', 'key', 'value') commands.config_dict_add('history_gap_interval', 'key', 'value')
@pytest.mark.parametrize('value', ['', None, 42]) @pytest.mark.parametrize('value', ['', None, 42])
def test_dict_add_invalid_values(self, commands, value): def test_dict_add_invalid_values(self, commands, value):
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match="Invalid value '{}'".format(value)): match="Invalid value '{}'".format(value)):
commands.config_dict_add('aliases', 'missingkey', value) commands.config_dict_add('aliases', 'missingkey', value)
@ -373,14 +373,14 @@ class TestRemove:
def test_list_remove_non_list(self, commands): def test_list_remove_non_list(self, commands):
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match=":config-list-remove can only be used for lists"): match=":config-list-remove can only be used for lists"):
commands.config_list_remove('content.javascript.enabled', commands.config_list_remove('content.javascript.enabled',
'never') 'never')
def test_list_remove_no_value(self, commands): def test_list_remove_no_value(self, commands):
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match="never is not in colors.completion.fg!"): match="never is not in colors.completion.fg!"):
commands.config_list_remove('colors.completion.fg', 'never') commands.config_list_remove('colors.completion.fg', 'never')
@ -398,14 +398,14 @@ class TestRemove:
def test_dict_remove_non_dict(self, commands): def test_dict_remove_non_dict(self, commands):
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match=":config-dict-remove can only be used for dicts"): match=":config-dict-remove can only be used for dicts"):
commands.config_dict_remove('content.javascript.enabled', commands.config_dict_remove('content.javascript.enabled',
'never') 'never')
def test_dict_remove_no_value(self, commands): def test_dict_remove_no_value(self, commands):
with pytest.raises( with pytest.raises(
cmdexc.CommandError, cmdutils.CommandError,
match="never is not in aliases!"): match="never is not in aliases!"):
commands.config_dict_remove('aliases', 'never') commands.config_dict_remove('aliases', 'never')
@ -425,7 +425,7 @@ class TestUnsetAndClear:
assert yaml_value(name) == ('never' if temp else configutils.UNSET) assert yaml_value(name) == ('never' if temp else configutils.UNSET)
def test_unset_unknown_option(self, commands): def test_unset_unknown_option(self, commands):
with pytest.raises(cmdexc.CommandError, match="No option 'tabs'"): with pytest.raises(cmdutils.CommandError, match="No option 'tabs'"):
commands.config_unset('tabs') commands.config_unset('tabs')
@pytest.mark.parametrize('save', [True, False]) @pytest.mark.parametrize('save', [True, False])
@ -472,7 +472,7 @@ class TestSource:
pyfile = config_tmpdir / 'config.py' pyfile = config_tmpdir / 'config.py'
pyfile.write_text('c.foo = 42', encoding='utf-8') pyfile.write_text('c.foo = 42', encoding='utf-8')
with pytest.raises(cmdexc.CommandError) as excinfo: with pytest.raises(cmdutils.CommandError) as excinfo:
commands.config_source() commands.config_source()
expected = ("Errors occurred while reading config.py:\n" expected = ("Errors occurred while reading config.py:\n"
@ -483,7 +483,7 @@ class TestSource:
pyfile = config_tmpdir / 'config.py' pyfile = config_tmpdir / 'config.py'
pyfile.write_text('1/0', encoding='utf-8') pyfile.write_text('1/0', encoding='utf-8')
with pytest.raises(cmdexc.CommandError) as excinfo: with pytest.raises(cmdutils.CommandError) as excinfo:
commands.config_source() commands.config_source()
expected = ("Errors occurred while reading config.py:\n" expected = ("Errors occurred while reading config.py:\n"
@ -582,7 +582,7 @@ class TestWritePy:
confpy = tmpdir / 'config.py' confpy = tmpdir / 'config.py'
confpy.ensure() confpy.ensure()
with pytest.raises(cmdexc.CommandError) as excinfo: with pytest.raises(cmdutils.CommandError) as excinfo:
commands.config_write_py(str(confpy)) commands.config_write_py(str(confpy))
expected = " already exists - use --force to overwrite!" expected = " already exists - use --force to overwrite!"
@ -599,7 +599,7 @@ class TestWritePy:
def test_oserror(self, commands, tmpdir): def test_oserror(self, commands, tmpdir):
"""Test writing to a directory which does not exist.""" """Test writing to a directory which does not exist."""
with pytest.raises(cmdexc.CommandError): with pytest.raises(cmdutils.CommandError):
commands.config_write_py(str(tmpdir / 'foo' / 'config.py')) commands.config_write_py(str(tmpdir / 'foo' / 'config.py'))
@ -709,7 +709,7 @@ class TestBind:
elif command == 'unbind': elif command == 'unbind':
func = commands.unbind func = commands.unbind
with pytest.raises(cmdexc.CommandError, match=expected): with pytest.raises(cmdutils.CommandError, match=expected):
func(*args, **kwargs) func(*args, **kwargs)
@pytest.mark.parametrize('key', ['a', 'b', '<Ctrl-X>']) @pytest.mark.parametrize('key', ['a', 'b', '<Ctrl-X>'])

View File

@ -28,7 +28,7 @@ import pytest
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from qutebrowser.misc import utilcmds from qutebrowser.misc import utilcmds
from qutebrowser.commands import cmdexc from qutebrowser.api import cmdutils
from qutebrowser.utils import utils, objreg from qutebrowser.utils import utils, objreg
@ -83,14 +83,14 @@ def test_debug_trace_exception(mocker):
hunter_mock = mocker.patch('qutebrowser.misc.utilcmds.hunter') hunter_mock = mocker.patch('qutebrowser.misc.utilcmds.hunter')
hunter_mock.trace.side_effect = _mock_exception hunter_mock.trace.side_effect = _mock_exception
with pytest.raises(cmdexc.CommandError, match='Exception: message'): with pytest.raises(cmdutils.CommandError, match='Exception: message'):
utilcmds.debug_trace() utilcmds.debug_trace()
def test_debug_trace_no_hunter(monkeypatch): def test_debug_trace_no_hunter(monkeypatch):
"""Test that an error is shown if debug_trace is called without hunter.""" """Test that an error is shown if debug_trace is called without hunter."""
monkeypatch.setattr(utilcmds, 'hunter', None) monkeypatch.setattr(utilcmds, 'hunter', None)
with pytest.raises(cmdexc.CommandError, match="You need to install " with pytest.raises(cmdutils.CommandError, match="You need to install "
"'hunter' to use this command!"): "'hunter' to use this command!"):
utilcmds.debug_trace() utilcmds.debug_trace()
@ -103,7 +103,7 @@ def test_repeat_command_initial(mocker, mode_manager):
""" """
objreg_mock = mocker.patch('qutebrowser.misc.utilcmds.objreg') objreg_mock = mocker.patch('qutebrowser.misc.utilcmds.objreg')
objreg_mock.get.return_value = mode_manager objreg_mock.get.return_value = mode_manager
with pytest.raises(cmdexc.CommandError, with pytest.raises(cmdutils.CommandError,
match="You didn't do anything yet."): match="You didn't do anything yet."):
utilcmds.repeat_command(win_id=0) utilcmds.repeat_command(win_id=0)

View File

@ -27,7 +27,7 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtNetwork import QNetworkProxy from PyQt5.QtNetwork import QNetworkProxy
import pytest import pytest
from qutebrowser.commands import cmdexc from qutebrowser.api import cmdutils
from qutebrowser.browser.network import pac from qutebrowser.browser.network import pac
from qutebrowser.utils import utils, urlutils, qtutils, usertypes from qutebrowser.utils import utils, urlutils, qtutils, usertypes
from helpers import utils as testutils from helpers import utils as testutils
@ -495,7 +495,7 @@ def test_raise_cmdexc_if_invalid(url, valid, has_err_string):
expected_text = "Invalid URL - " + qurl.errorString() expected_text = "Invalid URL - " + qurl.errorString()
else: else:
expected_text = "Invalid URL" expected_text = "Invalid URL"
with pytest.raises(cmdexc.CommandError, match=expected_text): with pytest.raises(cmdutils.CommandError, match=expected_text):
urlutils.raise_cmdexc_if_invalid(qurl) urlutils.raise_cmdexc_if_invalid(qurl)