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