Add a `Portal.cancel_actor()` test

infect_asyncio
Tyler Goodlet 2021-11-07 17:05:40 -05:00
parent 0ab5e5cadd
commit 56357242e9
2 changed files with 70 additions and 14 deletions

View File

@ -2,10 +2,15 @@
The most hipster way to force SC onto the stdlib's "async".
'''
from typing import Optional
import asyncio
import builtins
import importlib
import pytest
import trio
import tractor
from tractor import RemoteActorError
async def sleep_and_err():
@ -13,24 +18,78 @@ async def sleep_and_err():
assert 0
async def asyncio_actor():
assert tractor.current_actor().is_infected_aio()
async def sleep_forever():
await asyncio.sleep(float('inf'))
await tractor.to_asyncio.run_task(sleep_and_err)
async def asyncio_actor(
target: str,
expect_err: Optional[Exception] = None
) -> None:
assert tractor.current_actor().is_infected_aio()
target = globals()[target]
if '.' in expect_err:
modpath, _, name = expect_err.rpartition('.')
mod = importlib.import_module(modpath)
error = getattr(mod, name)
error = builtins.__dict__.get(expect_err)
try:
# spawn an ``asyncio`` task to run a func and return result
await tractor.to_asyncio.run_task(target)
except Exception as err:
if expect_err:
assert isinstance(err, error)
raise
def test_aio_simple_error(arb_addr):
'''
Verify a simple remote asyncio error propagates back through trio
to the parent actor.
'''
async def main():
async with tractor.open_nursery(
arbiter_addr=arb_addr
) as n:
await n.run_in_actor(
asyncio_actor,
target='sleep_and_err',
expect_err='AssertionError',
infect_asyncio=True,
)
with pytest.raises(RemoteActorError) as excinfo:
trio.run(main)
err = excinfo.value
assert isinstance(err, RemoteActorError)
assert err.type == AssertionError
def test_tractor_cancels_aio(arb_addr):
'''
Verify we can cancel a spawned asyncio task gracefully.
'''
async def main():
async with tractor.open_nursery() as n:
await n.run_in_actor(asyncio_actor, infected_asyncio=True)
portal = await n.run_in_actor(
asyncio_actor,
target='sleep_forever',
expect_err='asyncio.CancelledError',
infect_asyncio=True,
)
await portal.cancel_actor()
with pytest.raises(tractor.RemoteActorError) as excinfo:
tractor.run(main, arbiter_addr=arb_addr)
def test_aio_cancel_from_trio(arb_addr):
...
trio.run(main)
def test_aio_cancelled_from_aio_causes_trio_cancelled(arb_addr):
@ -49,10 +108,6 @@ def test_basic_interloop_channel_stream(arb_addr):
...
def test_basic_interloop_channel_stream(arb_addr):
...
def test_trio_cancels_and_channel_exits(arb_addr):
...

View File

@ -475,6 +475,7 @@ class Actor:
self._mods[modpath] = mod
if modpath == '__main__':
self._mods['__mp_main__'] = mod
except ModuleNotFoundError:
# it is expected the corresponding `ModuleNotExposed` error
# will be raised later