and translates commands to functions/objects/methods.
"""
+import re
+
__ALL__ = ('Error', 'HandlerError', 'CommandNotFoundError', 'Handler',
'Dispatcher', 'handler', 'is_handler', 'get_help')
def __unicode__(self):
return u'Error in command "%s".' % u' '.join(self.command)
+class WrongArgumentsError(CommandError):
+ r"""WrongArgumentsError(handler, message) -> WrongArgumentsError instance.
+
+ This exception is raised when an empty command string is received.
+ """
+
+ 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 u'Command "%s" %s.' % (self.handler.__name__, self.message)
+
class CommandNotSpecifiedError(CommandError):
r"""CommandNotSpecifiedError() -> CommandNotSpecifiedError instance.
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.
arguments is preserved and if there are multiple keyword arguments with
the same key, the last value is the winner (all other values are lost).
+ The command should be a unicode string.
+
Examples:
>>> parse_command('hello world')
([u'=hello'], {})
>>> parse_command(r'\thello')
([u'\thello'], {})
+ >>> parse_command(r'hello \n')
+ ([u'hello', u'\n'], {})
+ >>> parse_command(r'hello \nmundo')
+ ([u'hello', u'\nmundo'], {})
+ >>> parse_command(r'test \N')
+ ([u'test', None], {})
>>> parse_command(r'\N')
([None], {})
>>> parse_command(r'none=\N')
escape = False
keyword = None
state = SEP
+ def register_token(buff, keyword, seq, dic):
+ if buff == r'\N':
+ buff = None
+ if keyword is not None:
+ dic[keyword.encode('utf-8')] = buff
+ keyword = None
+ else:
+ seq.append(buff)
+ buff = u''
+ return (buff, keyword)
for n, c in enumerate(command):
# Escaped character
if escape:
+ # Not yet registered the token
+ if state == SEP and buff:
+ (buff, keyword) = register_token(buff, keyword, seq, dic)
+ state = TOKEN
for e in escaped_chars:
if c == e:
buff += eval(u'"\\' + e + u'"')
keyword = buff
buff = u''
continue
- if buff == r'\N':
- buff = None
- if keyword is not None: # Value found
- dic[str(keyword)] = buff
- keyword = None
- else: # Normal parameter found
- seq.append(buff)
- buff = u''
+ (buff, keyword) = register_token(buff, keyword, seq, dic)
state = TOKEN
# Getting a token
if state == TOKEN:
raise ParseError(command,
u'keyword argument (%s) without value' % keyword)
if buff:
- if buff == r'\N':
- buff = None
- if keyword is not None:
- dic[str(keyword)] = buff
- else:
- seq.append(buff)
+ register_token(buff, keyword, seq, dic)
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.
raise CommandIsAHandlerError(command)
raise CommandNotFoundError(command)
command.append(route[0])
+ if route[0] == 'parent':
+ raise CommandNotFoundError(command)
if not hasattr(handler, route[0].encode('utf-8')):
if isinstance(handler, Handler) and len(command) > 1:
raise CommandNotInHandlerError(command)
raise CommandNotFoundError(command)
handler = getattr(handler, route[0].encode('utf-8'))
route = route[1:]
- return handler(*route, **kwargs)
+ try:
+ return handler(*route, **kwargs)
+ except TypeError, e:
+ m = args_re.match(unicode(e))
+ if m:
+ (quant, n_ok, n_bad) = m.groups()
+ n_ok = int(n_ok)
+ n_bad = int(n_bad)
+ n_ok -= 1
+ n_bad -= 1
+ pl = ''
+ if n_ok > 1:
+ pl = 's'
+ raise WrongArgumentsError(handler, u'takes %s %s argument%s, '
+ '%s given' % (quant, n_ok, pl, n_bad))
+ m = kw_re.match(unicode(e))
+ if m:
+ (kw,) = m.groups()
+ raise WrongArgumentsError(handler,
+ u'got an unexpected keyword argument %s' % kw)
+ raise
if __name__ == '__main__':
assert p == ([u'=hello'], {}), p
p = parse_command(r'\thello')
assert p == ([u'\thello'], {}), p
+ p = parse_command(r'hello \n')
+ assert p == ([u'hello', u'\n'], {}), p
+ p = parse_command(r'hello \nmundo')
+ assert p == ([u'hello', u'\nmundo'], {}), p
+ p = parse_command(r'test \N')
+ assert p == ([u'test', None], {}), p
p = parse_command(r'\N')
assert p == ([None], {}), p
p = parse_command(r'none=\N')