Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Manlio Perillo

By: a guest on Mar 31st, 2010  |  syntax: Python  |  size: 3.16 KB  |  views: 196  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. """A WSGI middleware that run the application in a green thread.
  2.  
  3. THIS SOFTWARE IS UNDER MIT LICENSE.
  4. Copyright (c) 2010 Manlio Perillo (manlio.perillo@gmail.com)
  5. """
  6.  
  7. import sys
  8. from greenlet import getcurrent, greenlet
  9. from mako.template import Template
  10.  
  11.  
  12. class GState(tuple):
  13.     pass
  14.  
  15. GCONTINUE = 0
  16. GSUSPEND = 1
  17.  
  18.  
  19. class middleware(object):
  20.     """A middleware that use greenlet to provide non linear control flow.
  21.    """
  22.  
  23.     def __init__(self, application):
  24.         self.app = application
  25.  
  26.     def __call__(self, environ, start_response):
  27.         def _start_response(status, headers):
  28.             start_response(status, headers)
  29.             return self.write
  30.  
  31.         # Initialize greenlet and state
  32.         gp = greenlet(self.app)
  33.         self.in_app_iter = False
  34.  
  35.         r = gp.switch(environ, _start_response)
  36.         while isinstance(r, GState):
  37.             buf, status = r
  38.  
  39.             if status == GSUSPEND:
  40.                 # TODO: async WSGI extension
  41.                 # environ['wsgiorg.suspend']()
  42.                 # TODO: store environ as a per green thread state
  43.                 # gp.environ = environ
  44.                 pass
  45.  
  46.             yield buf
  47.  
  48.             r = gp.switch()
  49.  
  50.         # The application returned the app_iter object
  51.         self.in_app_iter = True
  52.         for buf in r:
  53.             yield buf
  54.  
  55.     def write(self, buf):
  56.         """WSGI "safe" write callable.
  57.        """
  58.  
  59.         gp = getcurrent()
  60.  
  61.         if self.in_app_iter:
  62.             exc = ValueError(
  63.                 'write callable called from application iterator')
  64.             gp.throw(exc)
  65.         else:
  66.             gp.parent.switch(GState((buf, GCONTINUE)))
  67.  
  68. def flush(ctx):
  69.     """A Mako function that flush the current buffer and return data
  70.    to the caller thread.
  71.    """
  72.  
  73.     gp = getcurrent()
  74.     body = ctx._buffer_stack[0].getvalue()
  75.     # TODO: get encoding to use from WSGI environ, stored in green
  76.     #       thread instance
  77.     buf = body.encode('us-ascii')
  78.  
  79.     # XXX assume FastEncodingBuffer is used
  80.     ctx._buffer_stack[0].data[:] = []
  81.  
  82.     gp.parent.switch(GState((buf, GCONTINUE)))
  83.     return ''
  84.  
  85.  
  86. @middleware
  87. def application(environ, start_response):
  88.     """A sample WSGI application that use Mako.
  89.    """
  90.  
  91.     headers = [('Content-Type', 'text/html')]
  92.     write = start_response('200 OK', headers)
  93.  
  94.     write('some data from write callable\n')
  95.  
  96.     buf = tmpl.render_unicode(body='Body')
  97.     return [buf]
  98.  
  99.  
  100.  
  101. tmpl = Template("""
  102. <%namespace name="greenlet" module="__main__" />
  103. <html>
  104.  <head>
  105.    <title>Mako example</title>
  106.  </head>
  107.  <body>
  108.    <div>Header</div>
  109.    ${greenlet.flush()}
  110.    ## TODO: async subrequest
  111.    <div>${body}</div>
  112.    ${greenlet.flush()}
  113.    <div>Footer</div>
  114.  </body>
  115. </html>
  116. """)
  117.  
  118.  
  119. if __name__ == '__main__':
  120.     def start_response(status, headers):
  121.         def write(buf):
  122.             raise NotImplementedError
  123.  
  124.         print 'status:', status
  125.         print 'headers', headers
  126.  
  127.         return write
  128.  
  129.     environ = {}
  130.     r = application(environ, start_response)
  131.     for i, buf in enumerate(r):
  132.         print 'chunk #%d' % i
  133.         sys.stdout.write(buf)