Examples¶
Before we proceed let’s setup a virtualenv environment, activate it and install:
$ pip install wheezy.routing
Hello World¶
helloworld.py shows you how to use wheezy.routing in a pretty simple WSGI application:
from wheezy.routing import PathRouter
if sys.version_info[0] >= 3:
def ntob(n, encoding):
return n.encode(encoding)
else:
def ntob(n, encoding):
return 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, _ = 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’s have a look through each line in this application. First of all we
import PathRouter
that is actually just an
exporting name for PathRouter
:
Next we create a pretty simple WSGI handler to provide a response.
def ntob(n, encoding):
return n
In addition let’s add a handler for the ‘not found’ response.
yield ntob("Hello World!", "utf-8")
def not_found(environ, start_response):
start_response("404 Not Found", [("Content-Type", "text/html")])
The declaration and mapping of patterns to handlers follows. We create an
instance of PathRouter
class and pass it a mapping, that in this particular 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 the root path of the request (it is
finishing route in the match chain). The second pattern '/{any}'
is a curly
expression, that is translated to regular expression, that ultimately matches
any path and is a 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 it to the router
match()
method. In return we
get handler
and kwargs
(parameters discovered from matching rule,
that we ignore for now).
return handler(environ, start_response)
The rest in the helloworld
application launches a simple wsgi server.
Try it by running:
$ python helloworld.py
Visit http://localhost:8080/.
Server Time¶
The server time application consists of two screens. The first one has a link
to the second that shows the time on the 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()
The view
module is pretty straight: a welcome
view with a link to
server_time
view. The server time page returns the server time. And finally
a catch all not_found
handler to display http 404 error, page not found.
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 the welcome
view is a way how we get a url for
server_time
view.
def server_time(environ, start_response):
start_response("200 OK", [("Content-type", "text/plain")])
The name now
was used during url mapping as you can see below (module
urls
):
from wheezy.routing import url
server_urls = [url("time", server_time, name="now")]
all_urls = [("", welcome), ("server/", server_urls)]
all_urls += [url("{url:any}", not_found)]
server_urls
are then included under the parent path server/
, so
anything that starts with the path server/
will be directed to the
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 urls import all_urls # noqa: I201
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/.