# 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 = \
(
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
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.
(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)
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'))
d.dispatch('inst cmd3 arg1 arg2 arg3')
except CommandNotFoundError, e:
print 'Not found:', e
+ print
+ print
# Parser tests
p = parse_command('hello world')
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.
# 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 ..."
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()
from pymin.pymindaemon import PyminDaemon
import config
-PyminDaemon(config.routes, config.bind_addr).run()
+PyminDaemon(config.Root(), config.bind_addr).run()