curio v0.9 Release Notes

Release Date: 2018-03-10 // about 6 years ago
  • 0๏ธโƒฃ 02/24/2018 Refinements to Task crash reporting. By default all Tasks that terminate with an uncaught exception log that exception as soon as it is detected. Although there is a risk that this creates extra output, silencing the output makes it almost impossible to debug programs. This is because errors get deferred to a later join() method---and you often don't know when that's going to take place. You might just be staring a program wondering why it's not working. If you really want errors to be silent, use spawn(coro, report_crash=False).

    02/23/2018 Some refinements to the AWAIT() function. You can now call it as follows:

               result = AWAIT(callable, *args, **kwargs)
    
           If the passed callable is a coroutine function or a function that
           produces an awaitable object, it will be passed to Curio and executed
           in an asynchronous context.   If callable is just a normal function,
           then callable(*args, **kwargs) is returned.
    
           This change is made to make it slightly easier to use objects
           as UniversalQueue within the context of an async thread.  For example,
           if you do this::
    
               q = UniversalQueue()
               ...
               @async_thread
               def consumer():
                   while True:
                       item = AWAIT(q.get)
                       print("Got:", item)
    
            The AWAIT operation will run the asynchronous version of q.get()
            instead of the normal synchronous version.  You want this--the
            async version supports cancellation and other nice features.
    

    02/22/2018 The async_thread() function is now meant to be used as a decorator only.

              @async_thread
              def func(args):
                  ...
    
           When the decorated function is called from asynchronous code using
           await func(args), it will seamlessly run in a separate execution thread.
           However, the function can also be called from synchronous code using
           func(args).  In that case, the function runs as it normally does.
           It's subtle, but the @async_thread decorator allows a function to adapt
           to either a synchronous or asynchronous environment depending on how 
           it has been called. 
    

    02/22/2018 New function spawn_thread() can be used to launch asynchronous threads. It mirrors the use of the spawn() function. For example:

              def func(args):
                  ...
    
              t = await spawn_thread(func, args)
              result = await t.join()
    
           Previously, async threads were created using the AsyncThread class.
           That still works, but the spawn_thread() function is probably easier.
    
           The launched function must be a normal synchronous function. 
           spawn_thread() can also be used as a context manager (see below).
    

    02/19/2018 Added ability of async threads to be created via context manager. For example:

              async with spawn_thread():
                  # Various blocking/synchronous operations
                  # Executes in a separate thread
                  ...
    
           When used, the body of the context manager runs in a
           separate thread and may involve blocking operations.
           However, be aware that any use of async/await is NOT
           allowed in such a block.  Any attempt to await on an async
           function inside the block will result in a RuntimeError
           exception. 
    

    02/06/2018 Refinements to the schedular activation API and debugging features.

    ๐Ÿšš 02/04/2018 The ZMQ module has been removed from Curio core and put into the examples directory. This should be spun into a separate package maintained independently of Curio.

    ๐Ÿšš 02/03/2018 Local() objects have been removed. The idea of having a thread-local style object for storing attributes is fraught with problems--especially given the potential mix of tasks, threads, and processes that is possible in Curio. The implementation of this has been moved into the examples directory where it can be adapted/copied into your code if it's still needed. Better yet, maybe take a look at PEP 567.

    ๐Ÿ”จ 02/02/2018 Some refactoring and simplification of the kernel run() method. First, run() only executes as long as the submitted coroutine is active. Upon termination, run() immediately returns regardless of whether or not other tasks are still running. Curio was already generating warning messages for orphaned tasks--tasks for which Task.join() is never invoked. As such, this change should not affect most properly written applications.

           Second, the timeout argument is no longer supported. If
           you want a timeout on what's happening, put it into the 
           supplied async function itself.
    
           Finally, if Kernel.run() is called with no arguments, it
           causes the kernel to process any activity that might be
           pending at that moment in time before returning.  This is
           something that might be useful should it be necessary
           to integrate Curio with a foreign event-loop.
    

    ๐Ÿ‘ป 01/31/2018 If the main task crashes with an exception, the kernel now returns immediately--even if child tasks are still in progress. This prevents a problem where the main task crashes, but it's not reported for an extended period due to child tasks continuing to run. In addition, if the main task crashes, the kernel does not perform a shutdown-- leaving tasks as they were at the time of the crash. This might facilitate debugging.

    ๐Ÿ–จ 01/31/2018 Printing a Task object will now show the file and line number of where it's currently waiting.

    01/23/2018 A refinement in task crash reporting. Previously, all task crashes were logged. However, Curio was also logging crashes in all unjoined tasks. Sometimes this would result in duplicate tracebacks. It's been modified to now only report crashes in unjoined tasks. If joining, it's assumed that the exception would be noticed there.

    01/22/2018 Semaphore and BoundedSemaphore now exposes a read-only property ".value" that gives the current Semaphore value. BoundedSemaphore objects expose a ".bound" property that gives the upper bound.

    ๐Ÿ—„ 01/03/2018 The Local() object has been officially deprecated in the documentation and will be removed at some point. Implementing task-level locals is much more complicated than it seems at first glance and there is discussion of a more general solution in PEP 567. If you need this kind of functionality, you should copy the task local code into your own application.

    ๐Ÿšš 12/22/2017 writeable() method of Socket removed. Use of this was highly specialized and potentially confusing since it's not normally needed. Use await _write_wait(sock) if you need to wait for a socket to be writable before calling send().

    12/19/2017 Slight change to Task Groups that allow tasks to spawn other tasks into the same group. See Issue #239.

    09/15/2017 Added the .readinto() method onto async files.

    09/15/2017 Made the @async_thread decorator return the actual exception that gets raised in the event of a failure. This makes it more like a normal function call. Previously, it was returning a TaskError exception for any crash. That's a bit weird since the use of threads or spawning of an external task is meant to be more implicit.