Proof-of-concept integration with PEP 492 async/await. · bdarnell/tornado@e3b71c3 (original) (raw)
4 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
1 | +from tornado.ioloop import IOLoop | |
2 | +from tornado.httpclient import AsyncHTTPClient | |
3 | +from tornado.options import parse_command_line, define, options | |
4 | +from tornado.web import RequestHandler, Application | |
5 | + | |
6 | +define('port', default=8080) | |
7 | + | |
8 | +class FooHandler(RequestHandler): | |
9 | +def get(self): | |
10 | +self.write('hello') | |
11 | + | |
12 | +class BarHandler(RequestHandler): | |
13 | +async def get(self): | |
14 | +resp = await AsyncHTTPClient().fetch('http://localhost:%d/foo' % | |
15 | +options.port) | |
16 | +self.write('read %d bytes' % len(resp.body)) | |
17 | + | |
18 | +if __name__ == '__main__': | |
19 | +parse_command_line() | |
20 | +app = Application([('/foo', FooHandler), | |
21 | + ('/bar', BarHandler)], debug=True) | |
22 | +app.listen(options.port) | |
23 | +IOLoop.current().start() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -310,6 +310,9 @@ def __del__(self): | ||
310 | 310 | app_log.error('Future %r exception was never retrieved: %s', |
311 | 311 | self, ''.join(tb).rstrip()) |
312 | 312 | |
313 | +def __await__(self): | |
314 | +return (yield self) | |
315 | + | |
313 | 316 | TracebackFuture = Future |
314 | 317 | |
315 | 318 | if futures is None: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -202,6 +202,8 @@ def _make_coroutine_wrapper(func, replace_callback): | ||
202 | 202 | argument, so we cannot simply implement ``@engine`` in terms of |
203 | 203 | ``@coroutine``. |
204 | 204 | """ |
205 | +import types | |
206 | +func = types.coroutine(func) | |
205 | 207 | @functools.wraps(func) |
206 | 208 | def wrapper(*args, **kwargs): |
207 | 209 | future = TracebackFuture() |
@@ -1040,3 +1042,26 @@ def _(asyncio_future): | ||
1040 | 1042 | |
1041 | 1043 | if singledispatch is not None: |
1042 | 1044 | convert_yielded = singledispatch(convert_yielded) |
1045 | + | |
1046 | +import abc, types | |
1047 | +class _Awaitable(abc.ABC): | |
1048 | +@classmethod | |
1049 | +def __subclasshook__(cls, C): | |
1050 | +if cls is _Awaitable: | |
1051 | +if C is Future: | |
1052 | +# Futures are awaitable but we want to handle them natively | |
1053 | +# instead of going through this wrapper. | |
1054 | +return False | |
1055 | +if any("__await__" in B.__dict__ for B in C.__mro__): | |
1056 | +return True | |
1057 | +return NotImplemented | |
1058 | +# TODO: this claims all generators; we really only want it to apply when | |
1059 | +# inspect.iscoroutine is true but that uses a flag on the instance. | |
1060 | +_Awaitable.register(types.GeneratorType) | |
1061 | + | |
1062 | +@convert_yielded.register(_Awaitable) | |
1063 | +def _(c): | |
1064 | +@coroutine | |
1065 | +def wrapped(): | |
1066 | +return (yield from c) | |
1067 | +return wrapped() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1388,10 +1388,8 @@ def _execute(self, transforms, *args, **kwargs): | ||
1388 | 1388 | self.check_xsrf_cookie() |
1389 | 1389 | |
1390 | 1390 | result = self.prepare() |
1391 | -if is_future(result): | |
1392 | -result = yield result | |
1393 | 1391 | if result is not None: |
1394 | -raise TypeError("Expected None, got %r" % result) | |
1392 | +result = yield result | |
1395 | 1393 | if self._prepared_future is not None: |
1396 | 1394 | # Tell the Application we've finished with prepare() |
1397 | 1395 | # and are ready for the body to arrive. |
@@ -1411,10 +1409,8 @@ def _execute(self, transforms, *args, **kwargs): | ||
1411 | 1409 | |
1412 | 1410 | method = getattr(self, self.request.method.lower()) |
1413 | 1411 | result = method(*self.path_args, **self.path_kwargs) |
1414 | -if is_future(result): | |
1415 | -result = yield result | |
1416 | 1412 | if result is not None: |
1417 | -raise TypeError("Expected None, got %r" % result) | |
1413 | +result = yield result | |
1418 | 1414 | if self._auto_finish and not self._finished: |
1419 | 1415 | self.finish() |
1420 | 1416 | except Exception as e: |