Release history

Trio 0.10.0 (2019-01-07)



  • Fixed a race condition on macOS, where Trio’s TCP listener would crash if an incoming TCP connection was closed before the listener had a chance to accept it. (#609)
  • trio.open_tcp_stream() has been refactored to clean up unsuccessful connection attempts more reliably. (#809)

Deprecations and Removals

  • Remove the APIs deprecated in 0.5.0. (ClosedStreamError, ClosedListenerError, Result) (#812)

Miscellaneous internal changes

  • There are a number of methods on trio.ssl.SSLStream that report information about the negotiated TLS connection, like selected_alpn_protocol, and thus cannot succeed until after the handshake has been performed. Previously, we returned None from these methods, like the stdlib ssl module does, but this is confusing, because that can also be a valid return value. Now we raise trio.ssl.NeedHandshakeError instead. (#735)

Trio 0.9.0 (2018-10-12)


  • New and improved APIs for inter-task communication:,, and trio.open_memory_channel() (which replaces trio.Queue). This interface uses separate “sender” and “receiver” objects, for consistency with other communication interfaces like Stream. Also, the two objects can now be closed individually, making it much easier to gracefully shut down a channel. Also, check out the nifty clone API to make it easy to manage shutdown in multiple-producer/multiple-consumer scenarios. Also, the API has been written to allow for future channel implementations that send objects across process boundaries. Also, it supports unbounded buffering if you really need it. Also, help I can’t stop writing also. See Using channels to pass values between tasks for more details. (#497)

Deprecations and Removals

Trio 0.8.0 (2018-10-01)


  • Trio’s default internal clock is now based on time.perf_counter() instead of time.monotonic(). This makes time-keeping more precise on Windows, and has no effect on other platforms. (#33)
  • Reworked trio, trio.testing, and trio.socket namespace construction, making them more understandable by static analysis tools. This should improve tab completion in editors, reduce false positives from pylint, and is a first step towards providing type hints. (#542)

Deprecations and Removals

Trio 0.7.0 (2018-09-03)



  • Prevent crashes when used with Sentry (raven-python). (#599)
  • The nursery context manager was rewritten to avoid use of @asynccontextmanager and @async_generator. This reduces extraneous frames in exception traces and addresses bugs regarding StopIteration and StopAsyncIteration exceptions not propagating correctly. (#612)
  • Updates the formatting of exception messages raised by trio.open_tcp_stream() to correctly handle a hostname passed in as bytes, by converting the hostname to a string. (#633)

Deprecations and Removals

  • trio.catch_signals has been deprecated in favor of open_signal_receiver(). The main differences are: it takes *-args now to specify the list of signals (so open_signal_receiver(SIGINT) instead of catch_signals({SIGINT})), and, the async iterator now yields individual signals, instead of “batches” (#354)
  • Remove all the APIs deprecated in 0.3.0 and 0.4.0. (#623)

Trio 0.6.0 (2018-08-13)



  • Make trio.socket._SocketType.connect always close the socket on cancellation (#247)
  • Fix a memory leak in trio.CapacityLimiter, that could occurr when acquire or acquire_on_behalf_of was cancelled. (#548)
  • Some version of macOS have a buggy getaddrinfo that was causing spurious test failures; we now detect those systems and skip the relevant test when found. (#580)
  • Prevent crashes when used with Sentry (raven-python). (#599)

Trio 0.5.0 (2018-07-20)


  • Suppose one task is blocked trying to use a resource – for example, reading from a socket – and while it’s doing this, another task closes the resource. Previously, this produced undefined behavior. Now, closing a resource causes pending operations on that resource to terminate immediately with a ClosedResourceError. ClosedStreamError and ClosedListenerError are now aliases for ClosedResourceError, and deprecated. For this to work, Trio needs to know when a resource has been closed. To facilitate this, new functions have been added: trio.hazmat.notify_fd_close() and trio.hazmat.notify_socket_close(). If you’re using Trio’s built-in wrappers like SocketStream or trio.socket, then you don’t need to worry about this, but if you’re using the low-level functions like trio.hazmat.wait_readable(), you should make sure to call these functions at appropriate times. (#36)
  • Tasks created by spawn_system_task() now no longer inherit the creator’s contextvars context, instead using one created at run(). (#289)
  • Add support for trio.Queue with capacity=0. Queue’s implementation is also faster now. (#473)
  • Switch to using standalone Outcome library for Result objects. (#494)

Deprecations and Removals

  • trio.hazmat.Result, trio.hazmat.Value and trio.hazmat.Error have been replaced by the equivalent classes in the Outcome library.

Trio 0.4.0 (2018-04-10)



  • Fix KeyboardInterrupt handling when threading state has been modified by a 3rd-party library. (#461)

Deprecations and Removals

Miscellaneous internal changes

Trio 0.3.0 (2017-12-28)


  • Simplified nurseries: In Trio, the rule used to be that “parenting is a full time job”, meaning that after a task opened a nursery and spawned some children into it, it had to immediately block in __aexit__ to supervise the new children, or else exception propagation wouldn’t work. Also there was some elaborate machinery to let you replace this supervision logic with your own custom supervision logic. Thanks to new advances in task-rearing technology, parenting is no longer a full time job! Now the supervision happens automatically in the background, and essentially the body of a async with trio.open_nursery() block acts just like a task running inside the nursery. This is important: it makes it possible for libraries to abstract over nursery creation. For example, if you have a Websocket library that needs to run a background task to handle Websocket pings, you can now do that with async with open_websocket(...) as ws: ..., and that can run a task in the background without your users having to worry about parenting it. And don’t worry, you can still make custom supervisors; it turned out all that spiffy machinery was actually redundant and didn’t provide much value. (#136)
  • Trio socket methods like bind and connect no longer require “pre-resolved” numeric addresses; you can now pass regular hostnames and Trio will implicitly resolve them for you. (#377)


  • Fixed some corner cases in Trio socket method implicit name resolution to better match stdlib behavior. Example: sock.bind(("", port)) now binds to the wildcard address instead of raising an error. (#277)

Deprecations and Removals

  • Removed everything that was deprecated in 0.2.0; see the 0.2.0 release notes below for details.
  • As was foretold in the v0.2.0 release notes, the bind method on Trio sockets is now async. Please update your calls or – better yet – switch to our shiny new high-level networking API, like serve_tcp(). (#241)
  • The resolve_local_address and resolve_remote_address methods on Trio sockets have been deprecated; these are unnecessary now that you can just pass your hostnames directly to the socket methods you want to use. (#377)

Trio 0.2.0 (2017-12-06)

Trio 0.2.0 contains changes from 14 contributors, and brings major new features and bug fixes, as well as a number of deprecations and a very small number of backwards incompatible changes. We anticipate that these should be easy to adapt to, but make sure to read about them below, and if you’re using Trio then remember to read and subscribe to issue #1.


Breaking changes and deprecations

Trio is a young and ambitious project, but it also aims to become a stable, production-quality foundation for async I/O in Python. Therefore, our approach for now is to provide deprecation warnings where-ever possible, but on a fairly aggressive cycle as we push towards stability. If you use Trio you should read and subscribe to issue #1. We’d also welcome feedback on how this approach is working, whether our deprecation warnings could be more helpful, or anything else.

The tl;dr is: stop using socket.bind if you can, and then fix everything your test suite warns you about.

Upcoming breaking changes without warnings (i.e., stuff that works in 0.2.0, but won’t work in 0.3.0):

  • In the next release, the bind method on Trio socket objects will become async (#241). Unfortunately, there’s no good way to provide a warning here. We recommend switching to the new highlevel networking APIs like serve_tcp(), which will insulate you from this change.

Breaking changes (i.e., stuff that could theoretically break a program that worked on 0.1.0):

  • trio.socket no longer attempts to normalize or modernize socket options across different platforms. The high-level networking API now handles that, freeing trio.socket to focus on giving you raw, unadulterated BSD sockets.
  • When a socket sendall call was cancelled, it used to attach some metadata to the exception reporting how much data was actually sent. It no longer does this, because in common configurations like an SSLStream wrapped around a SocketStream it becomes ambiguous which “level” the partial metadata applies to, leading to confusion and bugs. There is no longer any way to tell how much data was sent after a sendall is cancelled.
  • The trio.socket.getprotobyname() function is now async, like it should have been all along. I doubt anyone will ever use it, but that’s no reason not to get the details right.
  • The trio.socket functions getservbyport, getservbyname, and getfqdn have been removed, because they were obscure, buggy, and obsolete. Use getaddrinfo() instead.

Upcoming breaking changes with warnings (i.e., stuff that in 0.2.0 will work but will print loud complaints, and that won’t work in 0.3.0):

  • For consistency with the new start method, the nursery spawn method is being renamed to start_soon (#284)

  • trio.socket.sendall is deprecated; use trio.open_tcp_stream and SocketStream.send_all instead (#291)

  • Trio now consistently uses run for functions that take and run an async function (like!), and run_sync for functions that take and run a synchronous function. As part of this:

    See #68 for details.

  • trio.Queue’s join and task_done methods are deprecated without replacement (#321)

  • Trio 0.1.0 provided a set of built-in mechanisms for waiting for and tracking the result of individual tasks. We haven’t yet found any cases where using this actually led to simpler code, though, and this feature is blocking useful improvements, so the following are being deprecated without replacement:

    • nursery.zombies
    • nursery.monitor
    • nursery.reap
    • nursery.reap_and_unwrap
    • task.result
    • task.add_monitor
    • task.discard_monitor
    • task.wait

    This also lets us move a number of lower-level features out of the main trio namespace and into trio.hazmat:

    • trio.Tasktrio.hazmat.Task
    • trio.current_tasktrio.hazmat.current_task()
    • trio.Resulttrio.hazmat.Result
    • trio.Valuetrio.hazmat.Value
    • trio.Errortrio.hazmat.Error
    • trio.UnboundedQueuetrio.hazmat.UnboundedQueue

    In addition, several introspection attributes are being renamed:

    • nursery.childrennursery.child_tasks
    • task.parent_task → use task.parent_nursery.parent_task instead

    See #136 for more details.

  • To consolidate introspection functionality in trio.hazmat, the following functions are moving:

    See #317 for more details.

  • It was decided that 0.1.0’s “yield point” terminology was confusing; we now use “checkpoint” instead. As part of this, the following functions in trio.hazmat are changing names:

    In addition, the following functions in trio.testing are changing names:

    See #157 for more details.

  • trio.format_exception is deprecated; use traceback.format_exception() instead (#347).

  • trio.current_instruments is deprecated. For adding or removing instrumentation at run-time, see trio.hazmat.add_instrument() and trio.hazmat.remove_instrument() (#257)

Unfortunately, a limitation in PyPy3 5.8 breaks our deprecation handling for some renames. (Attempting to use the old names will give an unhelpful error instead of a helpful warning.) This does not affect CPython, or PyPy3 5.9+.

Other changes

  • run_sync_in_worker_thread() now has a robust mechanism for applying capacity limits to the number of concurrent threads (#10, #57, #156)

  • New support for tests to cleanly hook hostname lookup and socket operations: see Virtual networking for testing. In addition, trio.socket.SocketType is now an empty abstract base class, with the actual socket class made private. This shouldn’t effect anyone, since the only thing you could directly use it for in the first place was isinstance checks, and those still work (#170)

  • New class StrictFIFOLock

  • New exception ResourceBusyError

  • The trio.hazmat.ParkingLot class (which is used to implement many of Trio’s synchronization primitives) was rewritten to be simpler and faster (#272, #287)

  • It’s generally true that if you’re using Trio you have to use Trio functions, if you’re using asyncio you have to use asyncio functions, and so forth. (See the discussion of the “async sandwich” in the Trio tutorial for more details.) So for example, this isn’t going to work:

    async def main():
        # asyncio here
        await asyncio.sleep(1)
    # trio here

    Trio now reliably detects if you accidentally do something like this, and gives a helpful error message.

  • Trio now also has special error messages for several other common errors, like doing (should be

  • trio.socket now handles non-ascii domain names using the modern IDNA 2008 standard instead of the obsolete IDNA 2003 standard (#11)

  • When an Instrument raises an unexpected error, we now route it through the logging module instead of printing it directly to stderr. Normally this produces exactly the same effect, but this way it’s more configurable. (#306)

  • Fixed a minor race condition in IOCP thread shutdown on Windows (#81)

  • Control-C handling on Windows now uses signal.set_wakeup_fd() and should be more reliable (#42)

  • takes a new keyword argument restrict_keyboard_interrupt_to_checkpoints

  • New attributes allow more detailed introspection of the task tree: nursery.child_tasks, Task.child_nurseries, nursery.parent_task, Task.parent_nursery

  • trio.testing.wait_all_tasks_blocked() now takes a tiebreaker= argument. The main use is to allow MockClock’s auto-jump functionality to avoid interfering with direct use of wait_all_tasks_blocked() in the same test.

  • MultiError.catch() now correctly preserves __context__, despite Python’s best attempts to stop us (#165)

  • It is now possible to take weakrefs to Lock and many other classes (#331)

  • Fix sock.accept() for IPv6 sockets (#164)

  • PyCharm (and hopefully other IDEs) can now offer better completions for the trio and trio.hazmat modules (#314)

  • Trio now uses yapf to standardize formatting across the source tree, so we never have to think about whitespace again.

  • Many documentation improvements

Trio 0.1.0 (2017-03-10)

  • Initial release.