Clean up command exception handling

This commit is contained in:
Florian Bruhin 2014-04-30 10:41:25 +02:00
parent 689723508f
commit 995a0d19cc
5 changed files with 46 additions and 78 deletions

View File

@ -228,7 +228,7 @@ class QuteBrowser(QApplication):
for e in self._args.command: for e in self._args.command:
if e.startswith(':'): if e.startswith(':'):
logging.debug("Startup cmd {}".format(e)) logging.debug("Startup cmd {}".format(e))
self.commandmanager.run(e.lstrip(':')) self.commandmanager.run_safely(e.lstrip(':'))
else: else:
logging.debug("Startup url {}".format(e)) logging.debug("Startup url {}".format(e))
self._opened_urls.append(e) self._opened_urls.append(e)
@ -273,7 +273,7 @@ class QuteBrowser(QApplication):
modeman.manager.key_pressed.connect(status.on_key_pressed) modeman.manager.key_pressed.connect(status.on_key_pressed)
# commands # commands
cmd.got_cmd.connect(self.commandmanager.run) cmd.got_cmd.connect(self.commandmanager.run_safely)
cmd.got_search.connect(self.searchmanager.search) cmd.got_search.connect(self.searchmanager.search)
cmd.got_search_rev.connect(self.searchmanager.search_rev) cmd.got_search_rev.connect(self.searchmanager.search_rev)
cmd.returnPressed.connect(tabs.setFocus) cmd.returnPressed.connect(tabs.setFocus)

View File

@ -20,7 +20,7 @@
import logging import logging
from qutebrowser.commands._exceptions import (ArgumentCountError, from qutebrowser.commands._exceptions import (ArgumentCountError,
InvalidModeError, NeedsJSError) PrerequisitesError)
from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings
@ -83,19 +83,22 @@ class Command(QObject):
Raise: Raise:
ArgumentCountError if the argument count is wrong. ArgumentCountError if the argument count is wrong.
InvalidModeError if the command can't be called in this mode. PrerequisitesError if the command can't be called currently.
""" """
import qutebrowser.keyinput.modeman as modeman import qutebrowser.keyinput.modeman as modeman
if self.modes is not None and modeman.manager.mode not in self.modes: if self.modes is not None and modeman.manager.mode not in self.modes:
raise InvalidModeError("This command is only allowed in {} " raise PrerequisitesError("{}: This command is only allowed in {} "
"mode.".format('/'.join(self.modes))) "mode.".format(self.name,
'/'.join(self.modes)))
elif (self.not_modes is not None and elif (self.not_modes is not None and
modeman.manager.mode in self.not_modes): modeman.manager.mode in self.not_modes):
raise InvalidModeError("This command is not allowed in {} " raise PrerequisitesError("{}: This command is not allowed in {} "
"mode.".format('/'.join(self.not_modes))) "mode.".format(self.name,
'/'.join(self.not_modes)))
if self.needs_js and not QWebSettings.globalSettings().testAttribute( if self.needs_js and not QWebSettings.globalSettings().testAttribute(
QWebSettings.JavascriptEnabled): QWebSettings.JavascriptEnabled):
raise NeedsJSError raise PrerequisitesError("{}: This command needs javascript "
"enabled.".format(self.name))
if self.nargs[1] is None and self.nargs[0] <= len(args): if self.nargs[1] is None and self.nargs[0] <= len(args):
pass pass
elif self.nargs[0] <= len(args) <= self.nargs[1]: elif self.nargs[0] <= len(args) <= self.nargs[1]:

View File

@ -21,29 +21,31 @@ Defined here to avoid circular dependency hell.
""" """
class NoSuchCommandError(ValueError): class CommandError(Exception):
"""Common base class for all command exceptions."""
class NoSuchCommandError(CommandError):
"""Raised when a command wasn't found.""" """Raised when a command wasn't found."""
pass pass
class ArgumentCountError(TypeError): class ArgumentCountError(CommandError):
"""Raised when a command was called with an invalid count of arguments.""" """Raised when a command was called with an invalid count of arguments."""
pass pass
class InvalidModeError(Exception): class PrerequisitesError(CommandError):
"""Raised when a command is called in a wrong input mode.""" """Raised when a cmd can't be used because some prerequisites aren't met.
pass This is raised for example when we're in the wrong mode while executing the
command, or we need javascript enabled but don't have done so.
"""
class NeedsJSError(Exception):
"""Raised when a command needs javascript but it is disabled."""
pass pass

View File

@ -23,8 +23,7 @@ from PyQt5.QtWebKitWidgets import QWebPage
import qutebrowser.config.config as config import qutebrowser.config.config as config
import qutebrowser.commands.utils as cmdutils import qutebrowser.commands.utils as cmdutils
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
from qutebrowser.commands._exceptions import ( from qutebrowser.commands._exceptions import NoSuchCommandError, CommandError
ArgumentCountError, NoSuchCommandError, InvalidModeError, NeedsJSError)
def split_cmdline(text): def split_cmdline(text):
@ -162,7 +161,7 @@ class CommandManager:
try: try:
cmd = cmdutils.cmd_dict[cmdstr] cmd = cmdutils.cmd_dict[cmdstr]
except KeyError: except KeyError:
raise NoSuchCommandError(cmdstr) raise NoSuchCommandError('{}: no such command'.format(cmdstr))
if len(parts) == 1: if len(parts) == 1:
args = [] args = []
@ -187,59 +186,24 @@ class CommandManager:
else: else:
self._cmd.run(self._args) self._cmd.run(self._args)
@pyqtSlot(str, int, bool) def run(self, text, count=None):
def run(self, text, count=None, ignore_exc=True):
"""Parse a command from a line of text. """Parse a command from a line of text.
If ignore_exc is True, ignore exceptions and return True/False.
Args: Args:
text: The text to parse. text: The text to parse.
count: The count to pass to the command. count: The count to pass to the command.
ignore_exc: Ignore exceptions and return False instead.
Raise:
NoSuchCommandError: if a command wasn't found.
ArgumentCountError: if a command was called with the wrong count of
arguments.
InvalidModeError: if a command can't be called in this mode.
Return:
True if command was called (handler returnstatus is ignored!).
False if command wasn't called (there was an ignored exception).
""" """
if ';;' in text: if ';;' in text:
retvals = []
for sub in text.split(';;'): for sub in text.split(';;'):
retvals.append(self.run(sub, count, ignore_exc)) self.run(sub, count)
return all(retvals)
try:
self.parse(text) self.parse(text)
self._check() self._check()
except NoSuchCommandError as e:
if ignore_exc:
message.error("{}: no such command".format(e))
return False
else:
raise
except ArgumentCountError as e:
if ignore_exc:
message.error("{}: invalid argument count - {}".format(
self._cmd.name, e))
return False
else:
raise
except InvalidModeError as e:
if ignore_exc:
message.error("{}: {}".format(self._cmd.name, e))
return False
else:
raise
except NeedsJSError as e:
if ignore_exc:
message.error("{}: {}".format(self._cmd.name, e))
return False
else:
raise
self._run(count=count) self._run(count=count)
return True
@pyqtSlot(str, int)
def run_safely(self, text, count=None):
"""Run a command and display exceptions in the statusbar."""
try:
self.run(text, count)
except CommandError as e:
message.error(str(e))

View File

@ -22,8 +22,8 @@ import logging
from qutebrowser.keyinput._basekeyparser import BaseKeyParser from qutebrowser.keyinput._basekeyparser import BaseKeyParser
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
from qutebrowser.commands.managers import (CommandManager, ArgumentCountError, from qutebrowser.commands.managers import CommandManager
NoSuchCommandError) from qutebrowser.commands._exceptions import ArgumentCountError, CommandError
class CommandKeyParser(BaseKeyParser): class CommandKeyParser(BaseKeyParser):
@ -39,25 +39,24 @@ class CommandKeyParser(BaseKeyParser):
super().__init__(parent, supports_count, supports_chains) super().__init__(parent, supports_count, supports_chains)
self.commandmanager = CommandManager() self.commandmanager = CommandManager()
def _run_or_fill(self, cmdstr, count=None, ignore_exc=True): def _run_or_fill(self, cmdstr, count=None):
"""Run the command in cmdstr or fill the statusbar if args missing. """Run the command in cmdstr or fill the statusbar if args missing.
Args: Args:
cmdstr: The command string. cmdstr: The command string.
count: Optional command count. count: Optional command count.
ignore_exc: Ignore exceptions.
""" """
try: try:
self.commandmanager.run(cmdstr, count=count, ignore_exc=ignore_exc) self.commandmanager.run(cmdstr, count=count)
except NoSuchCommandError:
pass
except ArgumentCountError: except ArgumentCountError:
logging.debug("Filling statusbar with partial command {}".format( logging.debug("Filling statusbar with partial command {}".format(
cmdstr)) cmdstr))
message.set_cmd_text(':{} '.format(cmdstr)) message.set_cmd_text(':{} '.format(cmdstr))
except CommandError as e:
message.error(str(e))
def execute(self, cmdstr, _keytype, count=None): def execute(self, cmdstr, _keytype, count=None):
self._run_or_fill(cmdstr, count, ignore_exc=False) self._run_or_fill(cmdstr, count)
class PassthroughKeyParser(CommandKeyParser): class PassthroughKeyParser(CommandKeyParser):