Skip to content

Commit 5d394a3

Browse files
committed
add support for tornado
1 parent 3688e9f commit 5d394a3

File tree

6 files changed

+174
-0
lines changed

6 files changed

+174
-0
lines changed

ioc/extra/tornado/handler.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from werkzeug.routing import NotFound
2+
3+
import tornado.web
4+
import tornado.httpclient
5+
6+
class BaseHandler(tornado.web.RequestHandler):
7+
def dispatch(self):
8+
pass
9+
10+
def get(self):
11+
return self.dispatch()
12+
13+
def post(self):
14+
return self.dispatch()
15+
16+
def put(self):
17+
return self.dispatch()
18+
19+
def delete(self):
20+
return self.dispatch()
21+
22+
def head(self):
23+
return self.dispatch()
24+
25+
def options(self):
26+
return self.dispatch()
27+
28+
class RouterHandler(BaseHandler):
29+
def initialize(self, router, event_dispatcher):
30+
self.router = router
31+
self.event_dispatcher = event_dispatcher
32+
33+
def dispatch(self):
34+
try:
35+
self.event_dispatcher.dispatch('handler.request', {'handler': self})
36+
37+
name, parameters, callback = self.router.match(path_info=self.request.path, method=self.request.method)
38+
39+
event = self.event_dispatcher.dispatch('handler.callback', {
40+
'handler': self,
41+
'name': name,
42+
'callback': callback,
43+
'parameters': parameters
44+
})
45+
46+
event.get('callback')(self, **event.get('parameters'))
47+
48+
except NotFound:
49+
self.set_status(404)
50+
self.write("Not Found")
51+
52+
self.event_dispatcher.dispatch('handler.not_found', {
53+
'handler': self,
54+
})
55+
except Exception:
56+
self.set_status(500)
57+
self.write("An unexpected error occurred")
58+
59+
self.event_dispatcher.dispatch('handler.exception', {
60+
'handler': self,
61+
})
62+
63+
self.event_dispatcher.dispatch('handler.response', {
64+
'handler': self,
65+
})
66+
67+
self.finish()
68+
69+
self.event_dispatcher.dispatch('handler.terminate', {
70+
'handler': self,
71+
})

ioc/extra/tornado/router.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from werkzeug.routing import Map, Rule
2+
3+
class Router(object):
4+
def __init__(self, url_map=None):
5+
self._url_map = url_map or Map([])
6+
self._view_functions = {}
7+
self._adapter = None
8+
9+
10+
def add(self, name, pattern, view_func, defaults=None, subdomain=None, methods=None,
11+
build_only=False, strict_slashes=None,
12+
redirect_to=None, alias=False, host=None):
13+
14+
self._url_map.add(Rule(pattern, endpoint=name, defaults=defaults, subdomain=subdomain, methods=methods,
15+
build_only=build_only, strict_slashes=strict_slashes, redirect_to=redirect_to,
16+
alias=alias, host=host))
17+
18+
self._view_functions[name] = view_func
19+
20+
self._adapter = None
21+
22+
def adapter(self):
23+
if not self._adapter:
24+
self._adapter = self._url_map.bind("localhost")
25+
26+
return self._adapter
27+
28+
def match(self, path_info=None, method=None, return_rule=False, query_args=None):
29+
name, parameters = self.adapter().match(path_info, method, return_rule, query_args)
30+
31+
return name, parameters, self._view_functions[name]
32+
33+
def generate(self, name, values=None, method=None, force_external=False, append_unknown=True):
34+
35+
return self.adapter().build(name, values, method, force_external, append_unknown)

tests/ioc/extra/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'rande'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'rande'
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from tornado.testing import AsyncHTTPTestCase
2+
from tornado.web import Application
3+
4+
from ioc.event import Dispatcher
5+
6+
from ioc.extra.tornado.router import Router
7+
from ioc.extra.tornado.handler import RouterHandler
8+
9+
def view(handler, name=None):
10+
handler.write("Hello %s" % name)
11+
12+
def error(handler):
13+
raise Exception()
14+
15+
class MyHTTPTest(AsyncHTTPTestCase):
16+
def get_app(self):
17+
router = Router()
18+
router.add("hello", "/hello/<string:name>", view, methods=['GET'])
19+
router.add("exception", "/exception", error, methods=['GET'])
20+
21+
return Application([("/.*", RouterHandler, dict(router=router, event_dispatcher=Dispatcher()))])
22+
23+
def test_not_found(self):
24+
response = self.fetch('/')
25+
self.assertEquals("Not Found", response.body)
26+
self.assertEquals(404, response.code)
27+
28+
def test_found(self):
29+
response = self.fetch('/hello/Thomas')
30+
self.assertEquals("Hello Thomas", response.body)
31+
self.assertEquals(200, response.code)
32+
33+
def test_error(self):
34+
response = self.fetch('/exception')
35+
self.assertEquals("An unexpected error occurred", response.body)
36+
self.assertEquals(500, response.code)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import unittest
2+
3+
from ioc.extra.tornado.router import Router
4+
5+
def view():
6+
return "hello"
7+
8+
class RouterTest(unittest.TestCase):
9+
def setUp(self):
10+
11+
self.router = Router()
12+
13+
def test_add_and_match_routes(self):
14+
self.router.add("homepage", "/", view)
15+
16+
self.assertEquals(('homepage', {}, view), self.router.match("/"))
17+
18+
self.router.add("blog_post", "/blog/<string:slug>", view, methods=['GET'])
19+
20+
self.assertEquals(('blog_post', {'slug': 'hello'}, view), self.router.match("/blog/hello"))
21+
22+
def test_add_and_generate_routes(self):
23+
24+
self.router.add("homepage", "/", view)
25+
self.router.add("blog_post", "/blog/<string:slug>", view)
26+
27+
self.assertEquals("/", self.router.generate("homepage"))
28+
self.assertEquals("/blog/hello", self.router.generate("blog_post", {'slug': 'hello'}))
29+
30+
self.assertEquals("http://localhost/blog/hello", self.router.generate("blog_post", {'slug': 'hello'}, force_external=True))

0 commit comments

Comments
 (0)