call it our own maybe_future

our version of gen.maybe_future that's fully tornado- and asyncio-compatible
This commit is contained in:
Min RK
2018-03-12 14:37:44 +01:00
parent 58d602e549
commit dad26be2c6
8 changed files with 34 additions and 33 deletions

View File

@@ -8,7 +8,7 @@ import json
from tornado import gen, web
from .. import orm
from ..utils import admin_only, awaitable
from ..utils import admin_only, maybe_future
from .base import APIHandler
@@ -76,7 +76,7 @@ class UserListAPIHandler(APIHandler):
user.admin = True
self.db.commit()
try:
await awaitable(self.authenticator.add_user(user))
await maybe_future(self.authenticator.add_user(user))
except Exception as e:
self.log.error("Failed to create user: %s" % name, exc_info=True)
self.users.delete(user)
@@ -125,7 +125,7 @@ class UserAPIHandler(APIHandler):
self.db.commit()
try:
await awaitable(self.authenticator.add_user(user))
await maybe_future(self.authenticator.add_user(user))
except Exception:
self.log.error("Failed to create user: %s" % name, exc_info=True)
# remove from registry
@@ -149,7 +149,7 @@ class UserAPIHandler(APIHandler):
if user.spawner._stop_pending:
raise web.HTTPError(400, "%s's server is in the process of stopping, please wait." % name)
await awaitable(self.authenticator.delete_user(user))
await maybe_future(self.authenticator.delete_user(user))
# remove from registry
self.users.delete(user)

View File

@@ -57,7 +57,7 @@ from .log import CoroutineLogFormatter, log_request
from .proxy import Proxy, ConfigurableHTTPProxy
from .traitlets import URLPrefix, Command
from .utils import (
awaitable,
maybe_future,
url_path_join,
ISO8601_ms, ISO8601_s,
print_stacks, print_ps_info,
@@ -1052,7 +1052,7 @@ class JupyterHub(Application):
# and persist across sessions.
for user in db.query(orm.User):
try:
await awaitable(self.authenticator.add_user(user))
await maybe_future(self.authenticator.add_user(user))
except Exception:
self.log.exception("Error adding user %s already in db", user.name)
if self.authenticator.delete_invalid_users:
@@ -1083,7 +1083,7 @@ class JupyterHub(Application):
db.add(group)
for username in usernames:
username = self.authenticator.normalize_username(username)
if not (await awaitable(self.authenticator.check_whitelist(username))):
if not (await maybe_future(self.authenticator.check_whitelist(username))):
raise ValueError("Username %r is not in whitelist" % username)
user = orm.User.find(db, name=username)
if user is None:
@@ -1107,7 +1107,7 @@ class JupyterHub(Application):
for token, name in token_dict.items():
if kind == 'user':
name = self.authenticator.normalize_username(name)
if not (await awaitable(self.authenticator.check_whitelist(name))):
if not (await maybe_future(self.authenticator.check_whitelist(name))):
raise ValueError("Token name %r is not in whitelist" % name)
if not self.authenticator.validate_username(name):
raise ValueError("Token name %r is not valid" % name)
@@ -1497,7 +1497,7 @@ class JupyterHub(Application):
# clean up proxy while single-user servers are shutting down
if self.cleanup_proxy:
if self.proxy.should_start:
await awaitable(self.proxy.stop())
await maybe_future(self.proxy.stop())
else:
self.log.info("I didn't start the proxy, I can't clean it up")
else:

View File

@@ -23,7 +23,7 @@ from traitlets.config import LoggingConfigurable
from traitlets import Bool, Set, Unicode, Dict, Any, default, observe
from .handlers.login import LoginHandler
from .utils import awaitable, url_path_join
from .utils import maybe_future, url_path_join
from .traitlets import Command
@@ -244,7 +244,7 @@ class Authenticator(LoggingConfigurable):
self.log.warning("Disallowing invalid username %r.", username)
return
whitelist_pass = await awaitable(self.check_whitelist(username))
whitelist_pass = await maybe_future(self.check_whitelist(username))
if whitelist_pass:
return authenticated
else:
@@ -481,14 +481,14 @@ class LocalAuthenticator(Authenticator):
If self.create_system_users, the user will attempt to be created if it doesn't exist.
"""
user_exists = await awaitable(self.system_user_exists(user))
user_exists = await maybe_future(self.system_user_exists(user))
if not user_exists:
if self.create_system_users:
await awaitable(self.add_system_user(user))
await maybe_future(self.add_system_user(user))
else:
raise KeyError("User %s does not exist." % user.name)
await awaitable(super().add_user(user))
await maybe_future(super().add_user(user))
@staticmethod
def system_user_exists(user):

View File

@@ -19,7 +19,7 @@ except ImportError:
class InvalidToken(Exception):
pass
from .utils import awaitable
from .utils import maybe_future
KEY_ENV = 'JUPYTERHUB_CRYPT_KEY'
@@ -133,7 +133,7 @@ class CryptKeeper(SingletonConfigurable):
def encrypt(self, data):
"""Encrypt an object with cryptography"""
self.check_available()
return awaitable(self.executor.submit(self._encrypt, data))
return maybe_future(self.executor.submit(self._encrypt, data))
def _decrypt(self, encrypted):
decrypted = self.fernet.decrypt(encrypted)
@@ -142,7 +142,7 @@ class CryptKeeper(SingletonConfigurable):
def decrypt(self, encrypted):
"""Decrypt an object with cryptography"""
self.check_available()
return awaitable(self.executor.submit(self._decrypt, encrypted))
return maybe_future(self.executor.submit(self._decrypt, encrypted))
def encrypt(data):

View File

@@ -23,7 +23,7 @@ from .. import __version__
from .. import orm
from ..objects import Server
from ..spawner import LocalProcessSpawner
from ..utils import awaitable, url_path_join
from ..utils import maybe_future, url_path_join
from ..metrics import (
SERVER_SPAWN_DURATION_SECONDS, ServerSpawnStatus,
PROXY_ADD_DURATION_SECONDS, ProxyAddStatus
@@ -387,7 +387,7 @@ class BaseHandler(RequestHandler):
self.set_hub_cookie(user)
def authenticate(self, data):
return awaitable(self.authenticator.get_authenticated_user(self, data))
return maybe_future(self.authenticator.get_authenticated_user(self, data))
def get_next_url(self, user=None):
"""Get the next_url for login redirect
@@ -421,7 +421,7 @@ class BaseHandler(RequestHandler):
new_user = username not in self.users
user = self.user_from_username(username)
if new_user:
await awaitable(self.authenticator.add_user(user))
await maybe_future(self.authenticator.add_user(user))
# Only set `admin` if the authenticator returned an explicit value.
if admin is not None and admin != user.admin:
user.admin = admin
@@ -577,7 +577,7 @@ class BaseHandler(RequestHandler):
# hook up spawner._spawn_future so that other requests can await
# this result
finish_spawn_future = spawner._spawn_future = awaitable(finish_user_spawn())
finish_spawn_future = spawner._spawn_future = maybe_future(finish_user_spawn())
def _clear_spawn_future(f):
# clear spawner._spawn_future when it's done
# keep an exception around, though, to prevent repeated implicit spawns

View File

@@ -28,7 +28,7 @@ from traitlets import (
from .objects import Server
from .traitlets import Command, ByteSpecification, Callable
from .utils import awaitable, random_port, url_path_join, exponential_backoff
from .utils import maybe_future, random_port, url_path_join, exponential_backoff
class Spawner(LoggingConfigurable):
@@ -269,7 +269,7 @@ class Spawner(LoggingConfigurable):
Introduced.
"""
if callable(self.options_form):
options_form = await awaitable(self.options_form(self))
options_form = await maybe_future(self.options_form(self))
else:
options_form = self.options_form
@@ -783,7 +783,7 @@ class Spawner(LoggingConfigurable):
for callback in callbacks:
try:
await awaitable(callback())
await maybe_future(callback())
except Exception:
self.log.exception("Unhandled error in poll callback for %s", self)
return status

View File

@@ -12,7 +12,7 @@ from tornado import gen
from tornado.log import app_log
from traitlets import HasTraits, Any, Dict, default
from .utils import awaitable, url_path_join
from .utils import maybe_future, url_path_join
from . import orm
from ._version import _check_version, __version__
@@ -378,14 +378,14 @@ class User:
# trigger pre-spawn hook on authenticator
authenticator = self.authenticator
if (authenticator):
await awaitable(authenticator.pre_spawn_start(self, spawner))
await maybe_future(authenticator.pre_spawn_start(self, spawner))
spawner._start_pending = True
# wait for spawner.start to return
try:
# run optional preparation work to bootstrap the notebook
await awaitable(spawner.run_pre_spawn_hook())
f = awaitable(spawner.start())
await maybe_future(spawner.run_pre_spawn_hook())
f = maybe_future(spawner.start())
# commit any changes in spawner.start (always commit db changes before yield)
db.commit()
ip_port = await gen.with_timeout(timedelta(seconds=spawner.start_timeout), f)
@@ -533,7 +533,7 @@ class User:
auth = spawner.authenticator
try:
if auth:
await awaitable(
await maybe_future(
auth.post_spawn_stop(self, spawner)
)
except Exception:

View File

@@ -123,7 +123,7 @@ async def exponential_backoff(
deadline = random.uniform(deadline - tol, deadline + tol)
scale = 1
while True:
ret = await awaitable(pass_func(*args, **kwargs))
ret = await maybe_future(pass_func(*args, **kwargs))
# Truthy!
if ret:
return ret
@@ -414,16 +414,17 @@ def print_stacks(file=sys.stderr):
task.print_stack(file=file)
def awaitable(obj):
"""Wrap an object in something that's awaitable
def maybe_future(obj):
"""Return an asyncio Future
Use instead of gen.maybe_future
For our compatibility, this must accept:
- asyncio coroutine (gen.maybe_future doesn't work)
- asyncio coroutine (gen.maybe_future doesn't work in tornado < 5)
- tornado coroutine (asyncio.ensure_future doesn't work)
- scalar (asyncio.ensure_future doesn't work)
- concurrent.futures.Future (asyncio.ensure_future doesn't work)
- tornado Future (works both ways)
- asyncio Future (works both ways)
"""