async def test_coro_reject(self): p = Promise(success_sleep(), loop=self.loop) with self.assertRaisesRegex(RuntimeError, "Task does not support set_exception operation"): p.reject(Exception("Should Fail")) self.assertEqual(await p, SUCCESS_RESULT)
async def test_resolution(self): promise = Promise(self.fut) promise.resolve(None) result = await promise self.assertIsNone(result) self.assertEqual(await self.fut, result)
async def test_rejection(self): promise = Promise(self.fut, log_unhandled_exception=False) exc = Exception("test_rejection") promise.reject(exc) self.assertAsyncRaises(exc, promise) self.assertAsyncRaises(exc, self.fut)
async def test_coro_resolve(self): p = Promise(success_sleep(), loop=self.loop) with self.assertRaisesRegex(RuntimeError, "Task does not support set_result operation"): p.resolve(None) self.assertEqual(await p, SUCCESS_RESULT)
async def test_promise_of_a_promise(self): p = Promise() p2 = Promise(p) p.resolve(0) self.assertEqual(await p2.then(lambda x: 1 / x).catch(lambda exc: 0), 0)
async def test_external_resolution(self): promise = Promise(self.fut) self.fut.set_result(None) result = await self.fut self.assertIsNone(result, None) self.assertEqual(result, await promise)
async def test_catch(self): p = Promise(division_by_0()) with self.assertRaises(ZeroDivisionError): await p self.assertTrue( await p.catch(lambda exc: isinstance(exc, ZeroDivisionError)))
async def test_lastly_simple_error(self): counter = Counter() p = Promise(division_by_0()).lastly(lambda: counter.update(["lastly"])) with self.assertRaises(ZeroDivisionError): await p self.assertEqual(counter["lastly"], 1)
async def test_promise_cancelled_2(self): b = False async def a(): nonlocal b b = True p = Promise() lp = p.lastly(a) p.resolve(10) lp.cancel() with self.assertRaises(CancelledError): await lp self.assertEqual(await p, 10) self.assertFalse(b)
async def test_promise_cancelled(self): b = False async def a(): nonlocal b b = True p = Promise() lp = p.lastly(a) p.cancel() with self.assertRaises(CancelledError): await p with self.assertRaises(CancelledError): await lp self.assertFalse(b)
async def test_then_chain_timing(self): p = Promise().resolve(10) start_time = self.loop.time() result = (await p.then( lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop) ).then(lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop)).then( lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop) ).then(lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop)).then( lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop) ).then(lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop)).then( lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop)).then( lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop)).then( lambda x: Promise(sum_with_sleep(x, 10), loop=self.loop))) end_time = self.loop.time() self.assertEqual(result, 100) self.assertAlmostEqual(DEFAULT_SLEEP * 9, end_time - start_time, delta=0.05)
async def test_catch_continue_chain(self): counter = Counter() p = (Promise(division_by_0()).catch( lambda _: counter.update(["catch"]) or UNIQUE).then( lambda val: counter.update(["then"]) or val is UNIQUE).catch( lambda exc: counter.update(["catch"]))) self.assertTrue(await p) self.assertEqual(counter["catch"], 1) self.assertEqual(counter["then"], 1)
async def test_catch_mid_chain(self): counter = Counter() p = Promise(division_by_0()).then( lambda num: counter.update(["then"]) or num + 10) with self.assertRaises(ZeroDivisionError): await p self.assertTrue( await p.catch(lambda exc: isinstance(exc, ZeroDivisionError))) self.assertEqual(counter["then"], 0)
async def test_future_log_traceback(self): import gc fut = self.loop.create_future() fut.set_exception(RuntimeError) p = Promise(fut) del fut, p gc.collect() await sleep(0)
async def test_cancellation_managed(self): with Promise() as p: t = p.then(lambda x: x * 2) t.cancel() with self.assertRaises(CancelledError): await t self.assertTrue(t.done()) self.assertTrue(t.cancelled()) self.assertTrue(p.done()) self.assertTrue(p.cancelled())
async def test_chain_after_cancellation_after_resolution(self): with Promise() as p: p.resolve(10) self.assertEqual(await p, 10) t1 = p.then(lambda x: x * 2) self.assertEqual(await t1, 20) t2 = t1.then(lambda x: sum_with_sleep(x, 10)) with self.assertRaises(CancelledError): await t2
async def test_ignore_unhandled_exception_2(self): async def raise_exc(): raise RuntimeError p = Promise(raise_exc()).catch(lambda exc: "success") await p._fut # bypass promise __await__ # Wait till next loop cycle await sleep(0) self.assertEqual(self.exc_ctx_count, 0) self.assertIsNone(self.exc_ctx) self.assertEqual(await p, "success")
async def test_chain_no_external_resolve(self): with Promise() as p: self.assertTrue(callable(getattr(p, "resolve"))) self.assertTrue(callable(getattr(p, "reject"))) t = p.then(lambda x: x * 2) self.assertFalse(hasattr(t, "resolve")) self.assertFalse(hasattr(t, "reject")) p.resolve(10) result = await t self.assertEqual(result, 20)
async def test_ignore_unhandled_exception_3(self): async def raise_exc(): raise RuntimeError p = Promise(raise_exc()) with self.assertRaises(RuntimeError): await p # Wait till next loop cycle await sleep(0.1) self.assertEqual(self.exc_ctx_count, 0) self.assertIsNone(self.exc_ctx)
async def test_chain_cancellation_sync(self): with Promise() as p: p.resolve(10) t1 = p.then(lambda x: x * 2) t2 = t1.then(lambda x: x * 2) t3 = t2.then(lambda x: x * 2) self.assertEqual(await p, 10) with self.assertRaises(CancelledError): await p._notify_chain self.assertEqual(await t1, 20) self.assertEqual(await t2, 40) self.assertEqual(await t3, 80)
async def test_cancellation_managed_2(self): with Promise() as p: p.resolve(10) t = p.then(lambda x: x * 2) t.cancel() with self.assertRaises(CancelledError): await t self.assertEqual(await p, 10) self.assertTrue(t.done()) self.assertTrue(t.cancelled()) self.assertTrue(p.done()) self.assertTrue(p.cancelled())
async def test_catch_fails_and_recover(self): counter = Counter() def fails_catch(exc): self.assertIsInstance(exc, ZeroDivisionError) counter.update(["catch"]) raise RuntimeError self.assertIs( await (Promise(division_by_0()).catch(fails_catch).catch( lambda exc: self.assertIsInstance(exc, RuntimeError) or self. assertIsInstance(exc.__context__, ZeroDivisionError ) or counter.update(["catch"]) or UNIQUE)), UNIQUE, ) self.assertEqual(counter["catch"], 2)
async def test_catch_fails(self): counter = Counter() def fails_catch(prop_exc): self.assertIsInstance(prop_exc, ZeroDivisionError) counter.update(["catch"]) raise RuntimeError try: await (Promise(division_by_0()).catch(fails_catch)) except RuntimeError as exc: self.assertIsInstance(exc.__context__, ZeroDivisionError) else: self.fail("Promise should not have succeeded") self.assertEqual(counter["catch"], 1)
async def test_chain_cancellation_branch(self): with Promise() as p: p.resolve(10) t1 = p.then(lambda x: sum_with_sleep(x, 10)) t2 = p.then(lambda x: x * 2) t3 = p.then(lambda x: sum_with_sleep(x, 10)) t1.cancel() self.assertEqual(await p, 10) with self.assertRaises(CancelledError): await t1 self.assertEqual(await t2, 20) self.assertEqual(await t3, 20)
async def test_ignore_unhandled_cancellation_error(self): fut = self.loop.create_future() p = Promise(fut) fut.cancel() with self.assertRaises(CancelledError): await fut # Wait till next loop cycle await sleep(0) self.assertEqual(self.exc_ctx_count, 0) self.assertIsNone(self.exc_ctx) with self.assertRaises(CancelledError): await p
async def test_internal_state(self): promise = Promise(success_sleep(), loop=self.loop) self.assertEqual(promise.loop, self.loop) self.assertEqual(promise.done(), False) self.assertEqual(promise.cancelled(), False) await promise self.assertEqual(promise.loop, self.loop) self.assertEqual(promise.done(), True) self.assertEqual(promise.cancelled(), False)
async def test_promise_cancellation_after_result(self): p = Promise() counter = Counter() p.cancel() with self.assertRaises(CancelledError): await (p.then(lambda x: counter.update(["then"])).catch( lambda exc: counter.update(["catch"])).lastly( lambda: counter.update(["lastly"]))) self.assertTrue(p.done()) self.assertTrue(p.cancelled()) self.assertEqual(counter["then"], 0) self.assertEqual(counter["catch"], 0) self.assertEqual(counter["lastly"], 0)
async def test_ignore_unhandled_exception(self): async def raise_exc(): raise RuntimeError task = self.loop.create_task(raise_exc()) p = Promise(task, log_unhandled_exception=False) with self.assertRaises(RuntimeError): await task # Wait till next loop cycle await sleep(0) self.assertEqual(self.exc_ctx_count, 0) self.assertIsNone(self.exc_ctx) with self.assertRaises(RuntimeError): await p
async def test_task_cancellation(self): a = {} async def task(_): t1.cancel() a["test"] = 10 await asleep(DEFAULT_SLEEP) a["shouldnt_exist"] = 10 with Promise() as p: p.resolve(10) t1 = p.then(task) self.assertNotIn("test", a) self.assertNotIn("shouldnt_exist", a) with self.assertRaises(CancelledError): await t1 self.assertIn("test", a) self.assertNotIn("shouldnt_exist", a)
async def test_unhandled_exception_2(self): async def raise_exc(_): raise RuntimeError p = Promise(raise_exc(None)).catch(raise_exc) with self.assertRaises(RuntimeError): await p._fut # bypass promise __await__ # Wait till next loop cycle await sleep(0) self.assertEqual(self.exc_ctx_count, 1) self.assertIsNotNone(self.exc_ctx) self.assertIn("message", self.exc_ctx) self.assertIsInstance(self.exc_ctx["exception"], RuntimeError) with self.assertRaises(RuntimeError): await p