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.