Commits

Walt Woods committed 5493537

Added cherrypy.popargsHandler() to supplement cherrypy.popargs

Comments (0)

Files changed (2)

cherrypy/__init__.py

         
     return decorated
 
+def popargsHandler(handler, *args, **kwargs):
+    """This is a utility function designed to be mounted on a cherrypy object
+    to serve up a different handler based on a parameter in the url.  For
+    instance, if your application has multiple databases, each of which
+    have requests that are handled by a common DatabaseHandler class, but you
+    want the database ID to appear as the first part of the URL, you would
+    use popargsHandler as follows:
+
+    class DatabaseHandler:
+        def __init__(self, myDbName):
+            ...
+        @cherrypy.expose
+        def index(self):
+            ...
+    cherrypy.tree.mount(popargsHandler(DatabaseHandler, 'myDbName'))
+
+    This will make the URL '/blah/arg/klar' first create a DatabaseHandler
+    object initialized with the kwarg myDbName='blah'.  Then the cherrypy
+    default dispatcher would look for the property arg.klar in that 
+    DatabaseHandler object to handle the request.
+
+    You can also mount this class under another cherrypy object:
+
+    class Root:
+        user = popargsHandler(UserHandler, 'username')
+
+    This code will turn urls like '/user/blah/delete' into creating a 
+    UserHandler object with username='blah' to handle the 'delete' request.
+
+    Note that, like cherrypy.popargs(), vpath elements that do not exist
+    still try to execute the handler, but will not pass those kwargs not
+    existing in the path.  The caveat to this is that if no argument is passed,
+    popargsHandler() will not be executed, and any parent object's default()
+    method will be used instead.  That is, at least one of the arguments
+    specified in popargsHandler() must be passed in the URL for popargsHandler
+    to do anything.
+    """
+    class PopargsHandlerClass:
+        """Fake class whose only purpose is to proxy popargs"""
+        pass
+    cls = popargs(*args, handler=handler, **kwargs)(PopargsHandlerClass)
+    return cls()
+
 def url(path="", qs="", script_name=None, base=None, relative=None):
     """Create an absolute URL for the given path.
     

cherrypy/test/test_dynamicobjectmapping.py

     class ParameterizedPopArgs:
         """Test cherrypy.popargs() with a function call handler"""
     ParameterizedPopArgs = cherrypy.popargs('a', handler=ParameterizedHandler)(ParameterizedPopArgs)
-            
+
+    class PopArgsHandler:
+        """Test cherrypy.popargsHandler()"""
+        def __init__(self, **kwargs):
+            self.kwargs = kwargs
+        def index(self):
+            return str(self.kwargs)
+        index.exposed = True
+        def method(self):
+            return "PopArgsHandler.method()"
+        method.exposed = True
+
+    class PopArgsHandler2:
+        """Second test handler; ensures that nested class doesn't cause
+        issues.
+        """
+        def __init__(self, a):
+            self.a = a
+        def index(self):
+            return "second handler"
+        index.exposed = True
+
     Root.decorated = DecoratedPopArgs()
     Root.undecorated = NonDecoratedPopArgs()
     Root.index_only = IndexOnly()
     Root.parameter_test = ParameterizedPopArgs()
+    Root.popargs_handler = cherrypy.popargsHandler(PopArgsHandler, 'a', 'b')
+    Root.popargs_handler2 = cherrypy.popargsHandler(PopArgsHandler2, 'a')
 
     Root.users = UserContainerNode()
 
         self.getPage("/parameter_test/argument2/")
         self.assertBody("argument2")
 
+        # No params falls back to default
+        self.getPage("/popargs_handler/")
+        self.assertBody("default ('popargs_handler',)")
+
+        self.getPage("/popargs_handler/342/")
+        self.assertBody("{'a': '342'}")
+
+        self.getPage("/popargs_handler/344/245/")
+        self.assertBody("{'a': '344', 'b': '245'}")
+
+        self.getPage("/popargs_handler/344/245/method/")
+        self.assertBody("PopArgsHandler.method()")
+
+        self.getPage("/popargs_handler2/a/")
+        self.assertBody("second handler")
+