Meet aiotools

137 views
Skip to first unread message

Joongi Kim

unread,
Apr 17, 2017, 11:02:19 PM4/17/17
to aio-libs
While refactoring my company projects, I have created a small project that contains common patterns for asyncio, called "aiotools"
It offers two features currently: async timers and async ocntext managers.

This repository serves as an experiment room for me when I first try to apply CI tools such as codecov.
My experiences here will be back-ported to aiodocker as well as my company projects.

Please feel free to propose any ideas and PRs to add to aiotools!

Amirouche Boubekki

unread,
Jun 15, 2017, 1:21:28 PM6/15/17
to aio-libs

aiotools


PyPI version Python Versions Build Status Code Coverage

Idiomatic asyncio utilties


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 myserver(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(myserver, num_proc=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

Amirouche Boubekki

unread,
Jun 15, 2017, 1:27:37 PM6/15/17
to aio-libs


On Tuesday, April 18, 2017 at 5:02:19 AM UTC+2, Joongi Kim wrote:
 
While refactoring my company projects,

Kuddoz!
 
I have created a small project that contains common patterns for asyncio, called "aiotools"
It offers two features currently:
 
async timers

Can you explain what's the point of timers? it's like JavaScript window.setTimeout or it's like javaiscript's window.setInterval?
 
and async ocntext managers.

Very good idea! I am wondering why it is this not included in Python stdlib. That said, I don't like the naming of the function 'actxmgr' it's a difficult variable name to read.

Regarding async server, I am not sure what you are talking about. What is a very simple equivalance in code in plain asyncio?

Maybe I could read the code instead...

Thanks for sharing

+fav +watch

Joongi Kim

unread,
Jun 20, 2017, 10:31:56 PM6/20/17
to aio-libs


2017년 6월 16일 금요일 오전 2시 27분 37초 UTC+9, Amirouche Boubekki 님의 말:


On Tuesday, April 18, 2017 at 5:02:19 AM UTC+2, Joongi Kim wrote:
 
While refactoring my company projects,

Kuddoz!
 
I have created a small project that contains common patterns for asyncio, called "aiotools"
It offers two features currently:
 
async timers

Can you explain what's the point of timers? it's like JavaScript window.setTimeout or it's like javaiscript's window.setInterval?
 

It's like window.setInterval.
 
and async ocntext managers.

Very good idea! I am wondering why it is this not included in Python stdlib. That said, I don't like the naming of the function 'actxmgr' it's a difficult variable name to read.


In the future releases of Python stdlib will have the equivalent one (bpo-29679), so in that case aiotools.actxmgr will become an alias of it.
 
Regarding async server, I am not sure what you are talking about. What is a very simple equivalance in code in plain asyncio?
 
Maybe I could read the code instead...

It's for simplifying server intiailization and shutdown steps with a single async context manager.
Often we need to keep reference to server sockets, and holding such references in a single function scope helps a lot to write less bug-prone and easy-to-read codes.
Additionally it extends the same init/shutdown steps to multiple processes by automatically spawning child processes and new event loops inside them.
So you can easily write multi-core scalable asyncio server program, as long as external resources (e.g., DB) are synchronized (e.g., via transactions) and there is no shared states outside each event loop.
Reply all
Reply to author
Forward
0 new messages