diff options
Diffstat (limited to 'tests/test_tasks.py')
-rw-r--r-- | tests/test_tasks.py | 430 |
1 files changed, 209 insertions, 221 deletions
diff --git a/tests/test_tasks.py b/tests/test_tasks.py index 770f218..e1a8a27 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -6,15 +6,17 @@ import sys import types import unittest import weakref -from test import support -from test.script_helper import assert_python_ok -from unittest import mock -import asyncio -from asyncio import coroutines -from asyncio import test_utils +import trollius as asyncio +from trollius import From, Return +from trollius import coroutines +from trollius import test_support as support +from trollius import test_utils +from trollius.test_support import assert_python_ok +from trollius.test_utils import mock +PY33 = (sys.version_info >= (3, 3)) PY34 = (sys.version_info >= (3, 4)) PY35 = (sys.version_info >= (3, 5)) @@ -136,9 +138,14 @@ class TaskTests(test_utils.TestCase): self.loop.set_debug(False) @asyncio.coroutine + def noop(): + yield From(None) + raise Return('abc') + + @asyncio.coroutine def notmuch(): - yield from [] - return 'abc' + yield From(noop()) + raise Return('abc') # test coroutine function self.assertEqual(notmuch.__name__, 'notmuch') @@ -152,7 +159,7 @@ class TaskTests(test_utils.TestCase): # test coroutine object gen = notmuch() - if coroutines._DEBUG or PY35: + if PY35 or (coroutines._DEBUG and PY33): coro_qualname = 'TaskTests.test_task_repr.<locals>.notmuch' else: coro_qualname = 'notmuch' @@ -196,7 +203,7 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def notmuch(): - # notmuch() function doesn't use yield from: it will be wrapped by + # notmuch() function doesn't use yield: it will be wrapped by # @coroutine decorator return 123 @@ -209,12 +216,15 @@ class TaskTests(test_utils.TestCase): # test coroutine object gen = notmuch() - if coroutines._DEBUG or PY35: + if PY35 or coroutines._DEBUG: # On Python >= 3.5, generators now inherit the name of the # function, as expected, and have a qualified name (__qualname__ # attribute). coro_name = 'notmuch' - coro_qualname = 'TaskTests.test_task_repr_coro_decorator.<locals>.notmuch' + if PY35 or (coroutines._DEBUG and PY33): + coro_qualname = 'TaskTests.test_task_repr_coro_decorator.<locals>.notmuch' + else: + coro_qualname = 'notmuch' else: # On Python < 3.5, generators inherit the name of the code, not of # the function. See: http://bugs.python.org/issue21205 @@ -261,7 +271,8 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def wait_for(fut): - return (yield from fut) + res = yield From(fut) + raise Return(res) fut = asyncio.Future(loop=self.loop) task = asyncio.Task(wait_for(fut), loop=self.loop) @@ -275,9 +286,9 @@ class TaskTests(test_utils.TestCase): def test_task_basics(self): @asyncio.coroutine def outer(): - a = yield from inner1() - b = yield from inner2() - return a+b + a = yield From(inner1()) + b = yield From(inner2()) + raise Return(a+b) @asyncio.coroutine def inner1(): @@ -301,10 +312,11 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def task(): - yield from asyncio.sleep(10.0, loop=loop) - return 12 + yield From(asyncio.sleep(10.0, loop=loop)) + raise Return(12) t = asyncio.Task(task(), loop=loop) + test_utils.run_briefly(loop) loop.call_soon(t.cancel) with self.assertRaises(asyncio.CancelledError): loop.run_until_complete(t) @@ -315,9 +327,9 @@ class TaskTests(test_utils.TestCase): def test_cancel_yield(self): @asyncio.coroutine def task(): - yield - yield - return 12 + yield From(None) + yield From(None) + raise Return(12) t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) # start coro @@ -333,8 +345,8 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def task(): - yield from f - return 12 + yield From(f) + raise Return(12) t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) # start task @@ -349,8 +361,8 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def task(): - yield from f - return 12 + yield From(f) + raise Return(12) t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) @@ -371,11 +383,11 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def task(): - yield from fut1 + yield From(fut1) try: - yield from fut2 + yield From(fut2) except asyncio.CancelledError: - return 42 + raise Return(42) t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) @@ -396,13 +408,13 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def task(): - yield from fut1 + yield From(fut1) try: - yield from fut2 + yield From(fut2) except asyncio.CancelledError: pass - res = yield from fut3 - return res + res = yield From(fut3) + raise Return(res) t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) @@ -429,8 +441,8 @@ class TaskTests(test_utils.TestCase): t.cancel() self.assertTrue(t._must_cancel) # White-box test. # The sleep should be cancelled immediately. - yield from asyncio.sleep(100, loop=loop) - return 12 + yield From(asyncio.sleep(100, loop=loop)) + raise Return(12) t = asyncio.Task(task(), loop=loop) self.assertRaises( @@ -452,17 +464,16 @@ class TaskTests(test_utils.TestCase): loop = self.new_test_loop(gen) - x = 0 + non_local = {'x': 0} waiters = [] @asyncio.coroutine def task(): - nonlocal x - while x < 10: + while non_local['x'] < 10: waiters.append(asyncio.sleep(0.1, loop=loop)) - yield from waiters[-1] - x += 1 - if x == 2: + yield From(waiters[-1]) + non_local['x'] += 1 + if non_local['x'] == 3: loop.stop() t = asyncio.Task(task(), loop=loop) @@ -471,7 +482,7 @@ class TaskTests(test_utils.TestCase): self.assertEqual(str(cm.exception), 'Event loop stopped before Future completed.') self.assertFalse(t.done()) - self.assertEqual(x, 2) + self.assertEqual(non_local['x'], 3) self.assertAlmostEqual(0.3, loop.time()) # close generators @@ -482,6 +493,7 @@ class TaskTests(test_utils.TestCase): def test_wait_for(self): + @asyncio.coroutine def gen(): when = yield self.assertAlmostEqual(0.2, when) @@ -491,27 +503,34 @@ class TaskTests(test_utils.TestCase): loop = self.new_test_loop(gen) - foo_running = None + non_local = {'foo_running': None} @asyncio.coroutine def foo(): - nonlocal foo_running - foo_running = True + non_local['foo_running'] = True try: - yield from asyncio.sleep(0.2, loop=loop) + yield From(asyncio.sleep(0.2, loop=loop)) finally: - foo_running = False - return 'done' + non_local['foo_running'] = False + raise Return('done') fut = asyncio.Task(foo(), loop=loop) + test_utils.run_briefly(loop) with self.assertRaises(asyncio.TimeoutError): loop.run_until_complete(asyncio.wait_for(fut, 0.1, loop=loop)) + + # Trollius issue #2: need to run the loop briefly to ensure that the + # cancellation is propagated to all tasks + waiter = asyncio.Future(loop=loop) + fut.add_done_callback(lambda f: waiter.set_result(True)) + loop.run_until_complete(waiter) + self.assertTrue(fut.done()) # it should have been cancelled due to the timeout self.assertTrue(fut.cancelled()) self.assertAlmostEqual(0.1, loop.time()) - self.assertEqual(foo_running, False) + self.assertEqual(non_local['foo_running'], False) def test_wait_for_blocking(self): loop = self.new_test_loop() @@ -538,17 +557,24 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def foo(): - yield from asyncio.sleep(0.2, loop=loop) - return 'done' + yield From(asyncio.sleep(0.2, loop=loop)) + raise Return('done') asyncio.set_event_loop(loop) try: fut = asyncio.Task(foo(), loop=loop) + test_utils.run_briefly(loop) with self.assertRaises(asyncio.TimeoutError): loop.run_until_complete(asyncio.wait_for(fut, 0.01)) finally: asyncio.set_event_loop(None) + # Trollius issue #2: need to run the loop briefly to ensure that the + # cancellation is propagated to all tasks + waiter = asyncio.Future(loop=loop) + fut.add_done_callback(lambda f: waiter.set_result(True)) + loop.run_until_complete(waiter) + self.assertAlmostEqual(0.01, loop.time()) self.assertTrue(fut.done()) self.assertTrue(fut.cancelled()) @@ -584,10 +610,10 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def foo(): - done, pending = yield from asyncio.wait([b, a], loop=loop) + done, pending = yield From(asyncio.wait([b, a], loop=loop)) self.assertEqual(done, set([a, b])) self.assertEqual(pending, set()) - return 42 + raise Return(42) res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertEqual(res, 42) @@ -614,10 +640,10 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def foo(): - done, pending = yield from asyncio.wait([b, a]) + done, pending = yield From(asyncio.wait([b, a])) self.assertEqual(done, set([a, b])) self.assertEqual(pending, set()) - return 42 + raise Return(42) asyncio.set_event_loop(loop) res = loop.run_until_complete( @@ -638,7 +664,7 @@ class TaskTests(test_utils.TestCase): done, pending = self.loop.run_until_complete(task) self.assertFalse(pending) - self.assertEqual(set(f.result() for f in done), {'test', 'spam'}) + self.assertEqual(set(f.result() for f in done), set(('test', 'spam'))) def test_wait_errors(self): self.assertRaises( @@ -672,8 +698,8 @@ class TaskTests(test_utils.TestCase): loop=loop) done, pending = loop.run_until_complete(task) - self.assertEqual({b}, done) - self.assertEqual({a}, pending) + self.assertEqual(set((b,)), done) + self.assertEqual(set((a,)), pending) self.assertFalse(a.done()) self.assertTrue(b.done()) self.assertIsNone(b.result()) @@ -689,12 +715,12 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def coro1(): - yield + yield From(None) @asyncio.coroutine def coro2(): - yield - yield + yield From(None) + yield From(None) a = asyncio.Task(coro1(), loop=self.loop) b = asyncio.Task(coro2(), loop=self.loop) @@ -704,7 +730,7 @@ class TaskTests(test_utils.TestCase): loop=self.loop) done, pending = self.loop.run_until_complete(task) - self.assertEqual({a, b}, done) + self.assertEqual(set((a, b)), done) self.assertTrue(a.done()) self.assertIsNone(a.result()) self.assertTrue(b.done()) @@ -733,8 +759,8 @@ class TaskTests(test_utils.TestCase): loop=loop) done, pending = loop.run_until_complete(task) - self.assertEqual({b}, done) - self.assertEqual({a}, pending) + self.assertEqual(set((b,)), done) + self.assertEqual(set((a,)), pending) self.assertAlmostEqual(0, loop.time()) # move forward to close generator @@ -757,7 +783,7 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def exc(): - yield from asyncio.sleep(0.01, loop=loop) + yield From(asyncio.sleep(0.01, loop=loop)) raise ZeroDivisionError('err') b = asyncio.Task(exc(), loop=loop) @@ -765,8 +791,8 @@ class TaskTests(test_utils.TestCase): loop=loop) done, pending = loop.run_until_complete(task) - self.assertEqual({b}, done) - self.assertEqual({a}, pending) + self.assertEqual(set((b,)), done) + self.assertEqual(set((a,)), pending) self.assertAlmostEqual(0.01, loop.time()) # move forward to close generator @@ -788,14 +814,14 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def sleeper(): - yield from asyncio.sleep(0.15, loop=loop) + yield From(asyncio.sleep(0.15, loop=loop)) raise ZeroDivisionError('really') b = asyncio.Task(sleeper(), loop=loop) @asyncio.coroutine def foo(): - done, pending = yield from asyncio.wait([b, a], loop=loop) + done, pending = yield From(asyncio.wait([b, a], loop=loop)) self.assertEqual(len(done), 2) self.assertEqual(pending, set()) errors = set(f for f in done if f.exception() is not None) @@ -825,8 +851,8 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def foo(): - done, pending = yield from asyncio.wait([b, a], timeout=0.11, - loop=loop) + done, pending = yield From(asyncio.wait([b, a], timeout=0.11, + loop=loop)) self.assertEqual(done, set([a])) self.assertEqual(pending, set([b])) @@ -876,17 +902,16 @@ class TaskTests(test_utils.TestCase): # disable "slow callback" warning loop.slow_callback_duration = 1.0 completed = set() - time_shifted = False + non_local = {'time_shifted': False} @asyncio.coroutine def sleeper(dt, x): - nonlocal time_shifted - yield from asyncio.sleep(dt, loop=loop) + yield From(asyncio.sleep(dt, loop=loop)) completed.add(x) - if not time_shifted and 'a' in completed and 'b' in completed: - time_shifted = True + if not non_local['time_shifted'] and 'a' in completed and 'b' in completed: + non_local['time_shifted'] = True loop.advance_time(0.14) - return x + raise Return(x) a = sleeper(0.01, 'a') b = sleeper(0.01, 'b') @@ -896,8 +921,8 @@ class TaskTests(test_utils.TestCase): def foo(): values = [] for f in asyncio.as_completed([b, c, a], loop=loop): - values.append((yield from f)) - return values + values.append((yield From(f))) + raise Return(values) res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertAlmostEqual(0.15, loop.time()) @@ -929,11 +954,11 @@ class TaskTests(test_utils.TestCase): if values: loop.advance_time(0.02) try: - v = yield from f + v = yield From(f) values.append((1, v)) except asyncio.TimeoutError as exc: values.append((2, exc)) - return values + raise Return(values) res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertEqual(len(res), 2, res) @@ -960,7 +985,7 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def foo(): for f in asyncio.as_completed([a], timeout=1, loop=loop): - v = yield from f + v = yield From(f) self.assertEqual(v, 'a') loop.run_until_complete(asyncio.Task(foo(), loop=loop)) @@ -976,7 +1001,7 @@ class TaskTests(test_utils.TestCase): a = asyncio.sleep(0.05, 'a', loop=loop) b = asyncio.sleep(0.10, 'b', loop=loop) - fs = {a, b} + fs = set((a, b)) futs = list(asyncio.as_completed(fs, loop=loop)) self.assertEqual(len(futs), 2) @@ -1001,12 +1026,12 @@ class TaskTests(test_utils.TestCase): a = asyncio.sleep(0.05, 'a', loop=loop) b = asyncio.sleep(0.05, 'b', loop=loop) - fs = {a, b} + fs = set((a, b)) futs = list(asyncio.as_completed(fs, loop=loop)) self.assertEqual(len(futs), 2) waiter = asyncio.wait(futs, loop=loop) done, pending = loop.run_until_complete(waiter) - self.assertEqual(set(f.result() for f in done), {'a', 'b'}) + self.assertEqual(set(f.result() for f in done), set(('a', 'b'))) def test_as_completed_duplicate_coroutines(self): @@ -1020,13 +1045,13 @@ class TaskTests(test_utils.TestCase): c = coro('ham') for f in asyncio.as_completed([c, c, coro('spam')], loop=self.loop): - result.append((yield from f)) - return result + result.append((yield From(f))) + raise Return(result) fut = asyncio.Task(runner(), loop=self.loop) self.loop.run_until_complete(fut) result = fut.result() - self.assertEqual(set(result), {'ham', 'spam'}) + self.assertEqual(set(result), set(('ham', 'spam'))) self.assertEqual(len(result), 2) def test_sleep(self): @@ -1042,9 +1067,9 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def sleeper(dt, arg): - yield from asyncio.sleep(dt/2, loop=loop) - res = yield from asyncio.sleep(dt/2, arg, loop=loop) - return res + yield From(asyncio.sleep(dt/2, loop=loop)) + res = yield From(asyncio.sleep(dt/2, arg, loop=loop)) + raise Return(res) t = asyncio.Task(sleeper(0.1, 'yeah'), loop=loop) loop.run_until_complete(t) @@ -1064,22 +1089,21 @@ class TaskTests(test_utils.TestCase): t = asyncio.Task(asyncio.sleep(10.0, 'yeah', loop=loop), loop=loop) - handle = None + non_local = {'handle': None} orig_call_later = loop.call_later def call_later(delay, callback, *args): - nonlocal handle - handle = orig_call_later(delay, callback, *args) - return handle + non_local['handle'] = orig_call_later(delay, callback, *args) + return non_local['handle'] loop.call_later = call_later test_utils.run_briefly(loop) - self.assertFalse(handle._cancelled) + self.assertFalse(non_local['handle']._cancelled) t.cancel() test_utils.run_briefly(loop) - self.assertTrue(handle._cancelled) + self.assertTrue(non_local['handle']._cancelled) def test_task_cancel_sleeping_task(self): @@ -1094,18 +1118,18 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def sleep(dt): - yield from asyncio.sleep(dt, loop=loop) + yield From(asyncio.sleep(dt, loop=loop)) @asyncio.coroutine def doit(): sleeper = asyncio.Task(sleep(5000), loop=loop) loop.call_later(0.1, sleeper.cancel) try: - yield from sleeper + yield From(sleeper) except asyncio.CancelledError: - return 'cancelled' + raise Return('cancelled') else: - return 'slept in' + raise Return('slept in') doer = doit() self.assertEqual(loop.run_until_complete(doer), 'cancelled') @@ -1116,7 +1140,7 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def coro(): - yield from fut + yield From(fut) task = asyncio.Task(coro(), loop=self.loop) test_utils.run_briefly(self.loop) @@ -1144,9 +1168,9 @@ class TaskTests(test_utils.TestCase): def test_step_result(self): @asyncio.coroutine def notmuch(): - yield None - yield 1 - return 'ko' + yield From(None) + yield From(1) + raise Return('ko') self.assertRaises( RuntimeError, self.loop.run_until_complete, notmuch()) @@ -1157,19 +1181,18 @@ class TaskTests(test_utils.TestCase): class Fut(asyncio.Future): def __init__(self, *args, **kwds): self.cb_added = False - super().__init__(*args, **kwds) + super(Fut, self).__init__(*args, **kwds) def add_done_callback(self, fn): self.cb_added = True - super().add_done_callback(fn) + super(Fut, self).add_done_callback(fn) fut = Fut(loop=self.loop) - result = None + non_local = {'result': None} @asyncio.coroutine def wait_for_future(): - nonlocal result - result = yield from fut + non_local['result'] = yield From(fut) t = asyncio.Task(wait_for_future(), loop=self.loop) test_utils.run_briefly(self.loop) @@ -1178,7 +1201,7 @@ class TaskTests(test_utils.TestCase): res = object() fut.set_result(res) test_utils.run_briefly(self.loop) - self.assertIs(res, result) + self.assertIs(res, non_local['result']) self.assertTrue(t.done()) self.assertIsNone(t.result()) @@ -1204,24 +1227,24 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def sleeper(): - yield from asyncio.sleep(10, loop=loop) + yield From(asyncio.sleep(10, loop=loop)) base_exc = BaseException() @asyncio.coroutine def notmutch(): try: - yield from sleeper() + yield From(sleeper()) except asyncio.CancelledError: raise base_exc task = asyncio.Task(notmutch(), loop=loop) - test_utils.run_briefly(loop) + test_utils.run_briefly(loop, 2) task.cancel() self.assertFalse(task.done()) - self.assertRaises(BaseException, test_utils.run_briefly, loop) + self.assertRaises(BaseException, test_utils.run_briefly, loop, 2) self.assertTrue(task.done()) self.assertFalse(task.cancelled()) @@ -1242,37 +1265,6 @@ class TaskTests(test_utils.TestCase): yield self.assertTrue(asyncio.iscoroutinefunction(fn2)) - def test_yield_vs_yield_from(self): - fut = asyncio.Future(loop=self.loop) - - @asyncio.coroutine - def wait_for_future(): - yield fut - - task = wait_for_future() - with self.assertRaises(RuntimeError): - self.loop.run_until_complete(task) - - self.assertFalse(fut.done()) - - def test_yield_vs_yield_from_generator(self): - @asyncio.coroutine - def coro(): - yield - - @asyncio.coroutine - def wait_for_future(): - gen = coro() - try: - yield gen - finally: - gen.close() - - task = wait_for_future() - self.assertRaises( - RuntimeError, - self.loop.run_until_complete, task) - def test_coroutine_non_gen_function(self): @asyncio.coroutine def func(): @@ -1323,7 +1315,7 @@ class TaskTests(test_utils.TestCase): @asyncio.coroutine def coro1(loop): self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) - yield from fut1 + yield From(fut1) self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) fut2.set_result(True) @@ -1331,7 +1323,7 @@ class TaskTests(test_utils.TestCase): def coro2(loop): self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) fut1.set_result(True) - yield from fut2 + yield From(fut2) self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) task1 = asyncio.Task(coro1(self.loop), loop=self.loop) @@ -1346,54 +1338,50 @@ class TaskTests(test_utils.TestCase): def test_yield_future_passes_cancel(self): # Cancelling outer() cancels inner() cancels waiter. - proof = 0 + non_local = {'proof': 0} waiter = asyncio.Future(loop=self.loop) @asyncio.coroutine def inner(): - nonlocal proof try: - yield from waiter + yield From(waiter) except asyncio.CancelledError: - proof += 1 + non_local['proof'] += 1 raise else: self.fail('got past sleep() in inner()') @asyncio.coroutine def outer(): - nonlocal proof try: - yield from inner() + yield From(inner()) except asyncio.CancelledError: - proof += 100 # Expect this path. + non_local['proof'] += 100 # Expect this path. else: - proof += 10 + non_local['proof'] += 10 f = asyncio.async(outer(), loop=self.loop) test_utils.run_briefly(self.loop) f.cancel() self.loop.run_until_complete(f) - self.assertEqual(proof, 101) + self.assertEqual(non_local['proof'], 101) self.assertTrue(waiter.cancelled()) def test_yield_wait_does_not_shield_cancel(self): # Cancelling outer() makes wait() return early, leaves inner() # running. - proof = 0 + non_local = {'proof': 0} waiter = asyncio.Future(loop=self.loop) @asyncio.coroutine def inner(): - nonlocal proof - yield from waiter - proof += 1 + yield From(waiter) + non_local['proof'] += 1 @asyncio.coroutine def outer(): - nonlocal proof - d, p = yield from asyncio.wait([inner()], loop=self.loop) - proof += 100 + d, p = yield From(asyncio.wait([inner()], loop=self.loop)) + non_local['proof'] += 100 f = asyncio.async(outer(), loop=self.loop) test_utils.run_briefly(self.loop) @@ -1402,7 +1390,7 @@ class TaskTests(test_utils.TestCase): asyncio.CancelledError, self.loop.run_until_complete, f) waiter.set_result(None) test_utils.run_briefly(self.loop) - self.assertEqual(proof, 1) + self.assertEqual(non_local['proof'], 1) def test_shield_result(self): inner = asyncio.Future(loop=self.loop) @@ -1436,20 +1424,18 @@ class TaskTests(test_utils.TestCase): def test_shield_effect(self): # Cancelling outer() does not affect inner(). - proof = 0 + non_local = {'proof': 0} waiter = asyncio.Future(loop=self.loop) @asyncio.coroutine def inner(): - nonlocal proof - yield from waiter - proof += 1 + yield From(waiter) + non_local['proof'] += 1 @asyncio.coroutine def outer(): - nonlocal proof - yield from asyncio.shield(inner(), loop=self.loop) - proof += 100 + yield From(asyncio.shield(inner(), loop=self.loop)) + non_local['proof'] += 100 f = asyncio.async(outer(), loop=self.loop) test_utils.run_briefly(self.loop) @@ -1458,7 +1444,7 @@ class TaskTests(test_utils.TestCase): self.loop.run_until_complete(f) waiter.set_result(None) test_utils.run_briefly(self.loop) - self.assertEqual(proof, 1) + self.assertEqual(non_local['proof'], 1) def test_shield_gather(self): child1 = asyncio.Future(loop=self.loop) @@ -1527,7 +1513,7 @@ class TaskTests(test_utils.TestCase): def coro(): # The actual coroutine. self.assertTrue(gen.gi_running) - yield from fut + yield From(fut) # A completed Future used to run the coroutine. fut = asyncio.Future(loop=self.loop) @@ -1569,13 +1555,15 @@ class TaskTests(test_utils.TestCase): try: @asyncio.coroutine def t1(): - return (yield from t2()) + res = yield From(t2()) + raise Return(res) @asyncio.coroutine def t2(): f = asyncio.Future(loop=self.loop) asyncio.Task(t3(f), loop=self.loop) - return (yield from f) + res = yield From(f) + raise Return(res) @asyncio.coroutine def t3(f): @@ -1590,7 +1578,7 @@ class TaskTests(test_utils.TestCase): def test_yield_from_corowrapper_send(self): def foo(): a = yield - return a + raise Return(a) def call(arg): cw = asyncio.coroutines.CoroWrapper(foo(), foo) @@ -1598,7 +1586,8 @@ class TaskTests(test_utils.TestCase): try: cw.send(arg) except StopIteration as ex: - return ex.args[0] + ex.raised = True + return ex.value else: raise AssertionError('StopIteration was expected') @@ -1607,18 +1596,19 @@ class TaskTests(test_utils.TestCase): def test_corowrapper_weakref(self): wd = weakref.WeakValueDictionary() - def foo(): yield from [] + def foo(): + yield From(None) cw = asyncio.coroutines.CoroWrapper(foo(), foo) wd['cw'] = cw # Would fail without __weakref__ slot. cw.gen = None # Suppress warning from __del__. - @unittest.skipUnless(PY34, - 'need python 3.4 or later') + @test_utils.skipUnless(PY34, + 'need python 3.4 or later') def test_log_destroyed_pending_task(self): @asyncio.coroutine def kill_me(loop): future = asyncio.Future(loop=loop) - yield from future + yield From(future) # at this point, the only reference to kill_me() task is # the Task._wakeup() method in future._callbacks raise Exception("code never reached") @@ -1630,7 +1620,7 @@ class TaskTests(test_utils.TestCase): # schedule the task coro = kill_me(self.loop) task = asyncio.async(coro, loop=self.loop) - self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), {task}) + self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), set((task,))) # execute the task so it waits for future self.loop._run_once() @@ -1654,7 +1644,7 @@ class TaskTests(test_utils.TestCase): }) mock_handler.reset_mock() - @mock.patch('asyncio.coroutines.logger') + @mock.patch('trollius.coroutines.logger') def test_coroutine_never_yielded(self, m_log): debug = asyncio.coroutines._DEBUG try: @@ -1665,7 +1655,7 @@ class TaskTests(test_utils.TestCase): finally: asyncio.coroutines._DEBUG = debug - tb_filename = __file__ + tb_filename = sys._getframe().f_code.co_filename tb_lineno = sys._getframe().f_lineno + 2 # create a coroutine object but don't use it coro_noop() @@ -1674,12 +1664,13 @@ class TaskTests(test_utils.TestCase): self.assertTrue(m_log.error.called) message = m_log.error.call_args[0][0] func_filename, func_lineno = test_utils.get_function_source(coro_noop) + coro_name = getattr(coro_noop, '__qualname__', coro_noop.__name__) regex = (r'^<CoroWrapper %s\(\) .* at %s:%s, .*> was never yielded from\n' r'Coroutine object created at \(most recent call last\):\n' r'.*\n' r' File "%s", line %s, in test_coroutine_never_yielded\n' r' coro_noop\(\)$' - % (re.escape(coro_noop.__qualname__), + % (re.escape(coro_name), re.escape(func_filename), func_lineno, re.escape(tb_filename), tb_lineno)) @@ -1689,14 +1680,23 @@ class TaskTests(test_utils.TestCase): self.loop.set_debug(True) task = asyncio.Task(coroutine_function(), loop=self.loop) - lineno = sys._getframe().f_lineno - 1 - self.assertIsInstance(task._source_traceback, list) - self.assertEqual(task._source_traceback[-1][:3], - (__file__, - lineno, - 'test_task_source_traceback')) + self.check_soure_traceback(task._source_traceback, -1) self.loop.run_until_complete(task) + def test_coroutine_class(self): + # Trollius issue #9 + self.loop.set_debug(True) + + class MyClass(object): + def __call__(self): + return 7 + + obj = MyClass() + coro_func = asyncio.coroutine(obj) + coro_obj = coro_func() + res = self.loop.run_until_complete(coro_obj) + self.assertEqual(res, 7) + class GatherTestsBase: @@ -1772,30 +1772,19 @@ class GatherTestsBase: aio_path = os.path.dirname(os.path.dirname(asyncio.__file__)) code = '\n'.join(( - 'import asyncio.coroutines', - 'print(asyncio.coroutines._DEBUG)')) - - # Test with -E to not fail if the unit test was run with - # PYTHONASYNCIODEBUG set to a non-empty string - sts, stdout, stderr = assert_python_ok('-E', '-c', code, - PYTHONPATH=aio_path) - self.assertEqual(stdout.rstrip(), b'False') + 'import trollius.coroutines', + 'print(trollius.coroutines._DEBUG)')) sts, stdout, stderr = assert_python_ok('-c', code, - PYTHONASYNCIODEBUG='', + TROLLIUSDEBUG='', PYTHONPATH=aio_path) self.assertEqual(stdout.rstrip(), b'False') sts, stdout, stderr = assert_python_ok('-c', code, - PYTHONASYNCIODEBUG='1', + TROLLIUSDEBUG='1', PYTHONPATH=aio_path) self.assertEqual(stdout.rstrip(), b'True') - sts, stdout, stderr = assert_python_ok('-E', '-c', code, - PYTHONASYNCIODEBUG='1', - PYTHONPATH=aio_path) - self.assertEqual(stdout.rstrip(), b'False') - class FutureGatherTests(GatherTestsBase, test_utils.TestCase): @@ -1884,7 +1873,7 @@ class FutureGatherTests(GatherTestsBase, test_utils.TestCase): class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase): def setUp(self): - super().setUp() + super(CoroutineGatherTests, self).setUp() asyncio.set_event_loop(self.one_loop) def wrap_futures(self, *futures): @@ -1892,7 +1881,8 @@ class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase): for fut in futures: @asyncio.coroutine def coro(fut=fut): - return (yield from fut) + result = (yield From(fut)) + raise Return(result) coros.append(coro()) return coros @@ -1924,44 +1914,42 @@ class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase): def test_cancellation_broadcast(self): # Cancelling outer() cancels all children. - proof = 0 + non_local = {'proof': 0} waiter = asyncio.Future(loop=self.one_loop) @asyncio.coroutine def inner(): - nonlocal proof - yield from waiter - proof += 1 + yield From(waiter) + non_local['proof'] += 1 child1 = asyncio.async(inner(), loop=self.one_loop) child2 = asyncio.async(inner(), loop=self.one_loop) - gatherer = None + non_local['gatherer'] = None @asyncio.coroutine def outer(): - nonlocal proof, gatherer - gatherer = asyncio.gather(child1, child2, loop=self.one_loop) - yield from gatherer - proof += 100 + non_local['gatherer'] = asyncio.gather(child1, child2, loop=self.one_loop) + yield From(non_local['gatherer']) + non_local['proof'] += 100 f = asyncio.async(outer(), loop=self.one_loop) test_utils.run_briefly(self.one_loop) self.assertTrue(f.cancel()) with self.assertRaises(asyncio.CancelledError): self.one_loop.run_until_complete(f) - self.assertFalse(gatherer.cancel()) + self.assertFalse(non_local['gatherer'].cancel()) self.assertTrue(waiter.cancelled()) self.assertTrue(child1.cancelled()) self.assertTrue(child2.cancelled()) test_utils.run_briefly(self.one_loop) - self.assertEqual(proof, 0) + self.assertEqual(non_local['proof'], 0) def test_exception_marking(self): # Test for the first line marked "Mark exception retrieved." @asyncio.coroutine def inner(f): - yield from f + yield From(f) raise RuntimeError('should not be ignored') a = asyncio.Future(loop=self.one_loop) @@ -1969,7 +1957,7 @@ class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase): @asyncio.coroutine def outer(): - yield from asyncio.gather(inner(a), inner(b), loop=self.one_loop) + yield From(asyncio.gather(inner(a), inner(b), loop=self.one_loop)) f = asyncio.async(outer(), loop=self.one_loop) test_utils.run_briefly(self.one_loop) |