Module 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.

Classes

class Mapper

Class variables:

default_encoding (default None):
When set, is used to override the default_encoding of outgoing Responses. See rhino.Response for details. Does not affect responses returned via exceptions.
default_content_type (default None):
When set, is used to override the default_content_type of outgoing Responses. See rhino.Response for details. Does not affect responses returned via exceptions.
wrap_wsgi_input (default True):
Used to set the 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:

A string that does not contain a '.'
If the string does not contain a dot, it will be used to look up a named route of this mapper instance and return it's path.
A string of the form 'a.b', 'a.b.c', etc.
Follows the route to nested mappers by splitting off consecutive segments. Returns the path of the route found by looking up the final segment on the last mapper.
A Route instance
Returns the path for the route.
A resource that was added previously
Looks up the first route that points to this resource and returns its path.

start_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:

'enter'

Called from rhino.Resource, after a handler for the current request has been resolved, but before the handler is called.

Arguments: request

'leave'

Called from rhino.Resource, after the handler has returned successfully.

Arguments: request, response

'finalize'

Called from Mapper, before the WSGI response is finalized.

Arguments: request, response

'teardown'

Called from Mapper, before control is passed back to the WSGI layer.

Arguments: -

'close'

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.

Exceptions

class MapperException

class InvalidArgumentError

class InvalidTemplateError