async def test_local_cleanup(): """ Tests that local cleans up dead threads and tasks """ # Set up the local test_local = Local() # Assign in a thread class TestThread(threading.Thread): def run(self): test_local.foo = 456 thread = TestThread() thread.start() thread.join() # Assign in a Task async def test_task(): test_local.foo = 456 test_future = asyncio.ensure_future(test_task()) await test_future # Check there are two things in the storage assert len(test_local._storage) == 2 # Force cleanup test_local._last_cleanup = 0 test_local.foo = 1 # There should now only be one thing (this task) in the storage assert len(test_local._storage) == 1
async def test_local_many_layers(): """ Tests that local carries through a lot of layers of sync/async """ # Set up the local test_local = Local() test_local.foo = 8374 # Make sure we go between each world at least twice def sync_function(): async def async_function(): def sync_function_2(): async def async_function_2(): assert test_local.foo == 8374 test_local.foo = "miracles" async_to_sync(async_function_2)() await sync_to_async(sync_function_2)() async_to_sync(async_function)() await sync_to_async(sync_function)() # Check the value passed out again assert test_local.foo == "miracles"
async def test_local_task_to_sync(): """ Tests that local carries through sync_to_async """ # Set up the local test_local = Local() test_local.foo = 3 # Look at it in a sync context def sync_function(): assert test_local.foo == 3 test_local.foo = "phew, done" await sync_to_async(sync_function)() # Check the value passed out again assert test_local.foo == "phew, done"
def test_local_thread_to_async(): """ Tests that local carries through async_to_sync """ # Set up the local test_local = Local() test_local.foo = 12 # Look at it in an async context async def async_function(): assert test_local.foo == 12 test_local.foo = "inside" async_to_sync(async_function)() # Check the value passed out again assert test_local.foo == "inside"
def test_local_thread(): """ Tests that local works just inside a normal thread context """ test_local = Local() # Unassigned should be an error with pytest.raises(AttributeError): test_local.foo # Assign and check it persists test_local.foo = 2 assert test_local.foo == 2 # Delete and check it errors again del test_local.foo with pytest.raises(AttributeError): test_local.foo
def test_local_critical_no_thread_to_task(): """ Tests that local does not go through async_to_sync when the local is set as thread-critical """ # Set up the local test_local = Local(thread_critical=True) test_local.foo = 89 # Look at it in an async context async def async_function(): with pytest.raises(AttributeError): test_local.foo test_local.foo = "numbers" assert test_local.foo == "numbers" async_to_sync(async_function)() # Check the value outside assert test_local.foo == 89
async def test_local_critical_no_task_to_thread(): """ Tests that local doesn't go through sync_to_async when the local is set as thread-critical. """ # Set up the local test_local = Local(thread_critical=True) test_local.foo = 86 # Look at it in a sync context def sync_function(): with pytest.raises(AttributeError): test_local.foo test_local.foo = "secret" assert test_local.foo == "secret" await sync_to_async(sync_function)() # Check the value outside is not touched assert test_local.foo == 86
async def test_local_task_to_sync_to_task(): """ Tests that local carries through sync_to_async and then back through async_to_sync """ # Set up the local test_local = Local() test_local.foo = 756 # Look at it in an async context inside a sync context def sync_function(): async def async_function(): assert test_local.foo == 756 test_local.foo = "dragons" async_to_sync(async_function)() await sync_to_async(sync_function)() # Check the value passed out again assert test_local.foo == "dragons"
def test_local_thread_nested(): """ Tests that local does not leak across threads """ test_local = Local() # Unassigned should be an error with pytest.raises(AttributeError): test_local.foo print("outside ID", Local._get_context_id()) # Assign and check it does not persist inside the thread class TestThread(threading.Thread): # Failure reason failed = "unknown" def run(self): print("inside ID", Local._get_context_id()) # Make sure the attribute is not there try: test_local.foo self.failed = "leak inside" return except AttributeError: pass # Check the value is good self.failed = "set inside" test_local.foo = 123 assert test_local.foo == 123 # Binary signal that these tests passed to the outer thread self.failed = "" test_local.foo = 8 thread = TestThread() thread.start() thread.join() assert thread.failed == "" # Check it didn't leak back out assert test_local.foo == 8