Skip to main content

aioloop-proxy

A proxy for asyncio.AbstractEventLoop for 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 provides loop proxy class that fully implements asyncio.AbstractEventLoop interface 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 with unittest and pytest easily (the actual integraion is out of the project scope).

Installation

pip install aioloop-proxy

Usage

import 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 methods

LoopProxy implements all asyncio.AbstractEventLoop public methods. Additionally, it provides two proxy-specific ones: loop.check_and_shutdown() and loop.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.

kind is a enum.Flag described 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 | WRITERS

All 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 corresponding kind is 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 raise TimeoutError after 15 minute timeout. It can be done by shifting the 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 task is resumed immediatelly because the test wall-clock is 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 by proxy.call_later() or proxy.call_at() methods.

Release files for aioloop-proxy 0.0.13

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aioloop-proxy 0.0.13
File Size Uploaded
aioloop-proxy-0.0.13.tar.gz 41.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aioloop-proxy 0.0.13
File Interpreter ABI Platform
aioloop_proxy-0.0.13-py3-none-any.whl Python 3 none any Details

Total release size: 63.8 kB

Release files / aioloop-proxy-0.0.13.tar.gz

Download URL aioloop-proxy-0.0.13.tar.gz
Size 41.2 kB
Tags Source
SHA-256 checksum
How to use checksums
48ef40cb70de5884fe10178d3c78f658d4058bc78411c0c050ac5b045a7b518d
BLAKE2b-256 checksum
How to use checksums
a89d90a5c96d5b9cd86a6fb5dcd1cdb09fc66dfde1834eda859894c66f5859f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.7.1 importlib_metadata/4.10.1 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.10

Release files / aioloop_proxy-0.0.13-py3-none-any.whl

Download URL aioloop_proxy-0.0.13-py3-none-any.whl
Size 22.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aeb5388f046abafc7fd4a676bf254eea48bc193e08278b0e490ddbf079d1b6eb
BLAKE2b-256 checksum
How to use checksums
db8164e44a7a152135da431f5e304f560de5a0a44837f44c9f983dddfe6d45f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.7.1 importlib_metadata/4.10.1 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.10

Release history Release notifications | RSS feed

This release

0.0.13 This release

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page