|
1 import werkzeug |
|
2 from werkzeug import exceptions |
|
3 from werkzeug import Request, Response |
|
4 from werkzeug.routing import Map, Rule |
|
5 |
|
6 import logging |
|
7 |
|
8 # logging |
|
9 log = logging.getLogger('svv.wsgi') |
|
10 |
|
11 class AppHandler (object): |
|
12 """ |
|
13 Per-request handler context |
|
14 """ |
|
15 |
|
16 # default content type for response |
|
17 CONTENT_TYPE = 'text/html' |
|
18 |
|
19 def __init__ (self, request) : |
|
20 """ |
|
21 Initialize for processing the given Request, to prepare for action-method later on |
|
22 """ |
|
23 |
|
24 self.request = request |
|
25 |
|
26 def respond (self, url_values) : |
|
27 """ |
|
28 Handle request that was mapped to ourselves via the URL routing, using given dict of values from URL. |
|
29 """ |
|
30 |
|
31 # render |
|
32 html = unicode(self.render(**url_values)) |
|
33 |
|
34 # XXX: unicode |
|
35 return Response(html, mimetype='text/html') |
|
36 |
|
37 def render (self, **args) : |
|
38 """ |
|
39 Handling a GET request, returning the proper response HTML. |
|
40 """ |
|
41 |
|
42 raise NotImplementedError() |
|
43 |
|
44 import html |
|
45 from html import tags |
|
46 |
|
47 class Index (AppHandler) : |
|
48 def render (self) : |
|
49 title = "Index" |
|
50 css = ["/static/layout.css", "/static/style.css"] |
|
51 |
|
52 head = ( |
|
53 tags.title(title), |
|
54 (tags.link(rel='Stylesheet', type="text/css", href=src) for src in css), |
|
55 ) |
|
56 |
|
57 header = ("Foo List") |
|
58 nav = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Nav A', 'Nav B', 'Nav C'])] |
|
59 menu = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Menu A', 'Menu B', 'Menu C'])] |
|
60 footer = ("Copyright?") |
|
61 |
|
62 content = ( |
|
63 tags.ul(tags.li("Item #%d" % i) for i in xrange(10)) |
|
64 ) |
|
65 |
|
66 layout = ( |
|
67 tags.div(id='header')(header), |
|
68 tags.div(id='container')( |
|
69 tags.div(id='menu')(menu), |
|
70 tags.div(id='nav')(nav), |
|
71 tags.div(id='content')(content), |
|
72 ), |
|
73 tags.div(id='footer')(footer), |
|
74 ) |
|
75 |
|
76 return html.document(head, layout) |
|
77 |
|
78 class WSGIApp (object) : |
|
79 """ |
|
80 Top-level WSGI handler impl |
|
81 """ |
|
82 |
|
83 # URL paths |
|
84 # map to AppHandler-endpoint |
|
85 URLS = Map(( |
|
86 Rule('/', endpoint=Index), |
|
87 )) |
|
88 |
|
89 def __init__ (self) : |
|
90 pass |
|
91 |
|
92 # wrap to use werkzeug's Request/Response |
|
93 @Request.application |
|
94 def __call__ (self, req) : |
|
95 """ |
|
96 Main WSGI entry point, error handling |
|
97 """ |
|
98 |
|
99 try : |
|
100 # wrapped handler |
|
101 response = self.request(req) |
|
102 |
|
103 except exceptions.HTTPException, e : |
|
104 # format properly as response, also includes redirects |
|
105 return e.get_response(req.environ) |
|
106 |
|
107 # XXX: except Exception, e : |
|
108 # XXX: we want to trap errors in prod, but not in dev? |
|
109 |
|
110 else : |
|
111 # a-ok |
|
112 return response |
|
113 |
|
114 def request (self, req) : |
|
115 """ |
|
116 Wrapped request handler, URL mapping |
|
117 """ |
|
118 |
|
119 # map URLs against this request |
|
120 urls = self.URLS.bind_to_environ(req) |
|
121 |
|
122 # lookup matching URL for handler type and matched values from URL |
|
123 url_handler, url_values = urls.match() |
|
124 |
|
125 # the per-request handler (from endpoint) |
|
126 req_handler = url_handler(req) |
|
127 |
|
128 # XXX: per-method thing? |
|
129 response = req_handler.respond(url_values) |
|
130 |
|
131 # ok |
|
132 return response |
|
133 |
|
134 |