forked from goodboy/tractor
Add a `Portal.cancel_actor()` test
parent
0ab5e5cadd
commit
56357242e9
|
@ -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):
|
||||
...
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue