mirror of
https://github.com/sprockets/sprockets.http.git
synced 2024-11-14 19:29:28 +00:00
Merge pull request #37 from dave-shawley/py39
asyncio.Task.all_tasks was removed in Python 3.9
This commit is contained in:
commit
bc19924904
6 changed files with 74 additions and 33 deletions
|
@ -1,9 +1,11 @@
|
||||||
language: python
|
language: python
|
||||||
|
os: linux
|
||||||
dist: xenial
|
dist: xenial
|
||||||
python:
|
python:
|
||||||
- 3.5
|
- 3.5
|
||||||
- 3.6
|
- 3.6
|
||||||
- 3.7
|
- 3.7
|
||||||
|
- 3.8
|
||||||
install:
|
install:
|
||||||
- pip install -r requires/development.txt codecov
|
- pip install -r requires/development.txt codecov
|
||||||
script:
|
script:
|
||||||
|
@ -12,11 +14,10 @@ script:
|
||||||
- flake8
|
- flake8
|
||||||
after_success:
|
after_success:
|
||||||
- codecov
|
- codecov
|
||||||
sudo: false
|
|
||||||
deploy:
|
deploy:
|
||||||
distributions: sdist bdist_wheel
|
distributions: sdist bdist_wheel
|
||||||
provider: pypi
|
provider: pypi
|
||||||
user: sprockets
|
username: sprockets
|
||||||
password:
|
password:
|
||||||
secure: ARvFw5CHqQZqPOkJXxQSe7EAEbX1yt7FiBTtzz8Gd6XndbY10HVCSWhGYeldm9LevvQc9p77pBEvsl+bXGQbJ3NW/r/U5PADaFdmi4bxmXN8yc+dFKzn72MpZfL+kCV2T/HutuOY6dQa4okTkKVV+sqwPLKPhL69zH/PxQg8qe4=
|
secure: ARvFw5CHqQZqPOkJXxQSe7EAEbX1yt7FiBTtzz8Gd6XndbY10HVCSWhGYeldm9LevvQc9p77pBEvsl+bXGQbJ3NW/r/U5PADaFdmi4bxmXN8yc+dFKzn72MpZfL+kCV2T/HutuOY6dQa4okTkKVV+sqwPLKPhL69zH/PxQg8qe4=
|
||||||
on:
|
on:
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
Release History
|
Release History
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
`Next release`_
|
||||||
|
---------------
|
||||||
|
- Updated to support Python 3.9. ``asyncio.Task.all_tasks`` was removed
|
||||||
|
so I switched to ``asyncio.all_tasks`` if it exists.
|
||||||
|
- Deprecate calling ``sprockets.http.run`` with anything that isn't a
|
||||||
|
``sprockets.app.Application`` instance.
|
||||||
|
|
||||||
`2.1.1`_ (19 Feb 2020)
|
`2.1.1`_ (19 Feb 2020)
|
||||||
----------------------
|
----------------------
|
||||||
- :meth:`sprockets.http.app.CallbackManager.stop` no longer requires the
|
- :meth:`sprockets.http.app.CallbackManager.stop` no longer requires the
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -46,6 +46,7 @@ setuptools.setup(
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Programming Language :: Python :: 3.7',
|
'Programming Language :: Python :: 3.7',
|
||||||
'Programming Language :: Python :: 3.8',
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: 3.9',
|
||||||
'Programming Language :: Python :: Implementation :: CPython',
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
'Topic :: Internet :: WWW/HTTP',
|
'Topic :: Internet :: WWW/HTTP',
|
||||||
'Topic :: Software Development :: Libraries',
|
'Topic :: Software Development :: Libraries',
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
import warnings
|
||||||
|
|
||||||
from tornado import concurrent, web
|
from tornado import concurrent, web
|
||||||
|
|
||||||
|
@ -41,13 +42,19 @@ class _ShutdownHandler:
|
||||||
self._maybe_stop()
|
self._maybe_stop()
|
||||||
|
|
||||||
def _maybe_stop(self):
|
def _maybe_stop(self):
|
||||||
|
all_tasks = self._all_tasks()
|
||||||
now = self.io_loop.time()
|
now = self.io_loop.time()
|
||||||
if now < self.__deadline and asyncio.Task.all_tasks():
|
if now < self.__deadline and all_tasks:
|
||||||
self.io_loop.add_timeout(now + self.wait_timeout, self._maybe_stop)
|
self.io_loop.add_timeout(now + self.wait_timeout, self._maybe_stop)
|
||||||
else:
|
else:
|
||||||
self.io_loop.stop()
|
self.io_loop.stop()
|
||||||
self.logger.info('stopped IOLoop')
|
self.logger.info('stopped IOLoop')
|
||||||
|
|
||||||
|
def _all_tasks(self):
|
||||||
|
if hasattr(asyncio, 'all_tasks'):
|
||||||
|
return asyncio.all_tasks(self.io_loop.asyncio_loop)
|
||||||
|
return asyncio.Task.all_tasks(self.io_loop.asyncio_loop)
|
||||||
|
|
||||||
|
|
||||||
class CallbackManager:
|
class CallbackManager:
|
||||||
"""
|
"""
|
||||||
|
@ -254,6 +261,11 @@ def wrap_application(application, before_run, on_start, shutdown):
|
||||||
shutdown = [] if shutdown is None else shutdown
|
shutdown = [] if shutdown is None else shutdown
|
||||||
|
|
||||||
if not isinstance(application, Application):
|
if not isinstance(application, Application):
|
||||||
|
warnings.warn(
|
||||||
|
'sprockets.http.run is only going to accept '
|
||||||
|
'sprockets.app.Application instances in 3.0, '
|
||||||
|
'was called with {}'.format(type(application).__name__),
|
||||||
|
category=DeprecationWarning)
|
||||||
application = _ApplicationAdapter(application)
|
application = _ApplicationAdapter(application)
|
||||||
|
|
||||||
application.before_run_callbacks.extend(before_run)
|
application.before_run_callbacks.extend(before_run)
|
||||||
|
|
70
tests.py
70
tests.py
|
@ -1,5 +1,4 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import asyncio
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import distutils.dist
|
import distutils.dist
|
||||||
import distutils.errors
|
import distutils.errors
|
||||||
|
@ -470,6 +469,21 @@ class RunnerTests(MockHelper, unittest.TestCase):
|
||||||
self.io_loop.stop.assert_called_once_with()
|
self.io_loop.stop.assert_called_once_with()
|
||||||
self.assertNotEqual(self.io_loop._timeouts, [])
|
self.assertNotEqual(self.io_loop._timeouts, [])
|
||||||
|
|
||||||
|
def test_that_calling_with_non_sprockets_application_is_deprecated(self):
|
||||||
|
with warnings.catch_warnings(record=True) as captured:
|
||||||
|
warnings.filterwarnings(action='always', module='sprockets')
|
||||||
|
sprockets.http.runner.Runner(web.Application())
|
||||||
|
for warning in captured:
|
||||||
|
if 'sprockets.app.Application' in str(warning.message):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.fail('expected deprecation warning from runnr.Runner')
|
||||||
|
|
||||||
|
with warnings.catch_warnings(record=True) as captured:
|
||||||
|
warnings.filterwarnings(action='always', module='sprockets')
|
||||||
|
sprockets.http.runner.Runner(sprockets.http.app.Application())
|
||||||
|
self.assertEqual(len(captured), 0)
|
||||||
|
|
||||||
|
|
||||||
class AsyncRunTests(unittest.TestCase):
|
class AsyncRunTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -724,49 +738,55 @@ class ShutdownHandlerTests(unittest.TestCase):
|
||||||
self.assertIn('Injected Failure', cm.output[0])
|
self.assertIn('Injected Failure', cm.output[0])
|
||||||
|
|
||||||
def test_that_maybe_stop_retries_until_tasks_are_complete(self):
|
def test_that_maybe_stop_retries_until_tasks_are_complete(self):
|
||||||
async def f():
|
|
||||||
pass
|
|
||||||
|
|
||||||
fake_loop = unittest.mock.Mock()
|
fake_loop = unittest.mock.Mock()
|
||||||
fake_loop.time.return_value = 10
|
fake_loop.time.return_value = 10
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
wait_timeout = 1.0
|
||||||
tasks = [loop.create_task(f()) for _ in range(5)]
|
handler = sprockets.http.app._ShutdownHandler(
|
||||||
|
fake_loop, 5.0, wait_timeout)
|
||||||
|
|
||||||
handler = sprockets.http.app._ShutdownHandler(fake_loop, 5.0, 0.0)
|
handler._all_tasks = unittest.mock.Mock()
|
||||||
handler.on_shutdown_ready() # sets __deadline to 15
|
handler._all_tasks.return_value = ['does-not-matter']
|
||||||
|
|
||||||
|
# on_shutdown_ready should schedule the callback since there
|
||||||
|
# are outstanding tasks
|
||||||
|
handler.on_shutdown_ready()
|
||||||
|
fake_loop.add_timeout.assert_called_once_with(
|
||||||
|
fake_loop.time.return_value + wait_timeout,
|
||||||
|
handler._maybe_stop)
|
||||||
fake_loop.add_timeout.reset_mock()
|
fake_loop.add_timeout.reset_mock()
|
||||||
|
|
||||||
while tasks:
|
# the callback should re-schedule since there are still
|
||||||
task = tasks.pop()
|
# outstanding tasks
|
||||||
handler._maybe_stop()
|
handler._maybe_stop()
|
||||||
fake_loop.add_timeout.assert_called_once_with(
|
fake_loop.add_timeout.assert_called_once_with(
|
||||||
unittest.mock.ANY, handler._maybe_stop)
|
fake_loop.time.return_value + wait_timeout,
|
||||||
|
handler._maybe_stop)
|
||||||
fake_loop.add_timeout.reset_mock()
|
fake_loop.add_timeout.reset_mock()
|
||||||
loop.run_until_complete(task)
|
|
||||||
del task
|
|
||||||
|
|
||||||
|
# when all of the tasks are finished, the loop is stopped
|
||||||
|
handler._all_tasks.return_value = []
|
||||||
handler._maybe_stop()
|
handler._maybe_stop()
|
||||||
fake_loop.stop.assert_called_once_with()
|
fake_loop.stop.assert_called_once_with()
|
||||||
|
|
||||||
def test_that_maybe_stop_terminates_when_deadline_reached(self):
|
def test_that_maybe_stop_terminates_when_deadline_reached(self):
|
||||||
fake_loop = unittest.mock.Mock()
|
fake_loop = unittest.mock.Mock()
|
||||||
fake_loop.time.return_value = 10
|
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
shutdown_limit = 10
|
||||||
loop.create_task(asyncio.sleep(10))
|
ticks = range(0, shutdown_limit)
|
||||||
|
handler = sprockets.http.app._ShutdownHandler(
|
||||||
|
fake_loop, shutdown_limit, 1.0)
|
||||||
|
|
||||||
handler = sprockets.http.app._ShutdownHandler(fake_loop, 5.0, 0.0)
|
handler._all_tasks = unittest.mock.Mock()
|
||||||
handler.on_shutdown_ready() # sets __deadline to 15
|
handler._all_tasks.return_value = ['does-not-matter']
|
||||||
fake_loop.add_timeout.reset_mock()
|
|
||||||
|
|
||||||
while fake_loop.time.return_value < 15:
|
fake_loop.time.return_value = 0.0
|
||||||
|
handler.on_shutdown_ready() # sets deadline to 0 + shutdown_limit
|
||||||
|
for time_value in ticks: # tick down
|
||||||
|
fake_loop.time.return_value = float(time_value)
|
||||||
handler._maybe_stop()
|
handler._maybe_stop()
|
||||||
fake_loop.add_timeout.assert_called_once_with(
|
fake_loop.stop.assert_not_called()
|
||||||
unittest.mock.ANY, handler._maybe_stop)
|
|
||||||
fake_loop.add_timeout.reset_mock()
|
|
||||||
fake_loop.time.return_value += 1
|
|
||||||
|
|
||||||
|
fake_loop.time.return_value = float(shutdown_limit)
|
||||||
handler._maybe_stop()
|
handler._maybe_stop()
|
||||||
fake_loop.stop.assert_called_once_with()
|
fake_loop.stop.assert_called_once_with()
|
||||||
self.assertEqual(len(asyncio.Task.all_tasks(loop)), 1)
|
|
||||||
|
|
4
tox.ini
4
tox.ini
|
@ -1,5 +1,5 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py35,py36,py37,tornado,tornado50
|
envlist = py35,py36,py37,py38,py39,tornado,tornado50
|
||||||
indexserver =
|
indexserver =
|
||||||
default = https://pypi.python.org/simple
|
default = https://pypi.python.org/simple
|
||||||
toxworkdir = build/tox
|
toxworkdir = build/tox
|
||||||
|
@ -20,5 +20,5 @@ commands =
|
||||||
|
|
||||||
[testenv:tornado50]
|
[testenv:tornado50]
|
||||||
commands =
|
commands =
|
||||||
{envbindir}/pip install tornado=5.0
|
{envbindir}/pip install tornado==5.0
|
||||||
{[testenv]commands}
|
{[testenv]commands}
|
||||||
|
|
Loading…
Reference in a new issue