X-Git-Url: https://git.llucax.com/software/pymin.git/blobdiff_plain/3eefa8b40b56992b0c96cf085ef9a6059b7c7fc4..af3261630a29ae3ee1f4c9a4eb574998b3e1a47b:/pymin/dispatcher.py diff --git a/pymin/dispatcher.py b/pymin/dispatcher.py index 10e7fb8..bde8603 100644 --- a/pymin/dispatcher.py +++ b/pymin/dispatcher.py @@ -8,6 +8,7 @@ and translates commands to functions/objects/methods. """ import re +import logging ; log = logging.getLogger('pymin.dispatcher') __ALL__ = ('Error', 'HandlerError', 'CommandNotFoundError', 'Handler', 'Dispatcher', 'handler', 'is_handler', 'get_help') @@ -55,17 +56,18 @@ class CommandError(Error): return u'Error in command "%s".' % u' '.join(self.command) class WrongArgumentsError(CommandError): - r"""WrongArgumentsError() -> WrongArgumentsError instance. + r"""WrongArgumentsError(handler, message) -> WrongArgumentsError instance. This exception is raised when an empty command string is received. """ - def __init__(self, message): + def __init__(self, handler, message): r"Initialize the object, see class documentation for more info." + self.handler = handler self.message = message def __unicode__(self): - return self.message + return u'Command "%s" %s.' % (self.handler.__name__, self.message) class CommandNotSpecifiedError(CommandError): r"""CommandNotSpecifiedError() -> CommandNotSpecifiedError instance. @@ -201,17 +203,31 @@ class Handler: d = dict() for a in dir(self): h = getattr(self, a) + if a == 'parent': continue # Skip parents in SubHandlers if is_handler(h) or isinstance(h, Handler): d[a] = h.handler_help return d # A command was specified + if command == 'parent': # Skip parents in SubHandlers + raise HelpNotFoundError(command) if not hasattr(self, command.encode('utf-8')): raise HelpNotFoundError(command) handler = getattr(self, command.encode('utf-8')) - if not is_handler(handler) and not hasattr(handler): + if not is_handler(handler) and not hasattr(handler, 'handler_help'): raise HelpNotFoundError(command) return handler.handler_help + def handle_timer(self): + r"""handle_timer() -> None :: Do periodic tasks. + + By default we do nothing but calling handle_timer() on subhandlers. + """ + for a in dir(self): + if a == 'parent': continue # Skip parents in SubHandlers + h = getattr(self, a) + if isinstance(h, Handler): + h.handle_timer() + def parse_command(command): r"""parse_command(command) -> (args, kwargs) :: Parse a command. @@ -384,6 +400,7 @@ def parse_command(command): return (seq, dic) args_re = re.compile(r'\w+\(\) takes (.+) (\d+) \w+ \((\d+) given\)') +kw_re = re.compile(r'\w+\(\) got an unexpected keyword argument (.+)') class Dispatcher: r"""Dispatcher([root]) -> Dispatcher instance :: Command dispatcher. @@ -418,6 +435,7 @@ class Dispatcher: See Dispatcher class documentation for more info. """ + log.debug(u'Dispatcher(%r)', root) self.root = root def dispatch(self, route): @@ -429,26 +447,44 @@ class Dispatcher: route - *unicode* string with the command route. """ + log.debug('Dispatcher.dispatch(%r)', route) command = list() (route, kwargs) = parse_command(route) + log.debug(u'Dispatcher.dispatch: route=%r, kwargs=%r', route, kwargs) if not route: + log.debug(u'Dispatcher.dispatch: command not specified') raise CommandNotSpecifiedError() handler = self.root while not is_handler(handler): + log.debug(u'Dispatcher.dispatch: handler=%r, route=%r', + handler, route) if len(route) is 0: if isinstance(handler, Handler): + log.debug(u'Dispatcher.dispatch: command is a handler') raise CommandIsAHandlerError(command) + log.debug(u'Dispatcher.dispatch: command not found') raise CommandNotFoundError(command) command.append(route[0]) + log.debug(u'Dispatcher.dispatch: command=%r', command) + if route[0] == 'parent': + log.debug(u'Dispatcher.dispatch: is parent => not found') + raise CommandNotFoundError(command) if not hasattr(handler, route[0].encode('utf-8')): if isinstance(handler, Handler) and len(command) > 1: + log.debug(u'Dispatcher.dispatch: command not in handler') raise CommandNotInHandlerError(command) + log.debug(u'Dispatcher.dispatch: command not found') raise CommandNotFoundError(command) handler = getattr(handler, route[0].encode('utf-8')) route = route[1:] + log.debug(u'Dispatcher.dispatch: %r is a handler, calling it with ' + u'route=%r, kwargs=%r', handler, route, kwargs) try: + r = handler(*route, **kwargs) + log.debug(u'Dispatcher.dispatch: handler returned %s', r) return handler(*route, **kwargs) except TypeError, e: + log.debug(u'Dispatcher.dispatch: type error (%r)', e) m = args_re.match(unicode(e)) if m: (quant, n_ok, n_bad) = m.groups() @@ -459,14 +495,29 @@ class Dispatcher: pl = '' if n_ok > 1: pl = 's' - raise WrongArgumentsError( - u'Command "%s" takes %s %s argument%s, %s given.' - % (handler.__name__, quant, n_ok, pl, n_bad)) + e = WrongArgumentsError(handler, u'takes %s %s argument%s, ' + '%s given' % (quant, n_ok, pl, n_bad)) + log.debug(u'Dispatcher.dispatch: wrong arguments (%r)', e) + raise e + m = kw_re.match(unicode(e)) + if m: + (kw,) = m.groups() + e = WrongArgumentsError(handler, + u'got an unexpected keyword argument %s' % kw) + log.debug(u'Dispatcher.dispatch: wrong arguments (%r)', e) + raise e + log.debug(u'Dispatcher.dispatch: some other TypeError, re-raising') raise if __name__ == '__main__': + logging.basicConfig( + level = logging.DEBUG, + format = '%(asctime)s %(levelname)-8s %(message)s', + datefmt = '%H:%M:%S', + ) + @handler(u"test: Print all the arguments, return nothing") def test_func(*args): print 'func:', args