Mercurial > p > roundup > code
annotate roundup/web/router.py @ 4925:997fa47c92d5 routing
routing: Strip leading slash from both path and pattern, add test
for pattern parameter matching
| author | anatoly techtonik <techtonik@gmail.com> |
|---|---|
| date | Wed, 20 Aug 2014 13:37:34 +0300 |
| parents | 6ee1844019d5 |
| children | 7920d700e580 |
| rev | line source |
|---|---|
|
4905
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
1 #!/usr/bin/env python |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
2 """ |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
3 The purpose of router is to make Roundup URL scheme configurable |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
4 and allow extensions add their own handlers and URLs to tracker. |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
5 |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
6 Public domain work by: |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
7 anatoly techtonik <techtonik@gmail.com> |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
8 """ |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
9 |
|
4924
6ee1844019d5
routing: Add DEBUG flag for troubleshooting
anatoly techtonik <techtonik@gmail.com>
parents:
4918
diff
changeset
|
10 DEBUG = False |
|
6ee1844019d5
routing: Add DEBUG flag for troubleshooting
anatoly techtonik <techtonik@gmail.com>
parents:
4918
diff
changeset
|
11 |
|
6ee1844019d5
routing: Add DEBUG flag for troubleshooting
anatoly techtonik <techtonik@gmail.com>
parents:
4918
diff
changeset
|
12 |
|
4905
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
13 import re |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
14 |
|
4906
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
15 # --- Example URL mapping |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
16 |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
17 class NamedObject(object): |
|
4925
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
18 """Object that outputs its name when printed""" |
|
4906
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
19 def __init__(self, name): |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
20 self.name = name |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
21 def __repr__(self): |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
22 return self.name |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
23 |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
24 ExampleHandler = NamedObject('ExampleHandler') |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
25 ExampleFileHandler = NamedObject('ExampleFileHandler') |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
26 |
|
4909
f31c93abedf6
routing: No leading slash in URL map patterns
anatoly techtonik <techtonik@gmail.com>
parents:
4907
diff
changeset
|
27 |
|
4918
35dc9191394d
routing: Use Router in cgi.client.main
anatoly techtonik <techtonik@gmail.com>
parents:
4910
diff
changeset
|
28 EXAMPLE_URL_MAP = ( |
|
4909
f31c93abedf6
routing: No leading slash in URL map patterns
anatoly techtonik <techtonik@gmail.com>
parents:
4907
diff
changeset
|
29 'static/(.*)', ExampleFileHandler, |
|
4910
e5f90a69f660
routing: Fix router test
anatoly techtonik <techtonik@gmail.com>
parents:
4909
diff
changeset
|
30 'index', ExampleHandler |
|
4906
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
31 ) |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
32 |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
33 |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
34 # --- Regexp based router |
|
b860ede03056
routing: Add example URL map
anatoly techtonik <techtonik@gmail.com>
parents:
4905
diff
changeset
|
35 |
|
4905
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
36 class Router(object): |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
37 |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
38 def __init__(self, urlmap=[]): |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
39 """ |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
40 `urlmap` is a list (pattern, handler, pattern, ...) |
|
4925
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
41 leading slash in pattern is stripped |
|
4905
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
42 """ |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
43 self.urlmap = urlmap |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
44 |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
45 def get_handler(self, urlpath): |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
46 """ |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
47 `urlpath` is a part of url /that/looks?like=this |
|
4925
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
48 (leading slash is optional, will be stripped anyway) |
|
4905
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
49 |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
50 returns tuple (handler, arguments) or (None, ()) |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
51 """ |
|
4909
f31c93abedf6
routing: No leading slash in URL map patterns
anatoly techtonik <techtonik@gmail.com>
parents:
4907
diff
changeset
|
52 # strip leading slashes before matching |
|
f31c93abedf6
routing: No leading slash in URL map patterns
anatoly techtonik <techtonik@gmail.com>
parents:
4907
diff
changeset
|
53 path = urlpath.lstrip('/') |
|
4905
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
54 for i in range(0, len(self.urlmap), 2): |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
55 pattern, handler = self.urlmap[i], self.urlmap[i+1] |
|
4925
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
56 pattern = pattern.lstrip('/') |
|
4924
6ee1844019d5
routing: Add DEBUG flag for troubleshooting
anatoly techtonik <techtonik@gmail.com>
parents:
4918
diff
changeset
|
57 if DEBUG: |
|
6ee1844019d5
routing: Add DEBUG flag for troubleshooting
anatoly techtonik <techtonik@gmail.com>
parents:
4918
diff
changeset
|
58 print('router: matching %s' % pattern) |
|
4910
e5f90a69f660
routing: Fix router test
anatoly techtonik <techtonik@gmail.com>
parents:
4909
diff
changeset
|
59 match = re.match(pattern, path) |
|
4905
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
60 if match: |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
61 return handler, match.groups() |
|
6e313bdf6b69
routing: Add new roundup.web namespace with router component
anatoly techtonik <techtonik@gmail.com>
parents:
diff
changeset
|
62 return (None, ()) |
|
4907
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
63 |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
64 |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
65 |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
66 # [ ] len(urlmap) should be even to avoid errors |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
67 # (find a way to explain this to users) |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
68 |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
69 if __name__ == '__main__': |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
70 |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
71 import unittest |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
72 class test_Router(unittest.TestCase): |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
73 def test_example_routes(self): |
|
4918
35dc9191394d
routing: Use Router in cgi.client.main
anatoly techtonik <techtonik@gmail.com>
parents:
4910
diff
changeset
|
74 router = Router(EXAMPLE_URL_MAP) |
|
4907
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
75 self.assertEquals(router.get_handler(''), (None, ())) |
|
4910
e5f90a69f660
routing: Fix router test
anatoly techtonik <techtonik@gmail.com>
parents:
4909
diff
changeset
|
76 handler, params = router.get_handler('/index') |
|
4907
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
77 self.assertEquals(handler, ExampleHandler) |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
78 self.assertEquals(params, tuple()) |
|
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
79 |
|
4925
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
80 def test_route_param(self): |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
81 def echo_handler(args): |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
82 return args |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
83 router = Router(('/files/(.*)', echo_handler)) |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
84 self.assertEquals(router.get_handler(''), (None, ())) |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
85 self.assertEquals(router.get_handler('/files'), (None, ())) |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
86 handler, params = router.get_handler('/files/filename') |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
87 self.assertEquals(handler, echo_handler) |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
88 self.assertEquals(params, ('filename',)) |
|
997fa47c92d5
routing: Strip leading slash from both path and pattern, add test
anatoly techtonik <techtonik@gmail.com>
parents:
4924
diff
changeset
|
89 |
|
4907
c37069a99cec
routing: Add self-test to router.py
anatoly techtonik <techtonik@gmail.com>
parents:
4906
diff
changeset
|
90 unittest.main() |
