Ignore changes in the amount of whitespace
Differences between version dated 2011-01-08 15:53:16 and 2011-01-10 09:58:13
(spanning 3 versions)
Deletions are marked like this.
Additions are marked like this.
#!python
"""Some sketches of implementing a WSGI 2 async API, in both sync and async servers"""
def example_app(environ):
yield '200 OK', [('Content-type','text/plain')], [b'hello world!']
def example_middleware(app):
def wrapped(environ):
# middleware can modify environ here
status, headers, body = yield app(environ)
# and modify or replace s, h, body here
body = process(body) # ...only if you need to alter it
yield status, headers, body
def process(body_iter):
# This function is only needed if the middleware wants to read
# or modify the body in some way...
while True:
chunk = yield body_iter # fetch the next chunk from the body
if chunk is None:
break
# process/modify chunk here, then yield it to the server
yield chunk
return wrapped
def WSGI2(app):
"""Decorator that synchronously emulates WSGI2 futures under WSGI 1"""
def wsgi1_app(environ, start_response):
def process_response(shb):
s, h, body = shb
write = start_response(s, h)
return routine.RETURN(yielded)
else:
return base_trampoline(routine, yielded)
Coroutine(b, body_trampoline)
if not [body has send/throw methods]:
body = (item for item in body)
Coroutine(body, body_trampoline)()
def app_trampoline(routine, yielded):
if type(yielded) is tuple:
raise TypeError("Not a future, result, or generator:", yielded)
# [add an executor to environ here]
Coroutine(app(environ), app_trampoline, process_response)
Coroutine(app(environ), app_trampoline, process_response)()
return []
return wsgi1_app
def process_response(shb):
s, h, body = shb
[do an asynchronous start_response analog here]
def body_trampoline(routine, yielded):
if type(yielded) is bytes:
# only accept from outermost middleware
else:
return base_trampoline(routine, yielded)
Coroutine(body, body_trampoline, [optional termination callback])
if not [body has send/throw methods]:
body = (item for item in body)
Coroutine(body, body_trampoline, [optional termination callback])()
def app_trampoline(routine, yielded):
if type(yielded) is tuple:
return routine.RETURN(yielded)
raise TypeError("Not a future, result, or generator:", yielded)
# [add an executor to environ here]
Coroutine(app(environ), app_trampoline, process_response)
Coroutine(app(environ), app_trampoline, process_response)()
class Coroutine:
self.stack = [iterator]
self.trampoline = trampoline
self.callback = callback
self()
PAUSE = ()
return self.RESUME(func(*args, **kw))
except BaseException:
return self.RAISE(sys.exc_info())
def close():
while self.stack:
self.stack.pop().close()
def __call__(self, value=None, exc_info=()):
stack = self.stack
return rv
# Coroutine is entirely finished when the stack is empty
if exc_info:
try:
raise exc_info[1]
finally:
exc_info = ()
return self.callback(value)
}}}