Skip to main content

Idiomatic asyncio utilities

Project description

aiotools

PyPI version Python Versions Build Status Code Coverage

Idiomatic asyncio utilties

NOTE: This project is under early stage of developement. The public APIs may break version by version.

Async Context Manager

This is an asynchronous version of contextlib.contextmanager to make it easier to write asynchronous context managers without creating boilerplate classes.

import asyncio
import aiotools

@aiotools.actxmgr
async def mygen(a):
    await asyncio.sleep(1)
    yield a + 1
    await asyncio.sleep(1)

async def somewhere():
    async with mygen(1) as b:
        assert b == 2

Note that you need to wrap yield with a try-finally block to ensure resource releases (e.g., locks), even in the case when an exception is ocurred inside the async-with block.

import asyncio
import aiotools

lock = asyncio.Lock()

@aiotools.actxmgr
async def mygen(a):
    await lock.acquire()
    try:
        yield a + 1
    finally:
        lock.release()

async def somewhere():
    try:
        async with mygen(1) as b:
            raise RuntimeError('oops')
    except RuntimeError:
        print('caught!')  # you can catch exceptions here.

You can also create a group of async context managers, which are entered/exited all at once using asyncio.gather().

import asyncio
import aiotools

@aiotools.actxmgr
async def mygen(a):
    yield a + 10

async def somewhere():
    ctxgrp = aiotools.actxgroup(mygen(i) for i in range(10))
    async with ctxgrp as values:
        assert len(values) == 10
        for i in range(10):
            assert values[i] == i + 10

Async Server

This implements a common pattern to launch asyncio-based server daemons.

import asyncio
import aiotools

async def echo(reader, writer):
    data = await reader.read(100)
    writer.write(data)
    await writer.drain()
    writer.close()

@aiotools.actxmgr
async def myworker(loop, pidx, args):
    server = await asyncio.start_server(echo, '0.0.0.0', 8888,
        reuse_port=True, loop=loop)
    print(f'[{pidx}] started')
    yield  # wait until terminated
    server.close()
    await server.wait_closed()
    print(f'[{pidx}] terminated')

if __name__ == '__main__':
    # Run the above server using 4 worker processes.
    aiotools.start_server(myworker, num_workers=4)

It handles SIGINT/SIGTERM signals automatically to stop the server, as well as lifecycle management of event loops running on multiple processes.

Async Timer

import aiotools

i = 0

async def mytick(interval):
    print(i)
    i += 1

async def somewhere():
    t = aiotools.create_timer(mytick, 1.0)
    ...
    t.cancel()
    await t

t is an asyncio.Task object. To stop the timer, call t.cancel(); await t. Please don’t forget await-ing t because it requires extra steps to cancel and await all pending tasks. To make your timer function to be cancellable, add a try-except clause catching asyncio.CancelledError since we use it as a termination signal.

You may add TimerDelayPolicy argument to control the behavior when the timer-fired task takes longer than the timer interval. DEFAULT is to accumulate them and cancel all the remainings at once when the timer is cancelled. CANCEL is to cancel any pending previously fired tasks on every interval.

import asyncio
import aiotools

async def mytick(interval):
    await asyncio.sleep(100)  # cancelled on every next interval.

async def somewhere():
    t = aiotools.create_timer(mytick, 1.0, aiotools.TimerDelayPolicy.CANCEL)
    ...
    t.cancel()
    await t

Changelog

0.4.3 (2017-08-06)

  • Add aclosing() context manager like closing() in the standard library

  • Speed up Travis CI builds for packaging

  • Now provide README in rst as well as CHANGES (this file)

0.4.2 (2017-08-01)

  • server: Fix spawning subprocesses in child workers

  • Add support for uvloop

0.4.0 (2017-08-01)

  • Add use_threading argument to

  • Add initial documentation (which currently not served on readthedocs.io due to Python version problem)

0.3.2 (2017-07-31)

  • Add extra_procs argument to start_server() function

  • Add socket and ZeroMQ server examples

  • Improve CI configs

0.3.1 (2017-07-26)

  • Improve CI scripts

  • Adopt editorconfig

0.3.0 (2017-04-26)

  • Add start_server() function using multiprocessing with automatic children lifecycle management

  • Clarify the semantics of AsyncContextGroup using asyncio.gather() with return_exceptions=True

0.2.0 (2017-04-20)

  • Add abstract types for AsyncContextManager

  • Rename AsyncGenContextManager to AsyncContextManager

  • Add AsyncContextGroup

0.1.1 (2017-04-14)

  • Initial release

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aiotools-0.4.3.tar.gz (9.8 kB view details)

Uploaded Source

Built Distribution

aiotools-0.4.3-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

File details

Details for the file aiotools-0.4.3.tar.gz.

File metadata

  • Download URL: aiotools-0.4.3.tar.gz
  • Upload date:
  • Size: 9.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for aiotools-0.4.3.tar.gz
Algorithm Hash digest
SHA256 60df778df8017347afd803386f36aee5d18718eab113e692e1b0f028b908b2a0
MD5 36ca9dd4d88e6ae847f1a771cb2c3255
BLAKE2b-256 659459c66498df1f6452d5b48853a6ba20cbea726036b6a61be8cd5972c7da2f

See more details on using hashes here.

Provenance

File details

Details for the file aiotools-0.4.3-py3-none-any.whl.

File metadata

File hashes

Hashes for aiotools-0.4.3-py3-none-any.whl
Algorithm Hash digest
SHA256 bfd80ab724858e2d20dd8dcf685088b8cc5436bb6c3e1725c69232e69b55ccef
MD5 36fda17eada5042d8ad0315f9f797251
BLAKE2b-256 65e96d8c51d9fa88da199213eec85e3f20b0c7667e59e8f06ac6074dc1205f74

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page