This release has two breaking changes, and is otherwise characterized by a lot of hardening in cases of misbehaving coroutines.
Breaking changes
-
tinyio.as_completedis now used as:iterator = yield tinyio.as_completed({coro1, coro2, coro3}) for next_coro in iterator: result = yield next_coro
instead of manually polling
.donein a while loop. -
tinyio.from_triois now used astinyio.from_trio(coro)instead oftinyio.from_trio(fn, *args), which is now consistent with the rest of the tinyio API.
Bugfixes
- If a coroutine does not respond properly to
.throw(e.g. ignores it instead of shutting down) then this will no longer cause undefined behaviour of the loop (I have no idea what would have happened before), and a warning will be thrown. - The tinyio<>trio and tinyio<>asyncio integrations will now propagate exceptions raised on either side of the integration, shutting coroutines down appropriately.
- If using the (advanced)
tinyio.Loop().runtimeAPI, then we now detect cases in which the loop is not ran to completion and throw an appropriate error.
Usability
- Yielding an already-started generator will now raise an appropriate error.
- Nicer tracebacks under various circumstances.
Features
-
Added
tinyio.isolate(coro), which makes it possible to run a coroutine which may raise an error (or if any of its yielded coroutines raise an error). (Thanks @aburgm!)For the event loop geeks: this is basically equivalent to the existing tinyio<>{trio,asyncio} integrations, in which we have one event loop being a guest of another... except in this case it's one tinyio loop being a guest of another tinyio loop! The 'inner' loop becomes the boundary at which exceptions stop propagating, whilst the 'outer' loop handles the overall stepping of the system.
For everyone else: this is an advanced feature you probably don't need to worry about :)
Documentation
- Big documentation update, in particular describing how to set up async context managers and async iterators.
Full Changelog: v0.3.0...v0.4.0