From dcee710154e102e50fe89df1bdd2701726d3f1d2 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 5 Mar 2019 14:03:34 +0100 Subject: [PATCH] patch gen.maybe_future for compatibility with tornado 6 tornado gen.maybe_future is deprecated in >= 5.0 and doesn't accept asyncio coroutine objects or awaitables in general causing failures with tornado 6 on asyncio monkeypatch gen.maybe_future for easier backport to 5.x later, we can update to use our maybe_future throughout --- notebook/utils.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/notebook/utils.py b/notebook/utils.py index 5b3d9dff9..b1ae3b650 100644 --- a/notebook/utils.py +++ b/notebook/utils.py @@ -12,6 +12,20 @@ import stat import sys from distutils.version import LooseVersion +try: + from inspect import isawaitable +except ImportError: + def isawaitable(f): + """If isawaitable is undefined, nothing is awaitable""" + return False + +try: + from concurrent.futures import Future as ConcurrentFuture +except ImportError: + class ConcurrentFuture: + """If concurrent.futures isn't importable, nothing will be a c.f.Future""" + pass + try: from urllib.parse import quote, unquote, urlparse, urljoin from urllib.request import pathname2url @@ -19,6 +33,10 @@ except ImportError: from urllib import quote, unquote, pathname2url from urlparse import urlparse, urljoin +# tornado.concurrent.Future is asyncio.Future +# in tornado >=5 with Python 3 +from tornado.concurrent import Future as TornadoFuture +from tornado import gen from ipython_genutils import py3compat # UF_HIDDEN is a stat flag not defined in the stat module. @@ -306,3 +324,34 @@ if sys.platform == 'win32': check_pid = _check_pid_win32 else: check_pid = _check_pid_posix + + +def maybe_future(obj): + """Like tornado's gen.maybe_future + + but more compatible with asyncio for recent versions + of tornado + """ + if isinstance(obj, TornadoFuture): + return obj + elif isawaitable(obj): + return asyncio.ensure_future(obj) + elif isinstance(obj, ConcurrentFuture): + return asyncio.wrap_future(obj) + else: + # not awaitable, wrap scalar in future + f = TornadoFuture() + f.set_result(obj) + return f + +# monkeypatch tornado gen.maybe_future +# on Python 3 +# TODO: remove monkeypatch after backporting smaller fix to 5.x +try: + import asyncio +except ImportError: + pass +else: + import tornado.gen + tornado.gen.maybe_future = maybe_future +