qmsk/web/application.py
changeset 92 e5799432071c
child 103 5263f65c990e
equal deleted inserted replaced
91:292b26405ee7 92:e5799432071c
       
     1 from werkzeug.wrappers import Request, Response
       
     2 from werkzeug.exceptions import (
       
     3         HTTPException,
       
     4         BadRequest,         # 400
       
     5         NotFound,           # 404
       
     6 )
       
     7 from werkzeug.utils import redirect
       
     8 
       
     9 class Application:
       
    10     URLS = None
       
    11 
       
    12     def __init__ (self, urls=None):
       
    13         """
       
    14             urls        - werkzeug.routing.Map -> Handler
       
    15         """
       
    16 
       
    17         if not urls:
       
    18             urls = self.URLS
       
    19 
       
    20         if not urls:
       
    21             raise ValueError("Required URLS/urls=...")
       
    22 
       
    23         self.urls = urls
       
    24 
       
    25     def respond (self, request):
       
    26         """
       
    27             Lookup Request -> Handler, params -> Response
       
    28         """
       
    29         
       
    30         # bind to request
       
    31         urls = self.urls.bind_to_environ(request)
       
    32         
       
    33         # lookup
       
    34         handler, params = urls.match()
       
    35 
       
    36         # handler instance
       
    37         handler = handler(self, request, urls)
       
    38 
       
    39         try :
       
    40             handler.init()
       
    41 
       
    42             # apply
       
    43             return handler.respond(**params)
       
    44 
       
    45         finally :
       
    46             handler.cleanup()
       
    47 
       
    48     @Request.application
       
    49     def __call__ (self, request) :
       
    50         """
       
    51             WSGI entry point, werkzeug Request -> Response
       
    52         """
       
    53 
       
    54         try :
       
    55             return self.respond(request)
       
    56         
       
    57         except HTTPException as ex :
       
    58             return ex
       
    59 
       
    60 class Handler (object) :
       
    61     """
       
    62         Per-Request controller/view, containing the request context and generating the response.
       
    63     """
       
    64     
       
    65     # werkzeug defaults to UTF-8
       
    66     MIMETYPE = 'text/html'
       
    67 
       
    68     def __init__ (self, app, request, urls) :
       
    69         """
       
    70             app     - wsgi.Application
       
    71             request - werkzeug.Request
       
    72             urls    - werkzeug.routing.Map.bind_to_environ()
       
    73         """
       
    74 
       
    75         self.app = app
       
    76         self.request = request
       
    77         self.urls = urls
       
    78 
       
    79     def url (self, handler=None, **params) :
       
    80         """
       
    81             Return an URL for given endpoint, with parameters,
       
    82         """
       
    83 
       
    84         if not handler :
       
    85             handler = self.__class__
       
    86 
       
    87         return self.urls.build(handler, params)
       
    88 
       
    89     ## processing stages
       
    90     def init (self) :
       
    91         """
       
    92             Initialize on request start.
       
    93         """
       
    94 
       
    95         pass
       
    96 
       
    97     def process (self, **params) :
       
    98         """
       
    99             Process request args to build internal request state.
       
   100 
       
   101             May optionally return a Response, to e.g. redirect after POST.
       
   102         """
       
   103 
       
   104         pass
       
   105 
       
   106     def render (self) :
       
   107         """
       
   108             Render response.
       
   109         """
       
   110 
       
   111         raise NotImplementedError()
       
   112 
       
   113     def mimetype (self):
       
   114         return self.MIMETYPE
       
   115 
       
   116     def status (self):
       
   117         return 200
       
   118 
       
   119     def respond (self, **params) :
       
   120         """
       
   121             Generate a response, or raise an HTTPException
       
   122         """
       
   123         
       
   124         # returning e.g. redirect?
       
   125         response = self.process(**params)
       
   126 
       
   127         if response :
       
   128             return response
       
   129         
       
   130         return Response(self.render_response(), mimetype=self.mimetype(), status=self.status())
       
   131     
       
   132     def cleanup (self) :
       
   133         """
       
   134             After request processing. Do not fail :)
       
   135         """
       
   136         
       
   137         pass
       
   138