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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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()

Roundup Issue Tracker: http://roundup-tracker.org/