Package: aioloop-proxy
A proxy forasyncio.AbstractEventLoopfor testing purposes.When tests writing for asyncio based code, there are controversial requirements.First, a signle event loop for the whole test session (or test subset) is desired.  For
example, if web server starts slowly, there is a temptation to create a server only once
and access to the single web server instance from each test.Second, each test should be isolated.  It means that asyncio tasks (timers, connections,
etc.) created by test A should be finished at test A finalization and should not affect
test B execution.The library providesloop proxyclass that fully implementsasyncio.AbstractEventLoopinterface but redirects all actual work to the proxied
parent loop.  It allows to check that all activities created with the proxy are finished
on the proxy finalization. In turn, all tasks created with the parent loop are still
keep working during the proxy execution.Loop proxies can be nested, e.g. global-loop -> module-loop -> test-loop is supported.The library is test tool agnostic, e.g. it can be integrated withunittestandpytesteasily (the actual integraion is out of the project scope).Installationpip install aioloop-proxyUsageimport asyncio
import aioloop_proxy

loop = asyncio.new_event_loop()
server_addr = loop.run_until_complete(setup_and_run_test_server())
...

with aioloop_proxy(loop, strict=True) as loop_proxy:
   loop_proxy.run_until_complete(test_func(server_addr))Sure, each test system (unittest,pytest, name it) should not run the code
snippet above as-is but incorporate it as a dedicates test-case class or plugin.Extra loop methodsLoopProxyimplements allasyncio.AbstractEventLooppublic methods. Additionally,
it provides two proxy-specific ones:loop.check_and_shutdown()andloop.advance_time().await proxy.check_and_shutdown(kind=CheckKind.ALL)can be used for checking if
the proxy finished without active tasks, open transports etc.kindis aenum.Flagdescribed as the following:class CheckKind(enum.Flag):
    TASKS = enum.auto()
    SIGNALS = enum.auto()
    SERVERS = enum.auto()
    TRANSPORTS = enum.auto()
    READERS = enum.auto()
    WRITERS = enum.auto()
    HANDLES = enum.auto()

    ALL = TASKS | SIGNALS | SERVERS | TRANSPORTS | READERS | WRITERSAll checks are performed by default.  A specific test can omit some check if it raises a
false positive warning.N.B.Dangling resources are always closed even if correspondingkindis omitted.
A proxy loop should cleanup all acquired resources at the test finish for the sake of
tests isolation principle.proxy.advance_time(offset)is a perk that helps with writing tests for scenarios
that uses timeouts, delays, etc.Let’s assume, we have a code that should read data from peer or raiseTimeoutErrorafter 15 minute timeout.  It can be done by shiftingthe proxy local time(proxy.time()returned value) to 15 minutes forward artificially:task = asyncio.create_task(fetch_or_timeout())
loop.advance_time(15 * 60)
try:
    await task
except TimeoutError:
    ...In the example above,await taskis resumed immediatelly because the testwall-clockis shifted by 15 minutes two lines above, and all timers created by the
proxy are adjusted accordingly.The parent loop wall-clock is not touched.The method complexity is O(N) where N is amount of active timers created byproxy.call_later()orproxy.call_at()methods.