async def taskfunc() -> None: nonlocal got_past_checkpoint with CancelScope() as scope1: with CancelScope() as scope2: with CancelScope(shield=True): scope1.cancel() scope2.cancel() await checkpoint() got_past_checkpoint = True
async def test_nested_shield() -> None: async def killer(scope: CancelScope) -> None: await wait_all_tasks_blocked() scope.cancel() with pytest.raises(TimeoutError): async with create_task_group() as tg: with CancelScope() as scope: with CancelScope(shield=True): tg.start_soon(killer, scope) with fail_after(0.2): await sleep(2)
async def test_removed_interface_generator(backend, events): scanner = NetworkEventDetector(backend=backend) async def scenario(end): backend.add("foo") await sleep(0.003) assert events.get() == [] backend.add("bar") backend.add("bar") backend.add("bar") await sleep(0.003) assert events.get() == [] backend.remove("bar") backend.add("baz") await sleep(0.003) assert events.get() == ["bar"] backend.remove("foo") backend.remove("baz") await sleep(0.003) assert sorted(events.get()) == ["baz", "foo"] end() async with create_task_group() as tg: with CancelScope() as scope: tg.start_soon(scenario, scope.cancel) async for interface in scanner.removed_interfaces(): events.add(interface)
async def test_escaping_cancelled_error_from_cancelled_task() -> None: """Regression test for issue #88. No CancelledError should escape the outer scope.""" with CancelScope() as scope: with move_on_after(0.1): await sleep(1) scope.cancel()
async def test_cancelscope_wrong_exit_order() -> None: """ Test that a RuntimeError is raised if the task tries to exit cancel scopes in the wrong order. """ scope1 = CancelScope() scope2 = CancelScope() scope1.__enter__() scope2.__enter__() pytest.raises(RuntimeError, scope1.__exit__, None, None, None)
async def test_nested_fail_after() -> None: async def killer(scope: CancelScope) -> None: await wait_all_tasks_blocked() scope.cancel() async with create_task_group() as tg: with CancelScope() as scope: with CancelScope(): tg.start_soon(killer, scope) with fail_after(1): await sleep(2) pytest.fail("Execution should not reach this point") pytest.fail("Execution should not reach this point either") pytest.fail("Execution should also not reach this point") assert scope.cancel_called
async def test_cancel_before(): """ Test that starting to_process.run_sync() in a cancelled scope does not cause a worker process to be reserved. """ with CancelScope() as scope: scope.cancel() await to_process.run_sync(os.getpid) pytest.raises(LookupError, to_process._process_pool_workers.get)
async def test_cancel_from_shielded_scope() -> None: async with create_task_group() as tg: with CancelScope(shield=True) as inner_scope: assert inner_scope.shield tg.cancel_scope.cancel() with pytest.raises(get_cancelled_exc_class()): await sleep(0.01) with pytest.raises(get_cancelled_exc_class()): await sleep(0.01)
async def task(task_status: TaskStatus) -> NoReturn: nonlocal completed with CancelScope() as scope: # Enable the shield a little after the scope starts to make this test # general, even though it has no bearing on the current implementation. await sleep(0.1) scope.shield = True task_status.started() await sleep(0.1) completed = True scope.shield = False await sleep(1) pytest.fail("Execution should not reach this point")
async def test_shielding_immediate_scope_cancelled() -> None: async def cancel_when_ready() -> None: await wait_all_tasks_blocked() scope.cancel() sleep_completed = False async with create_task_group() as tg: with CancelScope(shield=True) as scope: tg.start_soon(cancel_when_ready) await sleep(0.5) sleep_completed = True assert not sleep_completed
async def host_task() -> None: nonlocal done async with create_task_group() as tg: with CancelScope(shield=True) as inner_scope: assert inner_scope.shield tg.cancel_scope.cancel() with pytest.raises(get_cancelled_exc_class()): await sleep(0) with pytest.raises(get_cancelled_exc_class()): await sleep(0) done = True
async def test_cancelscope_exit_in_wrong_task() -> None: async def enter_scope(scope: CancelScope) -> None: scope.__enter__() async def exit_scope(scope: CancelScope) -> None: scope.__exit__(None, None, None) scope = CancelScope() async with create_task_group() as tg: tg.start_soon(enter_scope, scope) with pytest.raises(RuntimeError): async with create_task_group() as tg: tg.start_soon(exit_scope, scope)
async def test_event_generator_suspension(backend, events): scanner = NetworkEventDetector(backend=backend) async def scenario(end): with scanner.suspended(): await sleep(0.003) backend.add("foo") await sleep(0.003) assert events.get() == [] backend.add("bar") backend.add("bar") backend.add("bar") await sleep(0.003) assert events.get() == [] backend.remove("bar") backend.add("baz") await sleep(0.003) assert events.get() == [] await sleep(0.003) assert sorted(events.get()) == [ ("interface_added", "baz", "baz_key"), ("interface_added", "foo", "foo_key"), ] backend.remove("foo") backend.remove("baz") await sleep(0.003) assert sorted(events.get()) == [ ("interface_removed", "baz", "baz_key"), ("interface_removed", "foo", "foo_key"), ] end() async with create_task_group() as tg: with CancelScope() as scope: tg.start_soon(scenario, scope.cancel) async for event in scanner.events(): events.add((event.type.value, event.interface, event.key))
async def test_receive_when_cancelled() -> None: """ Test that calling receive() in a cancelled scope prevents it from going through with the operation. """ send, receive = create_memory_object_stream() async with create_task_group() as tg: tg.start_soon(send.send, "hello") await wait_all_tasks_blocked() tg.start_soon(send.send, "world") await wait_all_tasks_blocked() with CancelScope() as scope: scope.cancel() await receive.receive() assert await receive.receive() == "hello" assert await receive.receive() == "world"
async def test_send_when_cancelled(): """ Test that calling send() in a cancelled scope prevents it from going through with the operation. """ async def receiver(): received.append(await receive.receive()) received = [] send, receive = create_memory_object_stream() async with create_task_group() as tg: tg.start_soon(receiver) with CancelScope() as scope: scope.cancel() await send.send('hello') await send.send('world') assert received == ['world']
async def test_cancel_during_acquire(self, release_first: bool) -> None: acquired = False async def task(*, task_status: TaskStatus) -> None: nonlocal acquired task_status.started() async with lock: acquired = True lock = Lock() async with create_task_group() as tg: await lock.acquire() await tg.start(task) tg.cancel_scope.cancel() with CancelScope(shield=True): if release_first: lock.release() await wait_all_tasks_blocked() else: await wait_all_tasks_blocked() lock.release() assert not acquired assert not lock.locked()
async def test_cancel_during_acquire(self, release_first: bool) -> None: acquired = False async def task(*, task_status: TaskStatus) -> None: nonlocal acquired task_status.started() async with semaphore: acquired = True semaphore = Semaphore(1) async with create_task_group() as tg: await semaphore.acquire() await tg.start(task) tg.cancel_scope.cancel() with CancelScope(shield=True): if release_first: semaphore.release() await wait_all_tasks_blocked() else: await wait_all_tasks_blocked() semaphore.release() assert not acquired assert semaphore.value == 1
async def test_cancelscope_cancel(self) -> None: with CancelScope() as scope: with pytest.deprecated_call(): await scope.cancel()
async def scoped_receiver() -> None: nonlocal receiver_scope with CancelScope() as receiver_scope: received.append(await receive.receive()) assert receiver_scope.cancel_called
async def exit_scope(scope: CancelScope) -> None: scope.__exit__(None, None, None)
async def enter_scope(scope: CancelScope) -> None: scope.__enter__()
async def test_cancelscope_exit_before_enter() -> None: """Test that a RuntimeError is raised if one tries to exit a cancel scope before entering.""" scope = CancelScope() pytest.raises(RuntimeError, scope.__exit__, None, None, None)
async def child() -> NoReturn: with CancelScope(): await sleep(1) raise Exception("foo")
async def test_shielded_deadline() -> None: with move_on_after(10): with CancelScope(shield=True): with move_on_after(1000): assert current_effective_deadline() - current_time() > 900
async def killer(scope: CancelScope) -> None: await wait_all_tasks_blocked() scope.cancel()
async def test_cancel_scope(self) -> None: with CancelScope() as scope: await maybe_async(scope.cancel())
async def test_maybe_async_cm() -> None: async with maybe_async_cm(CancelScope()): pass
async def native_coro_part() -> None: with CancelScope() as scope: scope.cancel()
async def task(): nonlocal local_scope, acquired with CancelScope() as local_scope: async with semaphore: acquired = True
async def never_cancel_task() -> None: with CancelScope(shield=True): await sleep(0.2) await event.wait()