]> git.llucax.com Git - software/pymin.git/commitdiff
Improve a lot error reporting and unicode/utf-8 compatibility.
authorLeandro Lucarella <llucax@gmail.com>
Sat, 6 Oct 2007 04:02:35 +0000 (01:02 -0300)
committerLeandro Lucarella <llucax@gmail.com>
Sat, 6 Oct 2007 04:02:35 +0000 (01:02 -0300)
Conversion between unicode and utf-8 is now done when sending/receiving
over the network by the PyminDaemon.

All errors provides now a conversion to unicode.

Dispatcher CommandNotFoundError was refactored to multiple classes with
specific and more descriptive error messages.

Handlers now can have a little help string (handler_help).

Handler's help command now list subhandlers (using handler_help).

A new error was added for help command (HelpNotFoundError).

All service handlers were updated.

TODO
pymin/dispatcher.py
pymin/pymindaemon.py
pymin/services/dhcp/__init__.py
pymin/services/dns/__init__.py
pymin/services/firewall/__init__.py
pymin/services/ip/__init__.py
pymin/services/proxy/__init__.py

diff --git a/TODO b/TODO
index 362b434a91b895c8e25d83965ca2bf00dc3d831c..b8d9c03853380c9db7272a5ad4f9ff6513a309fd 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,19 +1,6 @@
 
 Ideas / TODO:
 
-* Hacer el protocolo completamente introspectivo, de manera que el cliente pueda
-  ser muy simple y genérico y en caso de agregar funcionalidad no sea necesario
-  modificarlo.
-
-* Evaluar hacer un RootHandler en vez de un diccionario con los handlers de la
-  raiz para simplificar la introspección y tener un help/commands global.
-
-* Evaluar que el dispatcher vea si se llama a un HandlerContainer y de ser así
-  que tire una ayuda en vez de un CommandNotFound (por ejemplo si se pone:
-  "dhcp" solo que tire una ayuda). Y si hay un subcomando no encontrado, que
-  tire un Command Not Found in handler (por ej "dhcp lala" -> Command "lala" not
-  found in "dhcp").
-
 * Agregar logging.
 
 * Agregar validación con formencode.
index 7e9ef6079d9a9d66d3a681db0591b1ff0e85682c..39b4b75cf6522f64e78b2d097422a2bfc69285e1 100644 (file)
@@ -19,7 +19,16 @@ class Error(RuntimeError):
     command - is the command that raised the exception, expressed as a list of
               paths (or subcommands).
     """
-    pass
+
+    def __init__(self, message):
+        r"Initialize the Error object. See class documentation for more info."
+        self.message = message
+
+    def __unicode__(self):
+        return self.message
+
+    def __str__(self):
+        return unicode(self).encode('utf-8')
 
 class HandlerError(Error):
     r"""HandlerError(command) -> HandlerError instance :: Base handlers error.
@@ -37,25 +46,59 @@ class CommandError(Error):
     """
 
     def __init__(self, command):
-        r"""Initialize the object.
-
-        See class documentation for more info.
-        """
+        r"Initialize the object, see class documentation for more info."
         self.command = command
 
-    def __str__(self):
-        return 'Command error: "%s"' % self.command
+    def __unicode__(self):
+        return u'Error in command "%s".' % u' '.join(self.command)
+
+class CommandNotSpecifiedError(CommandError):
+    r"""CommandNotSpecifiedError() -> CommandNotSpecifiedError instance.
+
+    This exception is raised when an empty command string is received.
+    """
+
+    def __init__(self):
+        r"Initialize the object, see class documentation for more info."
+        pass
+
+    def __unicode__(self):
+        return u'Command not specified.'
+
+class CommandIsAHandlerError(CommandError):
+    r"""CommandIsAHandlerError() -> CommandIsAHandlerError instance.
+
+    This exception is raised when a command is a handler containing commands
+    instead of a command itself.
+    """
+
+    def __unicode__(self):
+        command = ' '.join(self.command)
+        return u'"%s" is a handler, not a command (type "%s help" for help).' \
+                    % (command, command)
+
+class CommandNotInHandlerError(CommandError):
+    r"""CommandNotInHandlerError() -> CommandNotInHandlerError instance.
+
+    This exception is raised when a command parent is a hanlder containing
+    commands, but the command itself is not found.
+    """
+
+    def __unicode__(self):
+        return u'Command "%(c)s" not found in handler "%(h)s" ' \
+                u'(type "%(h)s help" for help).' \
+                        % dict(c=u' '.join(self.command[-1:]),
+                                h=u' '.join(self.command[0:-1]))
 
 class CommandNotFoundError(CommandError):
-    r"""CommandNotFoundError(command) -> CommandNotFoundError instance.
+    r"""CommandNotFoundError(command[, handler]) -> CommandNotFoundError object.
 
     This exception is raised when the command received can't be dispatched
     because there is no handlers to process it.
     """
 
-    def __str__(self):
-        return 'Command not found: "%s"' % ' '.join(
-                                                repr(c) for c in self.command)
+    def __unicode__(self):
+        return u'Command "%s" not found.' % u' '.join(self.command)
 
 class ParseError(CommandError):
     r"""ParseError(command[, desc]) -> ParseError instance
@@ -75,8 +118,26 @@ class ParseError(CommandError):
         self.command = command
         self.desc = desc
 
-    def __str__(self):
-        return 'Syntax error, %s: %s' % (self.desc, self.command)
+    def __unicode__(self):
+        return u'Syntax error, %s: %s' % (self.desc, self.command)
+
+class HelpNotFoundError(Error):
+    r"""HelpNotFoundError(command) -> HelpNotFoundError instance.
+
+    This exception is raised when a help command can't find the command
+    asked for help.
+    """
+
+    def __init__(self, command):
+        r"""Initialize the object.
+
+        See class documentation for more info.
+        """
+        self.command = command
+
+    def __unicode__(self):
+        return u"Can't get help for '%s', command not found." % self.command
+
 
 def handler(help):
     r"""handler(help) -> function wrapper :: Mark a callable as a handler.
@@ -88,33 +149,32 @@ def handler(help):
     def wrapper(f):
         if not help:
             raise TypeError("'help' should not be empty")
-        f._dispatcher_help = help
+        f._dispatcher_handler = True
+        f.handler_help = help
         return f
     return wrapper
 
 def is_handler(handler):
     r"is_handler(handler) -> bool :: Tell if a object is a handler."
-    return callable(handler) and hasattr(handler, '_dispatcher_help')
-
-def get_help(handler):
-    r"get_help(handler) -> unicode :: Get a handler's help string."
-    if not is_handler(handler):
-        raise TypeError("'%s' should be a handler" % handler.__name__)
-    return handler._dispatcher_help
+    return callable(handler) and hasattr(handler, '_dispatcher_handler') \
+                and handler._dispatcher_handler
 
 class Handler:
     r"""Handler() -> Handler instance :: Base class for all dispatcher handlers.
 
     All dispatcher handlers should inherit from this class to have some extra
-    commands, like help.
+    commands, like help. You should override the 'handler_help' attribute to a
+    nice help message describing the handler.
     """
 
-    @handler(u'List available commands.')
+    handler_help = u'Undocumented handler'
+
+    @handler(u'List available commands')
     def commands(self):
         r"""commands() -> generator :: List the available commands."""
         return (a for a in dir(self) if is_handler(getattr(self, a)))
 
-    @handler(u'Show available commands with their help.')
+    @handler(u'Show available commands with their help')
     def help(self, command=None):
         r"""help([command]) -> unicode/dict :: Show help on available commands.
 
@@ -123,14 +183,19 @@ class Handler:
         and values are the help strings.
         """
         if command is None:
-            return dict((a, get_help(getattr(self, a)))
-                        for a in dir(self) if is_handler(getattr(self, a)))
-        if not hasattr(self, command):
-            raise CommandNotFoundError(command)
-        handler = getattr(self, command)
-        if not is_handler(handler):
-            raise CommandNotFoundError(command)
-        return get_help(handler)
+            d = dict()
+            for a in dir(self):
+                h = getattr(self, a)
+                if is_handler(h) or isinstance(h, Handler):
+                    d[a] = h.handler_help
+            return d
+        # A command was specified
+        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):
+            raise HelpNotFoundError(command)
+        return handler.handler_help
 
 def parse_command(command):
     r"""parse_command(command) -> (args, kwargs) :: Parse a command.
@@ -318,9 +383,7 @@ class Dispatcher:
     'arg1', 'arg 2', arg=3) will be called. The handler "tree" can be as
     complex and deep as you want.
 
-    If some command can't be dispatched (because there is no root handler
-    or there is no matching callable attribute), a CommandNotFoundError
-    is raised.
+    If some command can't be dispatched, a CommandError subclass is raised.
     """
 
     def __init__(self, root):
@@ -334,41 +397,47 @@ class Dispatcher:
         r"""dispatch(route) -> None :: Dispatch a command string.
 
         This method searches for a suitable callable object in the routes
-        "tree" and call it, or raises a CommandNotFoundError if the command
+        "tree" and call it, or raises a CommandError subclass if the command
         can't be dispatched.
+
+        route - *unicode* string with the command route.
         """
         command = list()
         (route, kwargs) = parse_command(route)
         if not route:
-            raise CommandNotFoundError(command)
+            raise CommandNotSpecifiedError()
         handler = self.root
         while not is_handler(handler):
             if len(route) is 0:
+                if isinstance(handler, Handler):
+                    raise CommandIsAHandlerError(command)
                 raise CommandNotFoundError(command)
             command.append(route[0])
-            if not hasattr(handler, route[0]):
+            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])
+            handler = getattr(handler, route[0].encode('utf-8'))
             route = route[1:]
         return handler(*route, **kwargs)
 
 
 if __name__ == '__main__':
 
-    @handler(u"test: Print all the arguments, return nothing.")
+    @handler(u"test: Print all the arguments, return nothing")
     def test_func(*args):
         print 'func:', args
 
     class TestClassSubHandler(Handler):
-        @handler(u"subcmd: Print all the arguments, return nothing.")
+        @handler(u"subcmd: Print all the arguments, return nothing")
         def subcmd(self, *args):
             print 'class.subclass.subcmd:', args
 
     class TestClass(Handler):
-        @handler(u"cmd1: Print all the arguments, return nothing.")
+        @handler(u"cmd1: Print all the arguments, return nothing")
         def cmd1(self, *args):
             print 'class.cmd1:', args
-        @handler(u"cmd2: Print all the arguments, return nothing.")
+        @handler(u"cmd2: Print all the arguments, return nothing")
         def cmd2(self, *args):
             print 'class.cmd2:', args
         subclass = TestClassSubHandler()
@@ -388,7 +457,7 @@ if __name__ == '__main__':
     d.dispatch('inst subclass subcmd arg1 arg2 arg3 arg4 arg5')
     try:
         d.dispatch('')
-    except CommandNotFoundError, e:
+    except CommandNotSpecifiedError, e:
         print 'Not found:', e
     try:
         d.dispatch('sucutrule piquete culete')
@@ -396,7 +465,11 @@ if __name__ == '__main__':
         print 'Not found:', e
     try:
         d.dispatch('inst cmd3 arg1 arg2 arg3')
-    except CommandNotFoundError, e:
+    except CommandNotInHandlerError, e:
+        print 'Not found:', e
+    try:
+        d.dispatch('inst')
+    except CommandIsAHandlerError, e:
         print 'Not found:', e
     print
     print
index ee5f80544837d41a85b657ed252a4e4438f49656..f7497536835ae72670cc2ca3acbcf55ba5d58ba3 100644 (file)
@@ -49,6 +49,7 @@ class PyminDaemon(eventloop.EventLoop):
         # Create EventLoop
         eventloop.EventLoop.__init__(self, sock)
         # Create Dispatcher
+        #TODO root.pymin = PyminHandler()
         self.dispatcher = dispatcher.Dispatcher(root)
         # Signal handling
         def quit(signum, frame):
@@ -65,7 +66,7 @@ class PyminDaemon(eventloop.EventLoop):
         r"handle() -> None :: Handle incoming events using the dispatcher."
         (msg, addr) = self.file.recvfrom(65535)
         try:
-            result = self.dispatcher.dispatch(msg)
+            result = self.dispatcher.dispatch(unicode(msg, 'utf-8'))
             if result is not None:
                 result = serializer.serialize(result)
             response = u'OK '
@@ -81,7 +82,7 @@ class PyminDaemon(eventloop.EventLoop):
             response += u'0\n'
         else:
             response += u'%d\n%s' % (len(result), result)
-        self.file.sendto(response, addr)
+        self.file.sendto(response.encode('utf-8'), addr)
 
     def run(self):
         r"run() -> None :: Run the event loop (shortcut to loop())"
index 8f42e1ac013db09d6739720e8537285505b4023c..0dcb0d4abe3bb920ec93efb4eea00b67a41c91b5 100644 (file)
@@ -19,13 +19,7 @@ class Error(HandlerError):
 
     message - A descriptive error message.
     """
-
-    def __init__(self, message):
-        r"Initialize the Error object. See class documentation for more info."
-        self.message = message
-
-    def __str__(self):
-        return self.message
+    pass
 
 class HostError(Error, KeyError):
     r"""
@@ -36,7 +30,7 @@ class HostError(Error, KeyError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host error: "%s"' % hostname
+        self.message = u'Host error: "%s"' % hostname
 
 class HostAlreadyExistsError(HostError):
     r"""
@@ -47,7 +41,7 @@ class HostAlreadyExistsError(HostError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host already exists: "%s"' % hostname
+        self.message = u'Host already exists: "%s"' % hostname
 
 class HostNotFoundError(HostError):
     r"""
@@ -59,7 +53,7 @@ class HostNotFoundError(HostError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host not found: "%s"' % hostname
+        self.message = u'Host not found: "%s"' % hostname
 
 
 class Host(Sequence):
@@ -89,18 +83,20 @@ class HostHandler(Handler):
     hosts - A dictionary with string keys (hostnames) and Host instances values.
     """
 
+    handler_help = u"Manage DHCP hosts"
+
     def __init__(self, hosts):
         r"Initialize HostHandler object, see class documentation for details."
         self.hosts = hosts
 
-    @handler(u'Add a new host.')
+    @handler(u'Add a new host')
     def add(self, name, ip, mac):
         r"add(name, ip, mac) -> None :: Add a host to the hosts list."
         if name in self.hosts:
             raise HostAlreadyExistsError(name)
         self.hosts[name] = Host(name, ip, mac)
 
-    @handler(u'Update a host.')
+    @handler(u'Update a host')
     def update(self, name, ip=None, mac=None):
         r"update(name[, ip[, mac]]) -> None :: Update a host of the hosts list."
         if not name in self.hosts:
@@ -110,26 +106,26 @@ class HostHandler(Handler):
         if mac is not None:
             self.hosts[name].mac = mac
 
-    @handler(u'Delete a host.')
+    @handler(u'Delete a host')
     def delete(self, name):
         r"delete(name) -> None :: Delete a host of the hosts list."
         if not name in self.hosts:
             raise HostNotFoundError(name)
         del self.hosts[name]
 
-    @handler(u'Get information about a host.')
+    @handler(u'Get information about a host')
     def get(self, name):
         r"get(name) -> Host :: List all the information of a host."
         if not name in self.hosts:
             raise HostNotFoundError(name)
         return self.hosts[name]
 
-    @handler(u'List hosts.')
+    @handler(u'List hosts')
     def list(self):
         r"list() -> tuple :: List all the hostnames."
         return self.hosts.keys()
 
-    @handler(u'Get information about all hosts.')
+    @handler(u'Get information about all hosts')
     def show(self):
         r"show() -> list of Hosts :: List all the complete hosts information."
         return self.hosts.values()
@@ -148,6 +144,8 @@ class DhcpHandler(Restorable, ConfigWriter, InitdHandler, TransactionalHandler,
     Both defaults to the current working directory.
     """
 
+    handler_help = u"Manage DHCP service"
+
     _initd_name = 'dhcpd'
 
     _persistent_attrs = ('params', 'hosts')
index 624dfc44c14e67690a1a59d3572df6d089fdba1f..cf44ea4e4036334ef70747416aaa7500e2056bb4 100644 (file)
@@ -29,13 +29,7 @@ class Error(HandlerError):
 
     message - A descriptive error message.
     """
-
-    def __init__(self, message):
-        r"Initialize the Error object. See class documentation for more info."
-        self.message = message
-
-    def __str__(self):
-        return self.message
+    pass
 
 class ZoneError(Error, KeyError):
     r"""
@@ -46,7 +40,7 @@ class ZoneError(Error, KeyError):
 
     def __init__(self, zonename):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Zone error: "%s"' % zonename
+        self.message = u'Zone error: "%s"' % zonename
 
 class ZoneNotFoundError(ZoneError):
     r"""
@@ -58,7 +52,7 @@ class ZoneNotFoundError(ZoneError):
 
     def __init__(self, zonename):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'zone not found: "%s"' % zonename
+        self.message = u'zone not found: "%s"' % zonename
 
 class ZoneAlreadyExistsError(ZoneError):
     r"""
@@ -69,7 +63,7 @@ class ZoneAlreadyExistsError(ZoneError):
 
     def __init__(self, zonename):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Zone already exists: "%s"' % zonename
+        self.message = u'Zone already exists: "%s"' % zonename
 
 class HostError(Error, KeyError):
     r"""
@@ -80,7 +74,7 @@ class HostError(Error, KeyError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host error: "%s"' % hostname
+        self.message = u'Host error: "%s"' % hostname
 
 class HostAlreadyExistsError(HostError):
     r"""
@@ -91,11 +85,11 @@ class HostAlreadyExistsError(HostError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host already exists: "%s"' % hostname
+        self.message = u'Host already exists: "%s"' % hostname
 
 class HostNotFoundError(HostError):
     r"""
-    HostNotFoundError(hostname) -> HostNotFoundError instance
+    HostNotFoundError(hostname) -> HostNotFoundError instance.
 
     This exception is raised when trying to operate on a hostname that doesn't
     exists.
@@ -103,36 +97,36 @@ class HostNotFoundError(HostError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host not found: "%s"' % hostname
+        self.message = u'Host not found: "%s"' % hostname
 
 class MailExchangeError(Error, KeyError):
     r"""
-    MailExchangeError(hostname) -> MailExchangeError instance
+    MailExchangeError(hostname) -> MailExchangeError instance.
 
     This is the base exception for all mail exchange related errors.
     """
 
     def __init__(self, mx):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Mail Exchange error: "%s"' % mx
+        self.message = u'Mail Exchange error: "%s"' % mx
 
 class MailExchangeAlreadyExistsError(MailExchangeError):
     r"""
-    MailExchangeAlreadyExistsError(hostname) -> MailExchangeAlreadyExistsError instance
+    MailExchangeAlreadyExistsError(hostname) -> MailExchangeAlreadyExistsError.
 
     This exception is raised when trying to add a mail exchange that already exists.
     """
 
     def __init__(self, mx):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Mail Exchange already exists: "%s"' % mx
+        self.message = u'Mail Exchange already exists: "%s"' % mx
 
 class MailExchangeNotFoundError(MailExchangeError):
     r"""
-    MailExchangeNotFoundError(hostname) -> MailExchangeNotFoundError instance
+    MailExchangeNotFoundError(hostname) -> MailExchangeNotFoundError instance.
 
-    This exception is raised when trying to operate on a mail exchange that doesn't
-    exists.
+    This exception is raised when trying to operate on a mail exchange that
+    doesn't exists.
     """
 
     def __init__(self, mx):
@@ -152,9 +146,10 @@ class NameServerError(Error, KeyError):
 
 class NameServerAlreadyExistsError(NameServerError):
     r"""
-    NameServerAlreadyExistsError(hostname) -> NameServerAlreadyExistsError instance
+    NameServerAlreadyExistsError(hostname) -> NameServerAlreadyExistsError.
 
-    This exception is raised when trying to add a name server that already exists.
+    This exception is raised when trying to add a name server that already
+    exists.
     """
 
     def __init__(self, ns):
@@ -163,10 +158,10 @@ class NameServerAlreadyExistsError(NameServerError):
 
 class NameServerNotFoundError(NameServerError):
     r"""
-    NameServerNotFoundError(hostname) -> NameServerNotFoundError instance
+    NameServerNotFoundError(hostname) -> NameServerNotFoundError instance.
 
-    This exception is raised when trying to operate on a name server that doesn't
-    exists.
+    This exception is raised when trying to operate on a name server that
+    doesn't exists.
     """
 
     def __init__(self, ns):
@@ -183,6 +178,9 @@ class Host(Sequence):
         return (self.name, self.ip)
 
 class HostHandler(Handler):
+
+    handler_help = u"Manage DNS hosts"
+
     def __init__(self,zones):
         self.zones = zones
 
@@ -233,6 +231,8 @@ class MailExchange(Sequence):
 
 class MailExchangeHandler(Handler):
 
+    handler_help = u"Manage DNS mail exchangers (MX)"
+
     def __init__(self, zones):
         self.zones = zones
 
@@ -282,6 +282,8 @@ class NameServer(Sequence):
 
 class NameServerHandler(Handler):
 
+    handler_help = u"Manage DNS name servers (NS)"
+
     def __init__(self, zones):
         self.zones = zones
 
@@ -326,7 +328,6 @@ class Zone(Sequence):
         return (self.name, self.hosts, self.mxs, self.nss)
 
 class ZoneHandler(Handler):
-
     r"""ZoneHandler(zones) -> ZoneHandler instance :: Handle a list of zones.
 
     This class is a helper for DnsHandler to do all the work related to zone
@@ -334,6 +335,9 @@ class ZoneHandler(Handler):
 
     zones - A dictionary with string keys (zone name) and Zone instances values.
     """
+
+    handler_help = u"Manage DNS zones"
+
     def __init__(self, zones):
         self.zones = zones
 
@@ -378,6 +382,8 @@ class DnsHandler(Restorable, ConfigWriter, InitdHandler, TransactionalHandler,
     Both defaults to the current working directory.
     """
 
+    handler_help = u"Manage DNS service"
+
     _initd_name = 'bind'
 
     _persistent_attrs = ('params', 'zones')
index dbf9b155015e4053cc32cc83e96c2537d18dec09..229cc207a3a2a5efff14b7d2f1e59bc02fb3bab8 100644 (file)
@@ -22,13 +22,7 @@ class Error(HandlerError):
 
     message - A descriptive error message.
     """
-
-    def __init__(self, message):
-        r"Initialize the Error object. See class documentation for more info."
-        self.message = message
-
-    def __str__(self):
-        return self.message
+    pass
 
 class RuleError(Error, KeyError):
     r"""
@@ -39,7 +33,7 @@ class RuleError(Error, KeyError):
 
     def __init__(self, rule):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Rule error: "%s"' % rule
+        self.message = u'Rule error: "%s"' % rule
 
 class RuleAlreadyExistsError(RuleError):
     r"""
@@ -50,7 +44,7 @@ class RuleAlreadyExistsError(RuleError):
 
     def __init__(self, rule):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Rule already exists: "%s"' % rule
+        self.message = u'Rule already exists: "%s"' % rule
 
 class RuleNotFoundError(RuleError):
     r"""
@@ -62,7 +56,7 @@ class RuleNotFoundError(RuleError):
 
     def __init__(self, rule):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Rule not found: "%s"' % rule
+        self.message = u'Rule not found: "%s"' % rule
 
 
 class Rule(Sequence):
@@ -129,11 +123,13 @@ class RuleHandler(Handler):
     rules - A list of Rule objects.
     """
 
+    handler_help = u"Manage firewall rules"
+
     def __init__(self, rules):
         r"Initialize the object, see class documentation for details."
         self.rules = rules
 
-    @handler(u'Add a new rule.')
+    @handler(u'Add a new rule')
     def add(self, *args, **kwargs):
         r"add(rule) -> None :: Add a rule to the rules list (see Rule doc)."
         rule = Rule(*args, **kwargs)
@@ -141,7 +137,7 @@ class RuleHandler(Handler):
             raise RuleAlreadyExistsError(rule)
         self.rules.append(rule)
 
-    @handler(u'Update a rule.')
+    @handler(u'Update a rule')
     def update(self, index, *args, **kwargs):
         r"update(index, rule) -> None :: Update a rule (see Rule doc)."
         # TODO check if the modified rule is the same of an existing one
@@ -151,7 +147,7 @@ class RuleHandler(Handler):
         except IndexError:
             raise RuleNotFoundError(index)
 
-    @handler(u'Delete a rule.')
+    @handler(u'Delete a rule')
     def delete(self, index):
         r"delete(index) -> Rule :: Delete a rule from the list returning it."
         index = int(index) # TODO validation
@@ -160,7 +156,7 @@ class RuleHandler(Handler):
         except IndexError:
             raise RuleNotFoundError(index)
 
-    @handler(u'Get information about a rule.')
+    @handler(u'Get information about a rule')
     def get(self, index):
         r"get(rule) -> Rule :: Get all the information about a rule."
         index = int(index) # TODO validation
@@ -169,7 +165,7 @@ class RuleHandler(Handler):
         except IndexError:
             raise RuleNotFoundError(index)
 
-    @handler(u'Get information about all rules.')
+    @handler(u'Get information about all rules')
     def show(self):
         r"show() -> list of Rules :: List all the complete rules information."
         return self.rules
@@ -188,6 +184,8 @@ class FirewallHandler(Restorable, ConfigWriter, ServiceHandler,
     Both defaults to the current working directory.
     """
 
+    handler_help = u"Manage firewall service"
+
     _persistent_attrs = 'rules'
 
     _restorable_defaults = dict(rules=list())
index 4330eeb359b8cdb8a31d49295505c07a69d9d911..c512d26a46bf0766c89416887e4795998330af51 100644 (file)
@@ -21,53 +21,47 @@ class Error(HandlerError):
 
     message - A descriptive error message.
     """
-
-    def __init__(self, message):
-        r"Initialize the Error object. See class documentation for more info."
-        self.message = message
-
-    def __str__(self):
-        return self.message
+    pass
 
 class DeviceError(Error):
 
     def __init__(self, device):
-        self.message = 'Device error : "%s"' % device
+        self.message = u'Device error : "%s"' % device
 
 class DeviceNotFoundError(DeviceError):
 
     def __init__(self, device):
-        self.message = 'Device not found : "%s"' % device
+        self.message = u'Device not found : "%s"' % device
 
 class AddressError(Error):
 
     def __init__(self, addr):
-        self.message = 'Address error : "%s"' % addr
+        self.message = u'Address error : "%s"' % addr
 
 class AddressNotFoundError(AddressError):
 
     def __init__(self, address):
-        self.message = 'Address not found : "%s"' % address
+        self.message = u'Address not found : "%s"' % address
 
 class AddressAlreadyExistsError(AddressError):
 
     def __init__(self, address):
-        self.message = 'Address already exists : "%s"' % address
+        self.message = u'Address already exists : "%s"' % address
 
 class RouteError(Error):
 
     def __init__(self, route):
-        self.message = 'Route error : "%s"' % route
+        self.message = u'Route error : "%s"' % route
 
 class RouteNotFoundError(RouteError):
 
     def __init__(self, route):
-        self.message = 'Route not found : "%s"' % route
+        self.message = u'Route not found : "%s"' % route
 
 class RouteAlreadyExistsError(RouteError):
 
     def __init__(self, route):
-        self.message = 'Route already exists : "%s"' % route
+        self.message = u'Route already exists : "%s"' % route
 
 
 class Route(Sequence):
@@ -89,6 +83,8 @@ class Route(Sequence):
 
 class RouteHandler(Handler):
 
+    handler_help = u"Manage IP routes"
+
     def __init__(self, devices):
         self.devices = devices
 
@@ -149,6 +145,8 @@ class Address(Sequence):
 
 class AddressHandler(Handler):
 
+    handler_help = u"Manage IP addresses"
+
     def __init__(self, devices):
         self.devices = devices
 
@@ -204,6 +202,8 @@ class Device(Sequence):
 
 class DeviceHandler(Handler):
 
+    handler_help = u"Manage network devices"
+
     def __init__(self, devices):
         # FIXME remove templates to execute commands
         from mako.template import Template
@@ -251,6 +251,8 @@ def get_devices():
 
 class IpHandler(Restorable, ConfigWriter, TransactionalHandler):
 
+    handler_help = u"Manage IP devices, addresses and routes"
+
     _persistent_attrs = 'devices'
 
     _restorable_defaults = dict(devices=get_devices())
index b3b1172bc74474752890f5ccd48fd8f2fd32ec6a..399eba1bf341b5c9eb37bcad32d9738ff572dd48 100644 (file)
@@ -19,13 +19,7 @@ class Error(HandlerError):
 
     message - A descriptive error message.
     """
-
-    def __init__(self, message):
-        r"Initialize the Error object. See class documentation for more info."
-        self.message = message
-
-    def __str__(self):
-        return self.message
+    pass
 
 class HostError(Error, KeyError):
     r"""
@@ -36,7 +30,7 @@ class HostError(Error, KeyError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host error: "%s"' % hostname
+        self.message = u'Host error: "%s"' % hostname
 
 class HostAlreadyExistsError(HostError):
     r"""
@@ -47,7 +41,7 @@ class HostAlreadyExistsError(HostError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host already exists: "%s"' % hostname
+        self.message = u'Host already exists: "%s"' % hostname
 
 class HostNotFoundError(HostError):
     r"""
@@ -59,7 +53,7 @@ class HostNotFoundError(HostError):
 
     def __init__(self, hostname):
         r"Initialize the object. See class documentation for more info."
-        self.message = 'Host not found: "%s"' % hostname
+        self.message = u'Host not found: "%s"' % hostname
 
 
 class Host(Sequence):
@@ -72,6 +66,8 @@ class Host(Sequence):
 
 class HostHandler(Handler):
 
+    handler_help = u"Manage proxy hosts"
+
     def __init__(self, hosts):
         self.hosts = hosts
 
@@ -99,6 +95,8 @@ class HostHandler(Handler):
 class ProxyHandler(Restorable, ConfigWriter, InitdHandler,
                    TransactionalHandler, ParametersHandler):
 
+    handler_help = u"Manage proxy service"
+
     _initd_name = 'squid'
 
     _persistent_attrs = ('params', 'hosts')