diff options
author | Yury Selivanov <yury@magic.io> | 2016-10-23 22:35:29 -0400 |
---|---|---|
committer | Yury Selivanov <yury@magic.io> | 2016-10-23 22:35:29 -0400 |
commit | b42e8d2c1f16448ca1c80a842239fc3da5857e0b (patch) | |
tree | 9fe9a94def377ab619fe195ecc3145703c782751 | |
parent | eb569e47754d8818f191a84db79ffc2cf1737fa7 (diff) | |
parent | 01c521ba7a06a5dc18c814faef740d01666c7af5 (diff) | |
download | cpython-git-b42e8d2c1f16448ca1c80a842239fc3da5857e0b.tar.gz |
Merge 3.6 (asyncio)
-rw-r--r-- | Lib/asyncio/futures.py | 9 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_futures.py | 156 |
2 files changed, 82 insertions, 83 deletions
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index e45d6aa387..b571130514 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -2,7 +2,7 @@ __all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError', - 'Future', 'wrap_future', + 'Future', 'wrap_future', 'isfuture' ] import concurrent.futures._base @@ -389,6 +389,10 @@ class Future: __await__ = __iter__ # make compatible with 'await' expression +# Needed for testing purposes. +_PyFuture = Future + + def _set_result_unless_cancelled(fut, result): """Helper setting the result only if the future was not cancelled.""" if fut.cancelled(): @@ -488,4 +492,5 @@ try: except ImportError: pass else: - Future = _asyncio.Future + # _CFuture is needed for tests. + Future = _CFuture = _asyncio.Future diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 6916b513e8..2c17ef2c27 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -9,6 +9,7 @@ from unittest import mock import asyncio from asyncio import test_utils +from asyncio import futures try: from test import support except ImportError: @@ -93,14 +94,17 @@ class DuckTests(test_utils.TestCase): assert g is f -class FutureTests(test_utils.TestCase): +class BaseFutureTests: + + def _new_future(self, loop=None): + raise NotImplementedError def setUp(self): self.loop = self.new_test_loop() self.addCleanup(self.loop.close) def test_initial_state(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertFalse(f.cancelled()) self.assertFalse(f.done()) f.cancel() @@ -108,15 +112,15 @@ class FutureTests(test_utils.TestCase): def test_init_constructor_default_loop(self): asyncio.set_event_loop(self.loop) - f = asyncio.Future() + f = self._new_future() self.assertIs(f._loop, self.loop) def test_constructor_positional(self): # Make sure Future doesn't accept a positional argument - self.assertRaises(TypeError, asyncio.Future, 42) + self.assertRaises(TypeError, self._new_future, 42) def test_cancel(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertTrue(f.cancel()) self.assertTrue(f.cancelled()) self.assertTrue(f.done()) @@ -127,7 +131,7 @@ class FutureTests(test_utils.TestCase): self.assertFalse(f.cancel()) def test_result(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.result) f.set_result(42) @@ -141,7 +145,7 @@ class FutureTests(test_utils.TestCase): def test_exception(self): exc = RuntimeError() - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) self.assertRaises(asyncio.InvalidStateError, f.exception) # StopIteration cannot be raised into a Future - CPython issue26221 @@ -158,12 +162,12 @@ class FutureTests(test_utils.TestCase): self.assertFalse(f.cancel()) def test_exception_class(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_exception(RuntimeError) self.assertIsInstance(f.exception(), RuntimeError) def test_yield_from_twice(self): - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) def fixture(): yield 'A' @@ -182,7 +186,7 @@ class FutureTests(test_utils.TestCase): def test_future_repr(self): self.loop.set_debug(True) - f_pending_debug = asyncio.Future(loop=self.loop) + f_pending_debug = self._new_future(loop=self.loop) frame = f_pending_debug._source_traceback[-1] self.assertEqual(repr(f_pending_debug), '<Future pending created at %s:%s>' @@ -190,21 +194,21 @@ class FutureTests(test_utils.TestCase): f_pending_debug.cancel() self.loop.set_debug(False) - f_pending = asyncio.Future(loop=self.loop) + f_pending = self._new_future(loop=self.loop) self.assertEqual(repr(f_pending), '<Future pending>') f_pending.cancel() - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() self.assertEqual(repr(f_cancelled), '<Future cancelled>') - f_result = asyncio.Future(loop=self.loop) + f_result = self._new_future(loop=self.loop) f_result.set_result(4) self.assertEqual(repr(f_result), '<Future finished result=4>') self.assertEqual(f_result.result(), 4) exc = RuntimeError() - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(exc) self.assertEqual(repr(f_exception), '<Future finished exception=RuntimeError()>') @@ -215,7 +219,7 @@ class FutureTests(test_utils.TestCase): text = '%s() at %s:%s' % (func.__qualname__, filename, lineno) return re.escape(text) - f_one_callbacks = asyncio.Future(loop=self.loop) + f_one_callbacks = self._new_future(loop=self.loop) f_one_callbacks.add_done_callback(_fakefunc) fake_repr = func_repr(_fakefunc) self.assertRegex(repr(f_one_callbacks), @@ -224,7 +228,7 @@ class FutureTests(test_utils.TestCase): self.assertEqual(repr(f_one_callbacks), '<Future cancelled>') - f_two_callbacks = asyncio.Future(loop=self.loop) + f_two_callbacks = self._new_future(loop=self.loop) f_two_callbacks.add_done_callback(first_cb) f_two_callbacks.add_done_callback(last_cb) first_repr = func_repr(first_cb) @@ -233,7 +237,7 @@ class FutureTests(test_utils.TestCase): r'<Future pending cb=\[%s, %s\]>' % (first_repr, last_repr)) - f_many_callbacks = asyncio.Future(loop=self.loop) + f_many_callbacks = self._new_future(loop=self.loop) f_many_callbacks.add_done_callback(first_cb) for i in range(8): f_many_callbacks.add_done_callback(_fakefunc) @@ -248,31 +252,31 @@ class FutureTests(test_utils.TestCase): def test_copy_state(self): from asyncio.futures import _copy_future_state - f = asyncio.Future(loop=self.loop) + f = self._new_future(loop=self.loop) f.set_result(10) - newf = asyncio.Future(loop=self.loop) + newf = self._new_future(loop=self.loop) _copy_future_state(f, newf) self.assertTrue(newf.done()) self.assertEqual(newf.result(), 10) - f_exception = asyncio.Future(loop=self.loop) + f_exception = self._new_future(loop=self.loop) f_exception.set_exception(RuntimeError()) - newf_exception = asyncio.Future(loop=self.loop) + newf_exception = self._new_future(loop=self.loop) _copy_future_state(f_exception, newf_exception) self.assertTrue(newf_exception.done()) self.assertRaises(RuntimeError, newf_exception.result) - f_cancelled = asyncio.Future(loop=self.loop) + f_cancelled = self._new_future(loop=self.loop) f_cancelled.cancel() - newf_cancelled = asyncio.Future(loop=self.loop) + newf_cancelled = self._new_future(loop=self.loop) _copy_future_state(f_cancelled, newf_cancelled) self.assertTrue(newf_cancelled.cancelled()) def test_iter(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) def coro(): yield from fut @@ -285,20 +289,20 @@ class FutureTests(test_utils.TestCase): @mock.patch('asyncio.base_events.logger') def test_tb_logger_abandoned(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) del fut self.assertFalse(m_log.error.called) @mock.patch('asyncio.base_events.logger') def test_tb_logger_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result(42) fut.result() del fut @@ -306,7 +310,7 @@ class FutureTests(test_utils.TestCase): @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_unretrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) del fut test_utils.run_briefly(self.loop) @@ -315,7 +319,7 @@ class FutureTests(test_utils.TestCase): @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) fut.exception() del fut @@ -323,7 +327,7 @@ class FutureTests(test_utils.TestCase): @mock.patch('asyncio.base_events.logger') def test_tb_logger_exception_result_retrieved(self, m_log): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_exception(RuntimeError('boom')) self.assertRaises(RuntimeError, fut.result) del fut @@ -337,12 +341,12 @@ class FutureTests(test_utils.TestCase): f1 = ex.submit(run, 'oi') f2 = asyncio.wrap_future(f1, loop=self.loop) res, ident = self.loop.run_until_complete(f2) - self.assertIsInstance(f2, asyncio.Future) + self.assertTrue(asyncio.isfuture(f2)) self.assertEqual(res, 'oi') self.assertNotEqual(ident, threading.get_ident()) def test_wrap_future_future(self): - f1 = asyncio.Future(loop=self.loop) + f1 = self._new_future(loop=self.loop) f2 = asyncio.wrap_future(f1) self.assertIs(f1, f2) @@ -377,10 +381,10 @@ class FutureTests(test_utils.TestCase): def test_future_source_traceback(self): self.loop.set_debug(True) - future = asyncio.Future(loop=self.loop) + future = self._new_future(loop=self.loop) lineno = sys._getframe().f_lineno - 1 self.assertIsInstance(future._source_traceback, list) - self.assertEqual(future._source_traceback[-1][:3], + self.assertEqual(future._source_traceback[-2][:3], (__file__, lineno, 'test_future_source_traceback')) @@ -396,57 +400,18 @@ class FutureTests(test_utils.TestCase): return exc exc = memory_error() - future = asyncio.Future(loop=self.loop) - if debug: - source_traceback = future._source_traceback + future = self._new_future(loop=self.loop) future.set_exception(exc) future = None test_utils.run_briefly(self.loop) support.gc_collect() if sys.version_info >= (3, 4): - if debug: - frame = source_traceback[-1] - regex = (r'^Future exception was never retrieved\n' - r'future: <Future finished exception=MemoryError\(\) ' - r'created at {filename}:{lineno}>\n' - r'source_traceback: Object ' - r'created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future exception was never retrieved\n' - r'future: ' - r'<Future finished exception=MemoryError\(\)>$' - ) + regex = r'^Future exception was never retrieved\n' exc_info = (type(exc), exc, exc.__traceback__) m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) else: - if debug: - frame = source_traceback[-1] - regex = (r'^Future/Task exception was never retrieved\n' - r'Future/Task created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, ' - r'in check_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ).format(filename=re.escape(frame[0]), - lineno=frame[1]) - else: - regex = (r'^Future/Task exception was never retrieved\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ) + regex = r'^Future/Task exception was never retrieved\n' m_log.error.assert_called_once_with(mock.ANY, exc_info=False) message = m_log.error.call_args[0][0] self.assertRegex(message, re.compile(regex, re.DOTALL)) @@ -458,14 +423,13 @@ class FutureTests(test_utils.TestCase): self.check_future_exception_never_retrieved(True) def test_set_result_unless_cancelled(self): - from asyncio import futures - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.cancel() futures._set_result_unless_cancelled(fut, 2) self.assertTrue(fut.cancelled()) def test_future_stop_iteration_args(self): - fut = asyncio.Future(loop=self.loop) + fut = self._new_future(loop=self.loop) fut.set_result((1, 2)) fi = fut.__iter__() result = None @@ -478,7 +442,21 @@ class FutureTests(test_utils.TestCase): self.assertEqual(result, (1, 2)) -class FutureDoneCallbackTests(test_utils.TestCase): +@unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._CFuture(*args, **kwargs) + + +class PyFutureTests(BaseFutureTests, test_utils.TestCase): + + def _new_future(self, *args, **kwargs): + return futures._PyFuture(*args, **kwargs) + + +class BaseFutureDoneCallbackTests(): def setUp(self): self.loop = self.new_test_loop() @@ -493,7 +471,7 @@ class FutureDoneCallbackTests(test_utils.TestCase): return bag_appender def _new_future(self): - return asyncio.Future(loop=self.loop) + raise NotImplementedError def test_callbacks_invoked_on_set_result(self): bag = [] @@ -557,5 +535,21 @@ class FutureDoneCallbackTests(test_utils.TestCase): self.assertEqual(f.result(), 'foo') +@unittest.skipUnless(hasattr(futures, '_CFuture'), + 'requires the C _asyncio module') +class CFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._CFuture(loop=self.loop) + + +class PyFutureDoneCallbackTests(BaseFutureDoneCallbackTests, + test_utils.TestCase): + + def _new_future(self): + return futures._PyFuture(loop=self.loop) + + if __name__ == '__main__': unittest.main() |