import werkzeug
from werkzeug import exceptions
from werkzeug import Request, Response
from werkzeug.routing import Map, Rule
import logging
# logging
log = logging.getLogger('svv.wsgi')
class AppHandler (object):
"""
Per-request handler type, containing the request context and implementing the response.
Works on a generic level, i.e. WSGI/Werkzeug URL-mapped request in, response out.
"""
# default content type for response
CONTENT_TYPE = 'text/html'
def __init__ (self, request) :
"""
Initialize for processing the given Request, to prepare for action-method later on
"""
self.request = request
def respond (self, url_values) :
"""
Handle request that was mapped to ourselves via the URL routing, using given dict of values from URL.
"""
raise NotImplementedError()
import html
from html import tags
class PageHandler (AppHandler) :
"""
Specialized AppHandler for normal HTML page views.
Renders the layout template and HTML.
"""
def respond (self, url_values) :
title = "Index"
css = ["/static/layout.css", "/static/style.css", "/static/treelist.css"]
scripts = [
"/static/js/prototype.js",
"/static/js/scriptaculous/scriptaculous.js",
"/static/js/treelist.js"
]
head = (
tags.title(title),
(tags.link(rel='Stylesheet', type="text/css", href=src) for src in css),
# XXX: script can't self-close >_<
(tags.script(src=src)(" ") for src in scripts),
)
header = ("Foo List")
nav = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Nav A', 'Nav B', 'Nav C'])]
menu = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Menu A', 'Menu B', 'Menu C'])]
footer = ("Copyright?")
# render page HTML
content = self.render(**url_values)
layout = (
tags.div(id='header')(header),
tags.div(id='container')(
tags.div(id='menu')(menu),
tags.div(id='nav')(nav),
tags.div(id='content')(content),
),
tags.div(id='footer')(footer),
)
# perform the actual rendering (run generators etc.)
html_text = unicode(html.document(head, layout))
# response object
# XXX: unicode?
return Response(html_text, mimetype='text/html')
def render (self, **args) :
"""
Render and return HTML for page content.
XXX: must be HTML object, support just text?
"""
raise NotImplementedError()
class Index (PageHandler) :
DATA = (
(100, "Top A", []),
(200, "Top B", [
(210, "Mid BA", [
(211, "Sub BAA", []),
(212, "Sub BAB", []),
]),
(220, "Mid BB", []),
]),
(300, "Top C", [
(310, "Mid CA", []),
(320, "Mid CB", []),
]),
)
def render (self) :
# build data set
data = self.DATA
def render_item (id, text, children) :
return tags.li(
tags.div(class_='item')(
# item text
tags.a(tags.input(type='checkbox', name_=id, checked=(
'checked' if self.request.form.get(str(id)) else None
)), text, class_='text'),
),
# children
tags.ul(render_item(*item) for item in children if item) if children else None,
#
class_=('more open' if children else None),
)
# render it
return (
tags.h3("Item list"),
tags.form(action='.', method='post')(
tags.ul(class_='treelist')(render_item(*item) for item in data),
tags.input(type='submit'),
),
)
class WSGIApp (object) :
"""
Top-level WSGI handler impl
"""
# URL paths
# map to AppHandler-endpoint
URLS = Map((
Rule('/', endpoint=Index),
))
def __init__ (self) :
pass
# wrap to use werkzeug's Request/Response
@Request.application
def __call__ (self, req) :
"""
Main WSGI entry point, error handling
"""
try :
# wrapped handler
response = self.request(req)
except exceptions.HTTPException, e :
# format properly as response, also includes redirects
return e.get_response(req.environ)
# XXX: except Exception, e :
# XXX: we want to trap errors in prod, but not in dev?
else :
# a-ok
return response
def request (self, req) :
"""
Wrapped request handler, URL mapping
"""
# map URLs against this request
urls = self.URLS.bind_to_environ(req)
# lookup matching URL for handler type and matched values from URL
url_handler, url_values = urls.match()
# the per-request handler (from endpoint)
req_handler = url_handler(req)
# XXX: per-method thing?
response = req_handler.respond(url_values)
# ok
return response