rutter: Python3-compatible WSGI composite¶
rutter forks the paste.urlmap module in order to provide a Python3-compatible impolementation, as well as the improved test coverage needed to support using the module across all supported Python versions.
The primary export of rutter is the rutter.urlmap.URLMap class. URLMap instances are dictionary-like objects which dispatch to WSGI applications based on the URL.
The keys in a URLMap are URL patterns, which match as prefixes of the request URL (e.g., like PATH_INFO.startswith(key)). Its values are WSGI applications to which matching requests are dispatched. On finding a match, the URLMap adjusts the SCRIPT_NAME and PATH_INFO environmental variables to indicate the new context.
URL Matching Rules¶
- URLs are matched most-specific-first, i.e., longest URL first.
- URL prefixes can also include domains, e.g. http://blah.com/foo. Domains can also be specified as tuples (‘blah.com’, ‘/foo’).
- If a given pattern includes a domain, its path will only be tested if the HTTP_HOST environment variable matches.
- Patterns which do not have domains will be tested only if no domain-specifc pattern matches.
Assume we want to serve two WSGI applications provided by separate modules, alpha:
from pyramid.config import Configurator from pyramid.view import view_config @view_config(renderer='string') def hello_alpha(request): return 'Hello, Alpha' def main(global_config=None, **local_config): config = Configurator() config.scan() return config.make_wsgi_app()
from pyramid.config import Configurator from pyramid.view import view_config @view_config(renderer='string') def hello_bravo(request): return 'Hello, Bravo' def main(global_config=None, **local_config): config = Configurator() config.scan() return config.make_wsgi_app()
Although these examples use pyramid; any WSGI-compliant application can be used as a dispatch target.
Imperative Configuration in Python¶
from wsgiref.simple_server import make_server from rutter.urlmap import URLMap from alpha import main as alpha_main from bravo import main as bravo_main def main(): # Grab the config, add a view, and make a WSGI app urlmap = URLMap() urlmap['/alpha'] = alpha_main() urlmap['/bravo'] = bravo_main() return urlmap if __name__ == '__main__': # When run from command line, launch a WSGI server and app app = main() server = make_server('0.0.0.0', 6543, app) server.serve_forever()
Assuming that alpha and bravo are importable, along with rutter, we can run this application:
$ /path/to/python example/imperative.py
Declarative Configuration using paste.deploy INI files¶
Assuming that we have a paste.deploy-compatible server starter (such as the pserve script installed by pyramid), we can configure the :class:`~rutter.urlmap.URLMap via an INI file:
[app:alpha] use = egg:rutter_example#alpha [app:bravo] use = egg:rutter_example#bravo [composite:main] use = egg:rutter#urlmap /bravo = bravo /alpha = alpha [server:main] use = egg:pyramid#wsgiref port = 6543 host = 127.0.0.1
And then run the composite application using the starter:
$ /path/to/pserve example/development.ini