Reputation: 3936
In old school webapp, app.yaml based routing allowed you to check for regular expressions and if matched, process a request by a handler whose name is based on the found pattern. For example \1_handler.py would dispatch to user_handler.py if the matched pattern was 'user'.
Is there a way to do the same thing with webapp2.Route? Can the lazy handler or the method_handler parameters be based on the matched patterns in template?
Upvotes: 1
Views: 1212
Reputation: 14487
webapp2 does not allow to route like that. I think the most reasonable solution is to write a custom dispatcher for webapp2.Router
.
It is possible to set a custom dispatcher like this:
app = WSGIApplication(...)
app.router.set_dispatcher(custom_dispatcher)
Here is a not tested sketch for dispatcher, code is based on webapp2.Router.default_dispatcher
:
from webapp2 import import_string
def custom_dispatcher(router, request, response):
route, args, kwargs = rv = router.match(request)
request.route, request.route_args, request.route_kwargs = rv
handler = route.handler
if isinstance(handler, basestring):
handler, args, kwargs = _parse_handler_template(handler, args, kwargs)
if handler not in self.handlers:
router.handlers[handler] = handler = import_string(handler)
else:
handler = router.handlers[handler]
return router.adapt(handler)(request, response)
def _parse_handler_template(handler, args, kwargs):
"""replace {key} in `handler` with values from `args` or `kwargs`.
Replaced values are removed from args/kwargs."""
args = list(args)
kwargs = dict(kwargs)
def sub(match):
if kwargs:
return kwargs.pop(match.group().strip('{}'))
else:
return args.pop(int(match.group().strip('{}'))
return re.sub('{.*?}', sub, handler), args, kwargs
This code should allow to register a rules like this:
app = WSGIApplication([
(r'module/<module>/<action>/<argument>', 'modules.{module}.action_{action}'),
])
This example does not allow to use variables from pattern in method name, for example: module.Class:action_{method}
. In Route
class this endpoint is split by semicolon and values stored in route.method_name
and route.handler
.
Upvotes: 4