Skip to content

Commit e753d2f

Browse files
committedMar 16, 2014
improve support for tornado
1 parent 2ea5262 commit e753d2f

10 files changed

+177
-13
lines changed
 

‎ioc/component.py

+3
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ def build_container(self, container):
236236
'container_builder': self
237237
})
238238

239+
for extension in extensions:
240+
extension.start(container)
241+
239242
return container
240243

241244
def create_definition(self, id):

‎ioc/extra/tornado/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'rande'

‎ioc/extra/tornado/di.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import ioc
2+
import os
3+
from ioc.extra.tornado.handler import RouterHandler
4+
from tornado.web import StaticFileHandler
5+
6+
class Extension(ioc.component.Extension):
7+
def load(self, config, container_builder):
8+
path = os.path.dirname(os.path.abspath(__file__))
9+
10+
loader = ioc.loader.YamlLoader()
11+
loader.load("%s/resources/config/services.yml" % path, container_builder)
12+
13+
container_builder.parameters.set('ioc.extra.tornado.port', config.get('port', 8888))
14+
container_builder.parameters.set('ioc.extra.tornado.static_folder', config.get('static_folder', '%project.root_folder%/resources/static'))
15+
container_builder.parameters.set('ioc.extra.tornado.static_public_path', config.get('static_public_path', '/static'))
16+
17+
def post_load(self, container_builder):
18+
if not container_builder.has('ioc.extra.jinja2'):
19+
return
20+
21+
definition = container_builder.get('ioc.extra.tornado.router')
22+
definition.add_tag('jinja2.global', {'name': 'url_for', 'method': 'generate'})
23+
24+
definition = container_builder.get('ioc.extra.tornado.asset_helper')
25+
definition.add_tag('jinja2.global', {'name': 'asset', 'method': 'generate_asset'})
26+
27+
def start(self, container):
28+
application = container.get('ioc.extra.tornado.application')
29+
application.add_handlers(".*$", [
30+
("/.*", RouterHandler, {
31+
"router": container.get('ioc.extra.tornado.router'),
32+
"event_dispatcher": container.get('ioc.extra.event_dispatcher'),
33+
"logger": container.get('element.logger')
34+
})
35+
])
36+
37+
application.add_handlers(".*$", [
38+
(container.parameters.get("ioc.extra.tornado.static_public_path") + "/(.*)", StaticFileHandler, {
39+
"path": container.parameters.get("ioc.extra.tornado.static_folder")
40+
})
41+
])

‎ioc/extra/tornado/handler.py

+57-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import tornado.web
44
import tornado.httpclient
5+
import mimetypes
56

67
class BaseHandler(tornado.web.RequestHandler):
78
def dispatch(self):
@@ -25,51 +26,98 @@ def head(self):
2526
def options(self):
2627
return self.dispatch()
2728

29+
def is_finish(self):
30+
return self._finished
31+
32+
def get_header(self, name):
33+
return self._headers.get(name)
34+
2835
class RouterHandler(BaseHandler):
29-
def initialize(self, router, event_dispatcher):
36+
def initialize(self, router, event_dispatcher, logger=None):
3037
self.router = router
3138
self.event_dispatcher = event_dispatcher
39+
self.logger = logger
3240

3341
def dispatch(self):
3442
try:
35-
self.event_dispatcher.dispatch('handler.request', {'handler': self})
43+
self.event_dispatcher.dispatch('handler.request', {
44+
'request_handler': self,
45+
'request': self.request
46+
})
47+
48+
if self.is_finish():
49+
return
3650

3751
name, parameters, callback = self.router.match(path_info=self.request.path, method=self.request.method)
3852

53+
if self.logger:
54+
self.logger.debug("[ioc.extra.tornado.RouterHandler] Match name:%s with parameters:%s (%s)" % (name, parameters, callback))
55+
3956
event = self.event_dispatcher.dispatch('handler.callback', {
40-
'handler': self,
57+
'request_handler': self,
58+
'request': self.request,
4159
'name': name,
4260
'callback': callback,
4361
'parameters': parameters
4462
})
4563

64+
if self.is_finish():
65+
return
66+
4667
event.get('callback')(self, **event.get('parameters'))
4768

69+
if self.is_finish():
70+
return
71+
4872
except NotFound:
4973
self.set_status(404)
5074
self.write("Not Found")
5175

5276
self.event_dispatcher.dispatch('handler.not_found', {
53-
'handler': self,
77+
'request_handler': self,
78+
'request': self.request,
5479
})
5580
except Exception, e:
5681
self.set_status(500)
5782
self.write("An unexpected error occurred")
5883

5984
import traceback
60-
traceback.print_exc()
85+
self.write("<pre>" + traceback.format_exc() + "</pre>")
6186

87+
print traceback.print_exc()
6288

6389
self.event_dispatcher.dispatch('handler.exception', {
64-
'handler': self,
90+
'request_handler': self,
91+
'request': self.request,
6592
})
6693

94+
if self.is_finish():
95+
return
96+
6797
self.event_dispatcher.dispatch('handler.response', {
68-
'handler': self,
98+
'request_handler': self,
99+
'request': self.request,
69100
})
70101

71-
self.finish()
102+
if not self.is_finish():
103+
self.finish()
72104

73105
self.event_dispatcher.dispatch('handler.terminate', {
74-
'handler': self,
106+
'request_handler': self,
107+
'request': self.request,
75108
})
109+
110+
111+
def send_file(self, file):
112+
"""
113+
Send a file to the client, it is a convenient method to avoid duplicated code
114+
"""
115+
mime_type, encoding = mimetypes.guess_type(file)
116+
117+
if mime_type:
118+
self.set_header('Content-Type', mime_type)
119+
120+
fp = open(file, 'r')
121+
self.write(fp.read())
122+
123+
fp.close()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
services:
2+
ioc.extra.tornado.router:
3+
class: ioc.extra.tornado.router.Router
4+
5+
ioc.extra.tornado.application:
6+
class: tornado.web.Application
7+
arguments: []
8+
kwargs:
9+
debug: True
10+
autoreload: True
11+
compiled_template_cache: True
12+
static_hash_cache: True
13+
serve_traceback: True
14+
gzip: True
15+
cookie_secret: MySecret
16+
17+
ioc.extra.tornado.asset_helper:
18+
class: ioc.extra.tornado.router.AssetHelper
19+
arguments: [ "%ioc.extra.tornado.static_public_path%", '@ioc.extra.tornado.router', 'element.static']
20+

‎ioc/extra/tornado/router.py

+50
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,54 @@
11
from werkzeug.routing import Map, Rule
2+
import time
3+
4+
class AssetHelper(object):
5+
def __init__(self, static, router, route_name, version=None):
6+
self.static = static
7+
self.version = version or int(time.time())
8+
self.router = router
9+
self.route_name = route_name
10+
11+
def generate_asset(self, path, module=None):
12+
if not module:
13+
return self.generate_static(path)
14+
15+
return self.router.generate(self.route_name, filename=path, module=module, v=self.version)
16+
17+
def generate_static(self, path):
18+
"""
19+
This method generates a valid path to the public folder of the running project
20+
"""
21+
if not path:
22+
return ""
23+
24+
if path[0] == '/':
25+
return "%s?v=%s" % (path, self.version)
26+
27+
return "%s/%s?v=%s" % (self.static, path, self.version)
28+
29+
class TornadoMultiDict(object):
30+
"""
31+
This code make the RequestHandler.arguments compatible with WTForm module
32+
"""
33+
def __init__(self, handler):
34+
self.handler = handler
35+
36+
def __iter__(self):
37+
return iter(self.handler.request.arguments)
38+
39+
def __len__(self):
40+
return len(self.handler.request.arguments)
41+
42+
def __contains__(self, name):
43+
# We use request.arguments because get_arguments always returns a
44+
# value regardless of the existence of the key.
45+
return (name in self.handler.request.arguments)
46+
47+
def getlist(self, name):
48+
# get_arguments by default strips whitespace from the input data,
49+
# so we pass strip=False to stop that in case we need to validate
50+
# on whitespace.
51+
return self.handler.get_arguments(name, strip=False)
252

353
class Router(object):
454
def __init__(self, url_map=None):

‎requirements.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
PyYAML
22
coverage
33
nose
4-
jinja2
5-
Sphinx
4+
jinja2

‎requirements_python2.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
-r requirements.txt
22
unittest2
3+
Sphinx===2.7

‎requirements_python3.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
-r requirements.txt
2-
unittest2py3k
2+
unittest2py3k
3+
Sphinx===2.6

‎setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
packages = find_packages(),
1616
install_requires=["pyyaml"],
1717
platforms='any',
18-
)
18+
)

0 commit comments

Comments
 (0)
Please sign in to comment.