]> git.llucax.com Git - software/pymin.git/commitdiff
Use a handler object as the root dispatcher handler instead of a dict.
authorLeandro Lucarella <llucarella@integratech.com.ar>
Fri, 5 Oct 2007 16:01:53 +0000 (13:01 -0300)
committerLeandro Lucarella <llucarella@integratech.com.ar>
Fri, 5 Oct 2007 16:27:03 +0000 (13:27 -0300)
Now the dispatcher use a handler object as the root handler. This way you
can inherit your root handler from Handler and get the useful 'help' and
'coommands' commands for free.

config.py
pymin/dispatcher.py
pymin/pymindaemon.py
pymind

index 059faaeea54762900ef6162904c8888a767a0b30..5ae043d9ac0f3aa10f308c04590d3aed6a8b8f0e 100644 (file)
--- a/config.py
+++ b/config.py
@@ -1,36 +1,24 @@
 # vim: set et sts=4 sw=4 encoding=utf-8 :
 
 from pymin.services import *
-from pymin.dispatcher import handler
+from pymin.dispatcher import Handler
 
-# XXX for testing only
-@handler
-def test_func(*args):
-    print 'func:', args
-
-routes = dict \
-(
+class Root(Handler):
     dhcp = DhcpHandler(
         pickle_dir = 'var/lib/pymin/pickle/dhcp',
-        config_dir = 'var/lib/pymin/config/dhcp',
-    ),
+        config_dir = 'var/lib/pymin/config/dhcp')
     dns = DnsHandler(
         pickle_dir = 'var/lib/pymin/pickle/dns',
-        config_dir = 'var/lib/pymin/config/dns',
-    ),
+        config_dir = 'var/lib/pymin/config/dns')
     firewall = FirewallHandler(
         pickle_dir = 'var/lib/pymin/pickle/firewall',
-        config_dir = 'var/lib/pymin/config/firewall',
-    ),
+        config_dir = 'var/lib/pymin/config/firewall')
     ip = IpHandler(
         pickle_dir = 'var/lib/pymin/pickle/ip',
-        config_dir = 'var/lib/pymin/config/ip',
-    ),
+        config_dir = 'var/lib/pymin/config/ip')
     proxy = ProxyHandler(
         pickle_dir = 'var/lib/pymin/pickle/proxy',
-        config_dir = 'var/lib/pymin/config/proxy',
-    ),
-)
+        config_dir = 'var/lib/pymin/config/proxy')
 
 bind_addr = \
 (
index c7d260bda6f1910d27b610a3f79f4b579613256e..7e9ef6079d9a9d66d3a681db0591b1ff0e85682c 100644 (file)
@@ -294,15 +294,13 @@ def parse_command(command):
     return (seq, dic)
 
 class Dispatcher:
-    r"""Dispatcher([routes]) -> Dispatcher instance :: Command dispatcher
+    r"""Dispatcher([root]) -> Dispatcher instance :: Command dispatcher.
 
     This class provides a modular and extensible dispatching mechanism. You
-    can specify root 'routes' (as a dict where the key is the string of the
-    root command and the value is a callable object to handle that command,
-    or a subcommand if the callable is an instance and the command can be
-    sub-routed).
+    specify a root handler (probably as a pymin.dispatcher.Handler subclass),
 
-    The command can have arguments, separated by (any number of) spaces.
+    The command can have arguments, separated by (any number of) spaces and
+    keyword arguments (see parse_command for more details).
 
     The dispatcher tries to route the command as deeply as it can, passing
     the other "path" components as arguments to the callable. To route the
@@ -311,25 +309,26 @@ class Dispatcher:
 
     Example:
     >>> d = Dispatcher(dict(handler=some_handler))
-    >>> d.dispatch('handler attribute method arg1 arg2 "third argument"')
+    >>> d.dispatch('handler attribute method arg1 "arg 2" arg=3')
 
     If 'some_handler' is an object with an 'attribute' that is another
     object which has a method named 'method', then
-    some_handler.attribute.method('arg1', 'arg2') will be called. If
-    some_handler is a function, then some_handler('attribute', 'method',
-    'arg1', 'arg2') 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.
+    some_handler.attribute.method('arg1', 'arg 2', arg=3) will be called.
+    If some_handler is a function, then some_handler('attribute', 'method',
+    '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.
     """
 
-    def __init__(self, routes=dict()):
+    def __init__(self, root):
         r"""Initialize the Dispatcher object.
 
         See Dispatcher class documentation for more info.
         """
-        self.routes = routes
+        self.root = root
 
     def dispatch(self, route):
         r"""dispatch(route) -> None :: Dispatch a command string.
@@ -342,11 +341,7 @@ class Dispatcher:
         (route, kwargs) = parse_command(route)
         if not route:
             raise CommandNotFoundError(command)
-        command.append(route[0])
-        handler = self.routes.get(route[0], None)
-        if handler is None:
-            raise CommandNotFoundError(command)
-        route = route[1:]
+        handler = self.root
         while not is_handler(handler):
             if len(route) is 0:
                 raise CommandNotFoundError(command)
@@ -378,12 +373,11 @@ if __name__ == '__main__':
             print 'class.cmd2:', args
         subclass = TestClassSubHandler()
 
-    test_class = TestClass()
+    class RootHandler(Handler):
+        func = staticmethod(test_func)
+        inst = TestClass()
 
-    d = Dispatcher(dict(
-            func=test_func,
-            inst=test_class,
-    ))
+    d = Dispatcher(RootHandler())
 
     d.dispatch(r'''func arg1 arg2 arg3 "fourth 'argument' with \", a\ttab and\n\\n"''')
     print 'inst commands:', tuple(d.dispatch('inst commands'))
@@ -404,6 +398,8 @@ if __name__ == '__main__':
         d.dispatch('inst cmd3 arg1 arg2 arg3')
     except CommandNotFoundError, e:
         print 'Not found:', e
+    print
+    print
 
     # Parser tests
     p = parse_command('hello world')
index be2c9750d29339d7b79d696bdf6218898ed267c8..ee5f80544837d41a85b657ed252a4e4438f49656 100644 (file)
@@ -11,28 +11,33 @@ command-line.
 import signal
 import socket
 
+from pymin.dispatcher import handler
+from pymin import dispatcher
 from pymin import eventloop
 from pymin import serializer
 
 class PyminDaemon(eventloop.EventLoop):
-    r"""PyminDaemon(bind_addr, routes) -> PyminDaemon instance
+    r"""PyminDaemon(root, bind_addr) -> PyminDaemon instance
 
     This class is well suited to run as a single process. It handles
     signals for controlled termination (SIGINT and SIGTERM), as well as
     a user signal to reload the configuration files (SIGUSR1).
 
-    bind_addr - is a tuple of (ip, port) where to bind the UDP socket to.
+    root - the root handler. This is passed directly to the Dispatcher.
 
-    routes - is a dictionary where the key is a command string and the value
-             is the command handler. This is passed directly to the Dispatcher.
+    bind_addr - is a tuple of (ip, port) where to bind the UDP socket to.
 
     Here is a simple usage example:
 
-    >>> def test_handler(*args): print 'test:', args
-    >>> PyminDaemon(('', 9999), dict(test=test_handler)).run()
+    >>> from pymin import dispatcher
+    >>> class Root(dispatcher.Handler):
+            @handler('Test command.')
+            def test(self, *args):
+                print 'test:', args
+    >>> PyminDaemon(Root(), ('', 9999)).run()
     """
 
-    def __init__(self, routes=dict(), bind_addr=('', 9999)):
+    def __init__(self, root, bind_addr=('', 9999)):
         r"""Initialize the PyminDaemon object.
 
         See PyminDaemon class documentation for more info.
@@ -44,7 +49,7 @@ class PyminDaemon(eventloop.EventLoop):
         # Create EventLoop
         eventloop.EventLoop.__init__(self, sock)
         # Create Dispatcher
-        self.dispatcher = Dispatcher(routes)
+        self.dispatcher = dispatcher.Dispatcher(root)
         # Signal handling
         def quit(signum, frame):
             print "Shuting down ..."
@@ -87,14 +92,14 @@ class PyminDaemon(eventloop.EventLoop):
 
 if __name__ == '__main__':
 
-    @handler(u"Print all the arguments, return nothing.")
-    def test_handler(*args):
-        print 'test:', args
-
-    @handler(u"Echo the message passed as argument.")
-    def echo_handler(message):
-        print 'echo:', message
-        return message
+    class Root(dispatcher.Handler):
+        @handler(u"Print all the arguments, return nothing.")
+        def test(self, *args):
+            print 'test:', args
+        @handler(u"Echo the message passed as argument.")
+        def echo(self, message):
+            print 'echo:', message
+            return message
 
-    PyminDaemon(dict(test=test_handler, echo=echo_handler)).run()
+    PyminDaemon(Root()).run()
 
diff --git a/pymind b/pymind
index 27a972269c7597f73a4fe40926cc592a90bf0e9b..a04307d1920909bbd3a25cce42c0c9d8fbb5dbcf 100755 (executable)
--- a/pymind
+++ b/pymind
@@ -4,5 +4,5 @@
 from pymin.pymindaemon import PyminDaemon
 import config
 
-PyminDaemon(config.routes, config.bind_addr).run()
+PyminDaemon(config.Root(), config.bind_addr).run()