from werkzeug.wrappers import Request, Response
from werkzeug.exceptions import (
HTTPException,
BadRequest, # 400
NotFound, # 404
)
from werkzeug.utils import redirect
class Application:
URLS = None
def __init__ (self, urls=None):
"""
urls - werkzeug.routing.Map -> Handler
"""
if not urls:
urls = self.URLS
if not urls:
raise ValueError("Required URLS/urls=...")
self.urls = urls
def lookup (self, request):
"""
Lookup Request -> Handler, params
"""
# bind to request
urls = self.urls.bind_to_environ(request)
# lookup
handler, params = urls.match()
# handler instance
handler = handler(self, request, urls)
return handler, params
def respond (self, request):
"""
Process Request -> Response, using lookup()
"""
handler, params = self.lookup(request)
try :
handler.init()
# apply
return handler.respond(**params)
finally :
handler.cleanup()
@Request.application
def __call__ (self, request) :
"""
WSGI entry point, werkzeug Request -> Response
"""
try :
return self.respond(request)
except HTTPException as ex :
return ex
class Handler (object) :
"""
Per-Request controller/view, containing the request context and generating the response.
"""
# werkzeug defaults to UTF-8
MIMETYPE = 'text/html'
def __init__ (self, app, request, urls) :
"""
app - wsgi.Application
request - werkzeug.Request
urls - werkzeug.routing.Map.bind_to_environ()
"""
self.app = app
self.request = request
self.urls = urls
def url (self, handler=None, **params) :
"""
Return an URL for given endpoint, with parameters,
"""
if not handler :
handler = self.__class__
return self.urls.build(handler, params)
## processing stages
def init (self) :
"""
Initialize on request start.
"""
pass
def process (self, **params) :
"""
Process request args to build internal request state.
May optionally return a Response, to e.g. redirect after POST.
"""
pass
def render (self) :
"""
Render response.
"""
raise NotImplementedError()
def status (self):
return 200
def headers (self):
return [ ]
def mimetype (self):
return self.MIMETYPE
def respond (self, **params) :
"""
Generate a response, or raise an HTTPException
"""
# returning e.g. redirect?
response = self.process(**params)
if response :
return response
return Response(self.render_response(), mimetype=self.mimetype(), status=self.status(), headers=self.headers())
def cleanup (self) :
"""
After request processing. Do not fail :)
"""
pass