rhino.mapper
The mapper dispatches incoming requests based on URL templates and also provides a WSGI interface.
The HTTP request's path is matched against a series of patterns in the order they were added. Patterns may be given as strings that must match the request path exactly, or they may be templates.
Groups of matching characters for templates are extracted from the URL and accessible via the routing_args
property of rhino.Request
.
A template is a string that can contain thee special kinds of markup:
{name}
or {name:range}
Whatever matches this part of the path will be available in the Request.routing_args
dict of named parameters under the key name
.
[]
Any part enclosed in brackets is optional. Brackets can be nested and contain named parameters. If an optional part contains named parameters and is missing from the request URL, the parameter names contained therein will also be missing from Request.routing_args
.
|
A vertical bar may only be present at the end of the template, and causes the path to be matched only against the part before the '|'
. The path can contain more characters after the match, which will be preserved in environ['PATH_INFO']
, where it can be used by nested mappers.
A named parameter can contain an optional named range specifier after a :
. which restricts what characters the parameter can match. The default ranges are as follows:
Range | Regular Expression |
---|---|
word | \w+ |
alpha | [a-zA-Z]+ |
digits | \d+ |
alnum | [a-zA-Z0-9]+ |
segment | [^/]+ |
unreserved | [a-zA-Z\d\-\.\_\~]+ |
any | .+ |
If no range is specified a parameter matches segment
.
Default ranges can be extended or overwritten by passing a dict mapping range names to regular expressions to the Mapper constructor. The regular expressions should be strings:
# match numbers in engineering format
mapper = Mapper(ranges={'real': r'(\+|-)?[1-9]\.[0-9]*E(\+|-)?[0-9]+'})
mapper.add('/a/b/{n:real}', my_math_app)
The '|'
is needed when nesting mappers:
foo_mapper = Mapper()
foo_mapper.add('/bar', bar_resource)
mapper = Mapper()
mapper.add('/', index)
mapper.add('/foo|', foo_mapper)
A request to /foo/bar
is now dispatched by mapper
to foo_mapper
and on to bar_resource
.
class Mapper
Class variables:
None
):default_encoding
of outgoing Responses. See rhino.Response
for details. Does not affect responses returned via exceptions.
None
):default_content_type
of outgoing Responses. See rhino.Response
for details. Does not affect responses returned via exceptions.
True
):wrap_wsgi_input
property on rhino.request.Request
instances created by this mapper.
__init__(ranges=None)
Create a new mapper.
The ranges
parameter can be used to override or augment the default ranges by passing in a dict mapping range names to regexp patterns.
add(template, resource, name=None)
Add a route to a resource.
The optional name
assigns a name to this route that can be used when building URLs. The name must be unique within this Mapper instance.
add_ctx_property(name, fn, cached=True)
Install a context property.
A context property is a callable that will be called on first access of the property named name
on Context
instances passing through this mapper. The result will be cached unless cached
is False.
If the context property is not callable, it will be installed as-is, otherwise, it will be called with the context instance as first argument.
add_wrapper(wrapper)
Install a wrapper.
A wrapper is a piece of middleware not unlike WSGI middelware but working with Request and Response objects instead. The argument to add_wrapper must be a callable that is called with the wrapped app as argument and should return another callable that accepts a Request and Context instance as arguments and returns a Response. The wrapper has full control over the execution. It can call the wrapped app to pass on the request, modify the response, etc.
Wrappers can be nested. This:
app = Mapper()
app.add_wrapper(wrapper1)
app.add_wrapper(wrapper2)
Could also be achieved like this:
app = Mapper()
app = wrapper2(wrapper1(app))
Except that in the first version 'app' still has all methods of Mapper.
Example for a wrapper that adds an X-Powered-By header to outgoing responses:
def add_x_powered_by_wrapper(app):
def wrap(request, ctx):
response = app(request)
response.headers['X-Powered-By'] = 'Unicorns'
return response
return wrap
handle_error(request, exc_info)
Log the 'exc_info' tuple in the server log.
path(target, params)
Build a URL path fragment for a resource or route.
Possible values for target
:
Route
instancestart_server(host='localhost', port=9000, app=None)
Start a wsgiref.simple_server
based server to run this mapper.
wsgi(environ, start_response)
Implements the mapper's WSGI interface.
class Route
A Route links a URL template and an optional name to a resource.
__init__(template, resource, ranges=None, name=None)
path(params)
Builds the URL path fragment for this route.
class Context
__init__(request=None)
add_callback(phase, fn)
Adds a callback to the context.
The phase
determines when and if the callback is executed, and which positional arguments are passed in:
Called from rhino.Resource
, after a handler for the current request has been resolved, but before the handler is called.
Arguments: request
Called from rhino.Resource
, after the handler has returned successfully.
Arguments: request, response
Called from Mapper
, before the WSGI response is finalized.
Arguments: request, response
Called from Mapper
, before control is passed back to the WSGI layer.
Arguments: -
Called when the WSGI server calls close()
on the response iterator.
Arguments: -
add_property(name, fn, cached=True)
Adds a lazily initialized property to the Context.
See also Mapper.add_ctx_property
, which uses this method to install the properties added on the Mapper level.
class MapperException
class InvalidArgumentError
class InvalidTemplateError