Improved error handling in the command system

This commit is contained in:
red-agent 2009-09-12 23:22:50 +03:00
parent ae0f32d922
commit 981572f79d
2 changed files with 31 additions and 22 deletions

View File

@ -25,6 +25,20 @@ from inspect import getargspec
class CommandInternalError(Exception): class CommandInternalError(Exception):
pass pass
class CommandError(Exception):
def __init__(self, message=None, command=None, name=None):
if command:
self.command = command
self.name = command.first_name
elif name:
self.command = None
self.name = name
if message:
super(CommandError, self).__init__(message)
else:
super(CommandError, self).__init__()
class Command(object): class Command(object):
DOC_STRIP_PATTERN = re.compile(r'(?:^[ \t]+|\A\n)', re.MULTILINE) DOC_STRIP_PATTERN = re.compile(r'(?:^[ \t]+|\A\n)', re.MULTILINE)
@ -43,7 +57,13 @@ class Command(object):
self.empty = empty self.empty = empty
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
return self.handler(*args, **kwargs) try:
return self.handler(*args, **kwargs)
except CommandError, exception:
if not exception.command and not exception.name:
raise CommandError(exception.message, self)
except TypeError:
raise CommandError("Command received invalid arguments", self)
def __repr__(self): def __repr__(self):
return "<Command %s>" % ', '.join(self.names) return "<Command %s>" % ', '.join(self.names)
@ -56,7 +76,7 @@ class Command(object):
@property @property
def first_name(self): def first_name(self):
return self.names[0] return self.names[0]
@property @property
def native_name(self): def native_name(self):
@ -162,14 +182,6 @@ class Command(object):
return usage if not complete else self.ARG_USAGE_PATTERN % (names, usage) return usage if not complete else self.ARG_USAGE_PATTERN % (names, usage)
class CommandError(Exception):
def __init__(self, command, *args, **kwargs):
if isinstance(command, Command):
self.command = command
self.name = command.first_name
self.name = command
super(Exception, self).__init__(*args, **kwargs)
class Dispatcher(type): class Dispatcher(type):
table = {} table = {}
hosted = {} hosted = {}
@ -180,7 +192,7 @@ class Dispatcher(type):
if Dispatcher.is_suitable(cls, dct): if Dispatcher.is_suitable(cls, dct):
Dispatcher.register_processor(cls) Dispatcher.register_processor(cls)
# Sanitize names even if processor is not suitable for registering, # Sanitize names even if processor is not suitable for registering,
# because it might be inherited by an another processor. # because it might be inherited by an another processor.
Dispatcher.sanitize_names(cls) Dispatcher.sanitize_names(cls)
@ -226,7 +238,7 @@ class Dispatcher(type):
if 'HOSTED_BY' in proc.__dict__: if 'HOSTED_BY' in proc.__dict__:
cls.register_adhocs(proc) cls.register_adhocs(proc)
commands = cls.traverse_commands(proc, inherited) commands = cls.traverse_commands(proc, inherited)
cls.register_commands(proc, commands) cls.register_commands(proc, commands)
@ -362,7 +374,7 @@ class CommandProcessor(object):
name = cls.prepare_name(name) name = cls.prepare_name(name)
command = Dispatcher.retrieve_command(cls, name) command = Dispatcher.retrieve_command(cls, name)
if not command: if not command:
raise CommandError(name, "Command does not exist") raise CommandError("Command does not exist", name=name)
return command return command
@classmethod @classmethod
@ -446,7 +458,7 @@ class CommandProcessor(object):
if len(spec_args) == 1: if len(spec_args) == 1:
if arguments or command.empty: if arguments or command.empty:
return (arguments,), {} return (arguments,), {}
raise CommandError(command, "Can not be used without arguments") raise CommandError("Can not be used without arguments", command)
raise CommandInternalError("Raw command must define no more then one argument") raise CommandInternalError("Raw command must define no more then one argument")
if '__optional__' in spec_args: if '__optional__' in spec_args:
@ -520,13 +532,10 @@ class CommandProcessor(object):
args, kwargs = self.parse_command_arguments(arguments) if arguments else ([], {}) args, kwargs = self.parse_command_arguments(arguments) if arguments else ([], {})
args, kwargs = self.adapt_command_arguments(command, arguments, args, kwargs) args, kwargs = self.adapt_command_arguments(command, arguments, args, kwargs)
try: if self.command_preprocessor(name, command, arguments, args, kwargs):
if self.command_preprocessor(name, command, arguments, args, kwargs): return
return value = command(self, *args, **kwargs)
value = command(self, *args, **kwargs) self.command_postprocessor(name, command, arguments, args, kwargs, value)
self.command_postprocessor(name, command, arguments, args, kwargs, value)
except TypeError:
raise CommandError(name, "Command received invalid arguments")
def command_preprocessor(self, name, command, arguments, args, kwargs): def command_preprocessor(self, name, command, arguments, args, kwargs):
""" """

View File

@ -100,7 +100,7 @@ class ChatCommands(CommonCommands):
Send a ping to the contact Send a ping to the contact
""" """
if self.account == gajim.ZEROCONF_ACC_NAME: if self.account == gajim.ZEROCONF_ACC_NAME:
raise CommandError(ping, _('Command is not supported for zeroconf accounts')) raise CommandError(_('Command is not supported for zeroconf accounts'))
gajim.connections[self.account].sendPing(self.contact) gajim.connections[self.account].sendPing(self.contact)
class PrivateChatCommands(CommonCommands): class PrivateChatCommands(CommonCommands):