diff --git a/dev-requirements.txt b/dev-requirements.txt index d61f287d..8fcffe9f 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -16,8 +16,7 @@ mock nbclassic<0.4 pre-commit pytest>=3.3 -pytest-asyncio; python_version < "3.7" -pytest-asyncio>=0.17; python_version >= "3.7" +pytest-asyncio>=0.17 pytest-cov requests-mock tbump diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 0d672533..4fad7447 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -23,15 +23,6 @@ from urllib.parse import unquote, urlparse, urlunparse if sys.version_info[:2] < (3, 3): raise ValueError("Python < 3.3 not supported: %s" % sys.version) -# For compatibility with python versions 3.6 or earlier. -# asyncio.Task.all_tasks() is fully moved to asyncio.all_tasks() starting with 3.9. Also applies to current_task. -try: - asyncio_all_tasks = asyncio.all_tasks - asyncio_current_task = asyncio.current_task -except AttributeError as e: - asyncio_all_tasks = asyncio.Task.all_tasks - asyncio_current_task = asyncio.Task.current_task - import tornado.httpserver import tornado.options from dateutil.parser import parse as parse_date @@ -3248,7 +3239,7 @@ class JupyterHub(Application): await self.cleanup() - tasks = [t for t in asyncio_all_tasks() if t is not asyncio_current_task()] + tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()] if tasks: self.log.debug("Cancelling pending tasks") @@ -3261,7 +3252,7 @@ class JupyterHub(Application): except StopAsyncIteration as e: self.log.error("Caught StopAsyncIteration Exception", exc_info=True) - tasks = [t for t in asyncio_all_tasks()] + tasks = [t for t in asyncio.all_tasks()] for t in tasks: self.log.debug("Task status: %s", t) asyncio.get_event_loop().stop() diff --git a/jupyterhub/tests/conftest.py b/jupyterhub/tests/conftest.py index 801616da..c74621b7 100644 --- a/jupyterhub/tests/conftest.py +++ b/jupyterhub/tests/conftest.py @@ -54,28 +54,6 @@ from .utils import add_user _db = None -def _pytest_collection_modifyitems(items): - """This function is automatically run by pytest passing all collected test - functions. - - We use it to add asyncio marker to all async tests and assert we don't use - test functions that are async generators which wouldn't make sense. - - It is no longer required with pytest-asyncio >= 0.17 - """ - for item in items: - if inspect.iscoroutinefunction(item.obj): - item.add_marker('asyncio') - assert not inspect.isasyncgenfunction(item.obj) - - -if sys.version_info < (3, 7): - # apply pytest-asyncio's 'auto' mode on Python 3.6. - # 'auto' mode is new in pytest-asyncio 0.17, - # which requires Python 3.7. - pytest_collection_modifyitems = _pytest_collection_modifyitems - - @fixture(scope='module') def ssl_tmpdir(tmpdir_factory): return tmpdir_factory.mktemp('ssl') diff --git a/jupyterhub/tests/test_singleuser.py b/jupyterhub/tests/test_singleuser.py index 1a870d59..8603f5c8 100644 --- a/jupyterhub/tests/test_singleuser.py +++ b/jupyterhub/tests/test_singleuser.py @@ -1,7 +1,7 @@ """Tests for jupyterhub.singleuser""" import os import sys -from contextlib import contextmanager +from contextlib import contextmanager, nullcontext from subprocess import CalledProcessError, check_output from unittest import mock from urllib.parse import urlencode, urlparse @@ -17,12 +17,6 @@ from .mocking import StubSingleUserSpawner, public_url from .utils import AsyncSession, async_requests, get_page -@contextmanager -def nullcontext(): - """Python 3.7+ contextlib.nullcontext, backport for 3.6""" - yield - - @pytest.mark.parametrize( "access_scopes, server_name, expect_success", [ diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index 8855e7ea..b64ff7b7 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -27,14 +27,26 @@ from tornado import gen, ioloop, web from tornado.httpclient import AsyncHTTPClient, HTTPError from tornado.log import app_log -# For compatibility with python versions 3.6 or earlier. -# asyncio.Task.all_tasks() is fully moved to asyncio.all_tasks() starting with 3.9. Also applies to current_task. -try: - asyncio_all_tasks = asyncio.all_tasks - asyncio_current_task = asyncio.current_task -except AttributeError as e: - asyncio_all_tasks = asyncio.Task.all_tasks - asyncio_current_task = asyncio.Task.current_task + +# Deprecated aliases: no longer needed now that we require 3.7 +def asyncio_all_tasks(loop=None): + warnings.warn( + "jupyterhub.utils.asyncio_all_tasks is deprecated in JupyterHub 2.4." + " Use asyncio.all_tasks().", + DeprecationWarning, + stacklevel=2, + ) + return asyncio.all_tasks(loop=loop) + + +def asyncio_current_task(loop=None): + warnings.warn( + "jupyterhub.utils.asyncio_current_task is deprecated in JupyterHub 2.4." + " Use asyncio.current_task().", + DeprecationWarning, + stacklevel=2, + ) + return asyncio.current_task(loop=loop) def random_port():