We start with a simple helloworld example, than add a bit more modularity in server time. Before we proceed with examples below let setup virtualenv environment:
$ virtualenv env
$ env/bin/easy_install wheezy.routing
helloworld.py shows you how to use Wheezy Routing in pretty a simple WSGI application:
import sys
from wheezy.routing import PathRouter
if sys.version_info[0] >= 3:
ntob = lambda n, encoding: n.encode(encoding)
else:
ntob = lambda n, encoding: n
def hello_world(environ, start_response):
start_response('200 OK', [
('Content-Type', 'text/html')
])
yield ntob('Hello World!', 'utf-8')
def not_found(environ, start_response):
start_response('404 Not Found', [
('Content-Type', 'text/html')
])
yield ntob('', 'utf-8')
r = PathRouter()
r.add_routes([
('/', hello_world),
('/{any}', not_found)
])
def main(environ, start_response):
handler, kwargs = r.match(environ['PATH_INFO'])
return handler(environ, start_response)
if __name__ == '__main__':
from wsgiref.simple_server import make_server
try:
print('Visit http://localhost:8080/')
make_server('', 8080, main).serve_forever()
except KeyboardInterrupt:
pass
print('\nThanks!')
Let have a look through each line in this application. First of all we import PathRouter that is actually just an exporting name for PathRouter:
from wheezy.routing import PathRouter
Next we create a pretty simple WSGI handler to provide a response.
def hello_world(environ, start_response):
start_response('200 OK', [
('Content-Type', 'text/html')
])
yield ntob('Hello World!', 'utf-8')
In addition let add a handler for not found response.
def not_found(environ, start_response):
start_response('404 Not Found', [
('Content-Type', 'text/html')
])
yield ntob('', 'utf-8')
The declaration and mapping of pattern to handler following. We create an instance of PathRouter class and pass mapping that in this partucular case is a tuple of two values: pattern and handler.
r = PathRouter()
r.add_routes([
('/', hello_world),
('/{any}', not_found)
])
The first pattern '/' will match only root path of the request (it is finishing route in match chain). The second pattern '/{any}' is a curly expression that is translated to regular expression that ultimately match any path and is finishing route as well.
main function serves as WSGI application entry point. The only thing we do here is to get a value of WSGI environment variable PATH_INFO (the remainder of the request URL’s path) and pass to router match() method, in return we get handler and kwargs (parameters discovered from matching rule, that we ignore for now).
def main(environ, start_response):
handler, kwargs = r.match(environ['PATH_INFO'])
return handler(environ, start_response)
The rest in the helloworld application launch a simple wsgi server. Try it by running:
$ python helloworld.py
Visit http://localhost:8080/.
Server time application consists of two screens. The first one has a link to the second that shows the time on server. The second page will be mapped as a separate application with its own routing. The design used in this sample is modular. Let’s start with config module. The only thing we need here is an instance of PathRouter.
from wheezy.routing import PathRouter
router = PathRouter()
view module is pretty straight: a welcome view with a link to server_time view. The server time page returns server time. And finally catch all not_found handler to display http 404 error, page not found.
from datetime import datetime
from config import router as r
def welcome(environ, start_response):
start_response('200 OK', [
('Content-type', 'text/html')
])
return ["Welcome! <a href='%s'>Server Time</a>" %
r.path_for('now')]
def server_time(environ, start_response):
start_response('200 OK', [
('Content-type', 'text/plain')
])
return ["The server time is: %s" % datetime.now()]
def not_found(environ, start_response):
start_response("404 Not Found", [
('Content-Type', 'text/plain')
])
return ["Not Found: " + environ['routing.kwargs']['url']]
So what is interesting in welcome view is a way how we get an url for server_time view.
return ["Welcome! <a href='%s'>Server Time</a>" %
r.path_for('now')]
The name now was used during url mapping that you can see below (module urls):
from wheezy.routing import url
from views import welcome, server_time, not_found
server_urls = [
url('time', server_time, name='now')
]
all_urls = [
('', welcome),
('server/', server_urls)
]
all_urls += [
url('{url:any}', not_found)
]
server_urls than included under the parent path server/, so anything that starts from server/ path will be directed to server_urls url mapping. Lastly we add a curly expression that maps any url match to our not_found handler.
We combine that all together in app module.
from config import router
from urls import all_urls
router.add_routes(all_urls)
def main(environ, start_response):
handler, kwargs = router.match(environ['PATH_INFO'].lstrip('/'))
environ['routing.kwargs'] = kwargs
return map(lambda chunk: chunk.encode('utf8'),
handler(environ, start_response))
if __name__ == '__main__':
from wsgiref.simple_server import make_server
try:
print('Visit http://localhost:8080/')
make_server('', 8080, main).serve_forever()
except KeyboardInterrupt:
pass
print('\nThanks!')
Try it by running:
$ python app.py
Visit http://localhost:8080/.