curio v0.6 Release Notes

Release Date: 2017-02-15 // almost 5 years ago
  • 02/13/2017 Added a withfd=True option to UniversalQueue. For example:

              q = UniversalQueue(withfd=True)
           If added, the queue internally sets up an I/O loopback
           where putting items on the queue write bytes to an I/O
           channel.  The queue then spouts a fileno() method and
           becomes pollable in other event loops.  This is potentially
           useful strategy for integrating Curio with GUIs and other
           kinds of foreign event loops.  

    02/11/2017 Added a guard for proper use of asynchronous generators involving asynchronous finalization. Must be wrapped by finalize(). For example:

           async def some_generator():
                   yield val
                   await action()
           async def coro():
               async with finalize(some_generator()) as agen:
                   async for item in agen:
           Failure to do this results in a RuntimeError if an
           asynchronous generator is iterated.   This is not needed for
           generators that don't perform finalization steps involving
           async code.

    02/08/2017 New method implementation. It should be backwards compatible, but there are two new ways of using it:

               kernel = Kernel()
               # Run a coroutine with a timeout/deadline applied to it
                   result =, timeout=secs)
               except TaskTimeout:
                   print('Timed out')
               # Run all daemonic tasks through a single scheduling cycle
               # with no blocking
               # Run all daemonic tasks through a cycle, but specify a
               # timeout on internal blocking

    02/06/2017 New aside() function for launching a Curio task in an independent process. For example:

           async def child(name, n):
               print('Hello from', name)
               for i in range(n):
                   print('name says', i)
                   await sleep(1)
           async def main():
               t = await aside(child, 'Spam', 10)   # Runs in subprocess
               await t.join()
           In a nutshell, aside(coro, *args, **kwargs) creates a clean
           Python interpreter and invokes*args,
           **kwargs)) on the supplied coroutine.  The return value of
           aside() is a Task object.  Joining with it returns the
           child exit code (normally 0).  Cancelling it causes a
           TaskCancelled exception to be raised in the child.
           aside() does not involve a process fork or pipe. There
           is no underlying communication between the child and parent
           process.  If you want communication, use a Channel object 
           or set up some other kind of networking.

    02/06/2017 Some improvements to message passing and launching tasks in subprocesses. A new Channel object makes it easy to establish message passing between two different interpreters. For example, here is a producer program:

           from curio import Channel, run
           async def producer(ch):
               while True:
                   c = await ch.accept(authkey=b'peekaboo')
                   for i in range(10):
                       await c.send(i)
                   await c.send(None)   # Sentinel
           if __name__ == '__main__':
               ch = Channel(('localhost', 30000))
           Here is a consumer program::
           from curio import Channel, run
           async def consumer(ch):
               c = await ch.connect(authkey=b'peekaboo')
               while True:
                   msg = await c.recv()
                   if msg is None:
                   print('Got:', msg)
           if __name__ == '__main__':
              ch = Channel(('localhost', 30000))
           A Channel is a lot like a socket except that it sends discrete
           messages.   Any picklable Python compatible object can be

    🛠 02/03/2017 Fixed a few regressions in SSL sockets and the method.