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:
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)

View File

@ -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]:

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."""
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

View File

@ -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))

View File

@ -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):