def test_future_gather_cancel_outer(): fut1 = core.AsyncFuture() fut2 = core.AsyncFuture() # Gathering not-done futures gather = core.AsyncFuture.gather(fut1, fut2) assert not gather.done() assert gather.cancel() assert gather.done() assert gather.cancelled() with pytest.raises(CancelledError): assert gather.result()
def test_task_cancel_awaiting(): task_mgr = core.AsyncTaskManager.get_global_ptr() task_chain = task_mgr.make_task_chain("test_task_cancel_awaiting") fut = core.AsyncFuture() async def task_main(task): await fut return task.done task = core.PythonTask(task_main, 'task_main') task.set_task_chain(task_chain.name) task_mgr.add(task) task_chain.poll() assert not task.done() task_chain.poll() assert not task.done() task.cancel() task_chain.poll() assert task.done() assert task.cancelled() assert fut.done() assert fut.cancelled()
def test_task_cancel_waiting(): # Calling result() in a threaded task chain should cancel the future being # waited on if the surrounding task is cancelled. task_mgr = core.AsyncTaskManager.get_global_ptr() task_chain = task_mgr.make_task_chain("test_task_cancel_waiting") task_chain.set_num_threads(1) fut = core.AsyncFuture() async def task_main(task): # This will block the thread this task is in until the future is done, # or until the task is cancelled (which implicitly cancels the future). fut.result() return task.done task = core.PythonTask(task_main, 'task_main') task.set_task_chain(task_chain.name) task_mgr.add(task) task_chain.start_threads() try: assert not task.done() fut.cancel() task.wait() assert task.cancelled() assert fut.cancelled() finally: task_chain.stop_threads()
def test_future_timeout(): fut = core.AsyncFuture() with pytest.raises(TimeoutError): fut.result(0.001) # Works more than once with pytest.raises(TimeoutError): fut.result(0.001)
def test_future_shield(): # An already done future is returned as-is (no cancellation can occur) inner = core.AsyncFuture() inner.set_result(None) outer = core.AsyncFuture.shield(inner) assert inner == outer # Normally finishing future inner = core.AsyncFuture() outer = core.AsyncFuture.shield(inner) assert not outer.done() inner.set_result(None) assert outer.done() assert not outer.cancelled() assert inner.result() is None # Normally finishing future with result inner = core.AsyncFuture() outer = core.AsyncFuture.shield(inner) assert not outer.done() inner.set_result(123) assert outer.done() assert not outer.cancelled() assert inner.result() == 123 # Cancelled inner future does propagate cancellation outward inner = core.AsyncFuture() outer = core.AsyncFuture.shield(inner) assert not outer.done() inner.cancel() assert outer.done() assert outer.cancelled() # Finished outer future does nothing to inner inner = core.AsyncFuture() outer = core.AsyncFuture.shield(inner) outer.set_result(None) assert not inner.done() inner.cancel() assert not outer.cancelled() # Cancelled outer future does nothing to inner inner = core.AsyncFuture() outer = core.AsyncFuture.shield(inner) outer.cancel() assert not inner.done() inner.cancel() # Can be shielded multiple times inner = core.AsyncFuture() outer1 = core.AsyncFuture.shield(inner) outer2 = core.AsyncFuture.shield(inner) outer1.cancel() assert not inner.done() assert not outer2.done() inner.cancel() assert outer1.done() assert outer2.done()
def test_future_gather(): fut1 = core.AsyncFuture() fut2 = core.AsyncFuture() # 0 and 1 arguments are special assert core.AsyncFuture.gather().done() assert core.AsyncFuture.gather(fut1) == fut1 # Gathering not-done futures gather = core.AsyncFuture.gather(fut1, fut2) assert not gather.done() # One future done fut1.set_result(1) assert not gather.done() # Two futures done fut2.set_result(2) assert gather.done() assert not gather.cancelled() assert tuple(gather.result()) == (1, 2)
def test_future_cancelled(): fut = core.AsyncFuture() assert not fut.done() assert not fut.cancelled() fut.cancel() assert fut.done() assert fut.cancelled() with pytest.raises(CancelledError): fut.result() # Works more than once with pytest.raises(CancelledError): fut.result()
def test_future_done_callback(): fut = core.AsyncFuture() # Use the list hack since Python 2 doesn't have the "nonlocal" keyword. called = [False] def on_done(arg): assert arg == fut called[0] = True fut.add_done_callback(on_done) fut.cancel() assert fut.done() task_mgr = core.AsyncTaskManager.get_global_ptr() task_mgr.poll() assert called[0]
def test_future_done_callback_already_done(): # Same as above, but with the future already done when add_done_callback # is called. fut = core.AsyncFuture() fut.cancel() assert fut.done() # Use the list hack since Python 2 doesn't have the "nonlocal" keyword. called = [False] def on_done(arg): assert arg == fut called[0] = True fut.add_done_callback(on_done) task_mgr = core.AsyncTaskManager.get_global_ptr() task_mgr.poll() assert called[0]
def test_future_wait(): fut = core.AsyncFuture() # Launch a thread to set the result value. def thread_main(): time.sleep(0.001) fut.set_result(None) thread = threading.Thread(target=thread_main) assert not fut.done() thread.start() assert fut.result() is None assert fut.done() assert not fut.cancelled() assert fut.result() is None
def test_future_wait_timeout(): threading = pytest.importorskip("direct.stdpy.threading") fut = core.AsyncFuture() # Launch a thread to set the result value. def thread_main(): time.sleep(0.001) fut.set_result(None) thread = threading.Thread(target=thread_main) assert not fut.done() thread.start() assert fut.result(1.0) is None assert fut.done() assert not fut.cancelled() assert fut.result() is None
def test_future_wait_cancel(): fut = core.AsyncFuture() # Launch a thread to cancel the future. def thread_main(): time.sleep(0.001) fut.cancel() thread = threading.Thread(target=thread_main) assert not fut.done() thread.start() with pytest.raises(CancelledError): fut.result() assert fut.done() assert fut.cancelled() with pytest.raises(CancelledError): fut.result()
def test_coro_await_cancel_resistant_coro(): # Await another coro in a coro, but cancel the outer. fut = core.AsyncFuture() cancelled_caught = [0] keep_going = [False] async def cancel_resistant_coro(): while not fut.done(): try: await core.AsyncFuture.shield(fut) except CancelledError as ex: cancelled_caught[0] += 1 async def coro_main(): await cancel_resistant_coro() task = core.PythonTask(coro_main(), 'coro_main') task_mgr = core.AsyncTaskManager.get_global_ptr() task_mgr.add(task) assert not task.done() task_mgr.poll() assert not task.done() # No cancelling it once it started... for i in range(3): assert task.cancel() assert not task.done() for j in range(3): task_mgr.poll() assert not task.done() assert cancelled_caught[0] == 3 fut.set_result(None) task_mgr.poll() assert task.done() assert not task.cancelled()
def test_coro_await_coro(): # Await another coro in a coro. fut = core.AsyncFuture() async def coro2(): await fut async def coro_main(): await coro2() task = core.PythonTask(coro_main()) task_mgr = core.AsyncTaskManager.get_global_ptr() task_mgr.add(task) for i in range(5): task_mgr.poll() assert not task.done() fut.set_result(None) task_mgr.poll() assert task.done() assert not task.cancelled()
def test_future_result(): # Cancelled fut = core.AsyncFuture() assert not fut.done() fut.cancel() with pytest.raises(CancelledError): fut.result() # None fut = core.AsyncFuture() fut.set_result(None) assert fut.done() assert fut.result() is None # Store int fut = core.AsyncFuture() fut.set_result(123) assert fut.result() == 123 # Store string fut = core.AsyncFuture() fut.set_result("test\000\u1234") assert fut.result() == "test\000\u1234" # Store TypedWritableReferenceCount tex = core.Texture() rc = tex.get_ref_count() fut = core.AsyncFuture() fut.set_result(tex) assert tex.get_ref_count() == rc + 1 assert fut.result() == tex assert tex.get_ref_count() == rc + 1 assert fut.result() == tex assert tex.get_ref_count() == rc + 1 fut = None assert tex.get_ref_count() == rc # Store EventParameter (no longer gets unwrapped) ep = core.EventParameter(0.5) fut = core.AsyncFuture() fut.set_result(ep) assert fut.result() is ep assert fut.result() is ep # Store TypedObject dg = core.Datagram(b"test") fut = core.AsyncFuture() fut.set_result(dg) assert fut.result() == dg assert fut.result() == dg # Store arbitrary Python object obj = object() rc = sys.getrefcount(obj) fut = core.AsyncFuture() fut.set_result(obj) assert sys.getrefcount(obj) == rc + 1 assert fut.result() is obj assert sys.getrefcount(obj) == rc + 1 assert fut.result() is obj assert sys.getrefcount(obj) == rc + 1 fut = None assert sys.getrefcount(obj) == rc