From 995a0d19cc7949ea0f53cb992dc0f0f4b75f892a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 30 Apr 2014 10:41:25 +0200 Subject: [PATCH] Clean up command exception handling --- qutebrowser/app.py | 4 +- qutebrowser/commands/_command.py | 17 ++++---- qutebrowser/commands/_exceptions.py | 24 ++++++----- qutebrowser/commands/managers.py | 64 +++++++---------------------- qutebrowser/keyinput/keyparser.py | 15 ++++--- 5 files changed, 46 insertions(+), 78 deletions(-) diff --git a/qutebrowser/app.py b/qutebrowser/app.py index b34af1b83..a9bcaa840 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -228,7 +228,7 @@ class QuteBrowser(QApplication): for e in self._args.command: if e.startswith(':'): logging.debug("Startup cmd {}".format(e)) - self.commandmanager.run(e.lstrip(':')) + self.commandmanager.run_safely(e.lstrip(':')) else: logging.debug("Startup url {}".format(e)) self._opened_urls.append(e) @@ -273,7 +273,7 @@ class QuteBrowser(QApplication): modeman.manager.key_pressed.connect(status.on_key_pressed) # 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_rev.connect(self.searchmanager.search_rev) cmd.returnPressed.connect(tabs.setFocus) diff --git a/qutebrowser/commands/_command.py b/qutebrowser/commands/_command.py index 0cd0cc386..678360f75 100644 --- a/qutebrowser/commands/_command.py +++ b/qutebrowser/commands/_command.py @@ -20,7 +20,7 @@ import logging from qutebrowser.commands._exceptions import (ArgumentCountError, - InvalidModeError, NeedsJSError) + PrerequisitesError) from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtWebKit import QWebSettings @@ -83,19 +83,22 @@ class Command(QObject): Raise: 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 if self.modes is not None and modeman.manager.mode not in self.modes: - raise InvalidModeError("This command is only allowed in {} " - "mode.".format('/'.join(self.modes))) + raise PrerequisitesError("{}: This command is only allowed in {} " + "mode.".format(self.name, + '/'.join(self.modes))) elif (self.not_modes is not None and modeman.manager.mode in self.not_modes): - raise InvalidModeError("This command is not allowed in {} " - "mode.".format('/'.join(self.not_modes))) + raise PrerequisitesError("{}: This command is not allowed in {} " + "mode.".format(self.name, + '/'.join(self.not_modes))) if self.needs_js and not QWebSettings.globalSettings().testAttribute( 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): pass elif self.nargs[0] <= len(args) <= self.nargs[1]: diff --git a/qutebrowser/commands/_exceptions.py b/qutebrowser/commands/_exceptions.py index 17fadb22c..fccaa368a 100644 --- a/qutebrowser/commands/_exceptions.py +++ b/qutebrowser/commands/_exceptions.py @@ -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.""" pass -class ArgumentCountError(TypeError): +class ArgumentCountError(CommandError): """Raised when a command was called with an invalid count of arguments.""" pass -class InvalidModeError(Exception): +class PrerequisitesError(CommandError): - """Raised when a command is called in a wrong input mode.""" - - pass - - -class NeedsJSError(Exception): - - """Raised when a command needs javascript but it is disabled.""" + """Raised when a cmd can't be used because some prerequisites aren't met. + + 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. + """ pass diff --git a/qutebrowser/commands/managers.py b/qutebrowser/commands/managers.py index 8c553fb92..6ac0ab59f 100644 --- a/qutebrowser/commands/managers.py +++ b/qutebrowser/commands/managers.py @@ -23,8 +23,7 @@ from PyQt5.QtWebKitWidgets import QWebPage import qutebrowser.config.config as config import qutebrowser.commands.utils as cmdutils import qutebrowser.utils.message as message -from qutebrowser.commands._exceptions import ( - ArgumentCountError, NoSuchCommandError, InvalidModeError, NeedsJSError) +from qutebrowser.commands._exceptions import NoSuchCommandError, CommandError def split_cmdline(text): @@ -162,7 +161,7 @@ class CommandManager: try: cmd = cmdutils.cmd_dict[cmdstr] except KeyError: - raise NoSuchCommandError(cmdstr) + raise NoSuchCommandError('{}: no such command'.format(cmdstr)) if len(parts) == 1: args = [] @@ -187,59 +186,24 @@ class CommandManager: else: self._cmd.run(self._args) - @pyqtSlot(str, int, bool) - def run(self, text, count=None, ignore_exc=True): + def run(self, text, count=None): """Parse a command from a line of text. - If ignore_exc is True, ignore exceptions and return True/False. - Args: text: The text to parse. 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: - retvals = [] for sub in text.split(';;'): - retvals.append(self.run(sub, count, ignore_exc)) - return all(retvals) - try: - self.parse(text) - 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(sub, count) + self.parse(text) + self._check() 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)) diff --git a/qutebrowser/keyinput/keyparser.py b/qutebrowser/keyinput/keyparser.py index 121f7e366..472757987 100644 --- a/qutebrowser/keyinput/keyparser.py +++ b/qutebrowser/keyinput/keyparser.py @@ -22,8 +22,8 @@ import logging from qutebrowser.keyinput._basekeyparser import BaseKeyParser import qutebrowser.utils.message as message -from qutebrowser.commands.managers import (CommandManager, ArgumentCountError, - NoSuchCommandError) +from qutebrowser.commands.managers import CommandManager +from qutebrowser.commands._exceptions import ArgumentCountError, CommandError class CommandKeyParser(BaseKeyParser): @@ -39,25 +39,24 @@ class CommandKeyParser(BaseKeyParser): super().__init__(parent, supports_count, supports_chains) 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. Args: cmdstr: The command string. count: Optional command count. - ignore_exc: Ignore exceptions. """ try: - self.commandmanager.run(cmdstr, count=count, ignore_exc=ignore_exc) - except NoSuchCommandError: - pass + self.commandmanager.run(cmdstr, count=count) except ArgumentCountError: logging.debug("Filling statusbar with partial command {}".format( cmdstr)) message.set_cmd_text(':{} '.format(cmdstr)) + except CommandError as e: + message.error(str(e)) 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):