--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmsk/web/application.py Sat Jun 07 16:21:39 2014 +0300
@@ -0,0 +1,138 @@
+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 respond (self, request):
+ """
+ Lookup Request -> Handler, params -> Response
+ """
+
+ # bind to request
+ urls = self.urls.bind_to_environ(request)
+
+ # lookup
+ handler, params = urls.match()
+
+ # handler instance
+ handler = handler(self, request, urls)
+
+ 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 mimetype (self):
+ return self.MIMETYPE
+
+ def status (self):
+ return 200
+
+ 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())
+
+ def cleanup (self) :
+ """
+ After request processing. Do not fail :)
+ """
+
+ pass
+