User Guide¶
Pattern and Handler¶
You create a mapping between: pattern
(a remainder of the request URL,
script name, http schema, host name or whatever else) and handler
(callable, string, etc.):
urls = [
('posts/2003', posts_for_2003),
('posts/{year}', posts_by_year),
('posts/(?P<year>\d+)/(?P<month>\d+)', posts_by_month)
]
It is completely up to you how to interpret pattern
(you can add own
patterns interpretation) and/or handler
. If you have a look at
Hello World example you notice the following:
return handler(environ, start_response)
or more specifically:
environ['PATH_INFO']
This operation takes the WSGI environment variable PATH_INFO
and passes it to
router for matching against available mappings. handler
in this case is a
simple callable that represents WSGI call handler.
def ntob(n, encoding):
return n
Extend Mapping¶
Since mapping
is nothing more than python list, you can make any
manipulation you like, e.g. add other mappings, construct them dynamically,
etc. Here is snippet from Server Time example:
all_urls = [("", welcome), ("server/", server_urls)]
all_urls += [url("{url:any}", not_found)]
home
mapping has been extended by simple adding another list.
Mapping Inclusion¶
Your application may be constructed with several modules, each of them
can have own url mapping. You can easily include them as a handler
(the
system checks if the handler is another mapping it creates nested
PathRouter
). Here is an example from Server Time:
server_urls = [url("time", server_time, name="now")]
all_urls = [("", welcome), ("server/", server_urls)]
all_urls += [url("{url:any}", not_found)]
server_urls
included into server/
subpath. So effective path for
server_time
handler is server/time
.
Note that the route selected for 'server/'
pattern is intermediate (it is not
finishing since there is another pattern included after it). The 'time'
pattern is
finishing since it is the last in the match chain.
Named Groups¶
Named groups are something that you can retrieve from the url mapping:
urls = [
('posts/{year}', posts_by_year),
('posts/(?P<year>\d+)/(?P<month>\d+)', posts_by_month)
]
kwargs
is assigned a dict
that represends key-value pairs
from the match:
>>> handler, kwargs = r.match('posts/2011/09')
>>> kwargs
{'month': '09', 'year': '2011'}
Extra Parameters¶
While named groups
get some information from the matched path
, you
can also merge these with some extra values during initialization of the mapping
(this is third parameter in tuple):
urls = [
('posts', latest_posts, {'blog_id': 100})
]
Note, that any values from the path match override extra parameters passed during initialization.
url
helper¶
There is wheezy.routing.router.url()
function that let you
make your url mappings more readable:
from wheezy.routing import url
urls = [
url('posts', latest_posts, kwargs={'blog_id': 100})
]
All it does just convers arguments to a tuple of four.
Named Mapping¶
Each path mapping you create is automatically named after the handler name.
The convention as to the name is: translate handler name from camel case
to underscore name and remove any ending like ‘handler’, ‘controller’, etc.
So LatestPostsHandler
is named as latest_posts
.
You can also specify an explicit name during mapping, it is convenient to use
url()
) function for this:
urls = [
url('posts', latest_posts, name='posts')
]
When you know the name for a url mapping, you can reconstruct its path.
Adding Routes¶
You have an instance of PathRouter
.
Call its method add_routes()
to add any pattern mapping you have. Here is how we do it in
the Hello World example:
r = PathRouter()
r.add_routes([("/", hello_world), ("/{any}", not_found)])
… or Server Time:
from urls import all_urls # noqa: I201
router.add_routes(all_urls)
Route Builders¶
Every pattern mapping you add to router is translated to an appropriate route
match strategy. The available routing match strategies are definded in
config
module by route_builders
list and
include:
- plain
- regex
- curly
You can easily extend this list with your own route strategies.
Plain Route¶
The plain route is selected in case the path satisfy the following regular
expression (at least one word
, '/'
or '-'
character):
The matching paths include: account/login
, blog/list
, etc. The
strategy performs string matching.
Finishing routes are matched by exact string equals
operation, intermediate
routes are matched with startswith
string operation.
Regex Route¶
Any valid regular expression will match this strategy. However there are a few limitations that apply if you would like to build paths by name (reverse function to path matching). Use regex syntax only inside named groups, create as many as necessary. The path build strategy simply replaces named groups with values supplied. Optional named groups are supported.
Curly Route¶
This is just a simplified version of regex routes. Curly route is something that matches the following regular expression:
You define a named group by using curly brakets. The form of
curly expression (pattern
is optional and corresponds to segment by
default):
{name[:pattern]}
The curly expression abc/{id}
is converted into regex abc/(?P<id>[^/]+)
.
The name inside the curly expression can be constrained with the following patterns:
i
,int
,number
,digits
- one or more digitsw
,word
- one or more word characterss
,segment
,part
- everything until'/'
(path segment)*
,a
,any
,rest
- match anything
Note that if the pattern constraint doesn’t correspond to anything mentioned above, then it will be interpreted as a regular expression:
locale:(en|ru)}/home => (?P<locale>(en|ru))/home
Curly routes also support optional values (these should be taken into square brackets):
[{locale:(en|ru)}/]home => ((?P<locale>(en|ru))/)?home
Here are examples of valid expressions:
posts/{year:i}/{month:i}
account/{name:w}
You can extend the recognized curly patterns:
from wheezy.routing.curly import patterns
patterns['w'] = r'\w+'
This way you can add your custom patterns.
Building Paths¶
Once you have defined routes you can build paths from them. See Named Mapping how the name of url mapping is constructed. Here is a example from Server Time:
def server_time(environ, start_response):
start_response("200 OK", [("Content-type", "text/plain")])
You can pass optional values (kwargs
argument) that will be used
to replace named groups of the path matching pattern:
>>> r = RegexRoute(
... r'abc/(?P<month>\d+)/(?P<day>\d+)',
... kwargs=dict(month=1, day=1)
... )
>>> r.path_for(dict(month=6, day=9))
'abc/6/9'
>>> r.path_for(dict(month=6))
'abc/6/1'
>>> r.path_for()
'abc/1/1'
Values passed to the path_for()
method override any values used during initialization of url mapping.
KeyError
is raised in case you try to build a path
that doesn’t exist or provide insufficient arguments for building a path.