async def test_returns_currently_running_event_loop_py36orless_compat( self, mocker, event_loop): spy_get_event_loop = mocker.spy(asyncio, "_get_running_loop") result = asyncio_compat.get_running_loop() assert result == event_loop assert spy_get_event_loop.call_count == 1 assert spy_get_event_loop.call_args == mocker.call()
def __init__(self, callback): """Creates an instance of an AwaitableCallback from a callback function. :param callback: Callback function to be made awaitable. """ loop = asyncio_compat.get_running_loop() self.future = asyncio_compat.create_future(loop) def wrapping_callback(*args, **kwargs): result = callback(*args, **kwargs) # Use event loop from outer scope, since the threads it will be used in will not have # an event loop. future.set_result() has to be called in an event loop or it does not work. loop.call_soon_threadsafe(self.future.set_result, result) return result self.callback = wrapping_callback
def __init__(self, return_arg_name=None): """Creates an instance of an AwaitableCallback """ # LBYL because this mistake doesn't cause an exception until the callback # which is much later and very difficult to trace back to here. if return_arg_name and not isinstance(return_arg_name, str): raise TypeError("internal error: return_arg_name must be a string") loop = asyncio_compat.get_running_loop() self.future = asyncio_compat.create_future(loop) def wrapping_callback(*args, **kwargs): # Use event loop from outer scope, since the threads it will be used in will not have # an event loop. future.set_result() and future.set_exception have to be called in an # event loop or they do not work. if "error" in kwargs and kwargs["error"]: exception = kwargs["error"] elif return_arg_name: if return_arg_name in kwargs: exception = None result = kwargs[return_arg_name] else: raise TypeError( "internal error: excepected argument with name '{}', did not get" .format(return_arg_name)) else: exception = None result = None if exception: # Do not use exc_info parameter on logger.error. This casuses pytest to save the traceback which saves stack frames which shows up as a leak logger.error( "Callback completed with error {}".format(exception)) logger.error( traceback.format_exception_only(type(exception), exception)) loop.call_soon_threadsafe(self.future.set_exception, exception) else: logger.debug( "Callback completed with result {}".format(result)) loop.call_soon_threadsafe(self.future.set_result, result) self.callback = wrapping_callback
async def async_fn_wrapper(*args, **kwargs): loop = asyncio_compat.get_running_loop() # Run fn in default ThreadPoolExecutor (CPU * 5 threads) return await loop.run_in_executor( None, functools.partial(fn, *args, **kwargs))
async def test_raises_runtime_error_if_no_running_event_loop_py36orless_compat(self, mocker): mocker.patch.object(asyncio, "_get_running_loop", return_value=None) with pytest.raises(RuntimeError, message="Expecting Runtime Error"): asyncio_compat.get_running_loop()
async def test_raises_runtime_error_if_no_running_event_loop(self, mocker): mocker.patch.object(asyncio, "get_running_loop", side_effect=RuntimeError) with pytest.raises(RuntimeError): asyncio_compat.get_running_loop()