The Trio project produces an async/await-native I/O library for
Python. Like all async libraries, its main purpose is to help write
programs that do multiple things at the same time with parallelized
I/O, such as a web spider that wants to fetch lots of pages in
parallel, a web server that needs to juggle lots of downloads and
websocket connections at the same time, a process supervisor
monitoring multiple subprocesses. Compared to other libraries, Trio
has an obsessive focus on usability and correctness.
Provides
Requires
License
Apache-2.0 OR MIT
Changelog
* Sun Nov 01 2026 Martin Hauke <mardnh@gmx.de>
- Update to version 0.35.0
Features
* Mark that Trio supports 3.15. (#3563)
Bugfixes
* Ensure that Trio consistently encodes all hostnames using IDNA
2008. (#11)
* Ensure trio.lowlevel.notify_closing works even on events that
have been deleted, e.g. because they were registered as one shot
events. (#3502)
* trio.Process no longer emits an EncodingWarning on Linux when
Python runs with -X warn_default_encoding (or
PYTHONWARNDEFAULTENCODING=1). (#3555).
Miscellaneous internal changes
* The typing for async-file-objects is now consistent about what
it exposes based on what is exposed by the underlying object.
(#3542)
* Fri Oct 09 2026 Martin Hauke <mardnh@gmx.de>
- Update to version 0.34.0
Features
* MemoryChannelStatistics now has a peak_buffer_used field, which
reports the largest number of items that have ever been in the
channel's buffer at once. This makes it easier to pick a
sensible max_buffer_size based on data from a real run, instead
of guessing. (#1723).
* Support Python 3.15, as of beta 4. Things may still change and
so this support may break in the future. (#3456)
Bugfixes
* Nursery.start() now preserves the __cause__ and __context__ of
exceptions raised before task_status.started() is called.
(#3261)
* Fixed incorrect error message in run_process: the stdout pipe
check now correctly says "stdout" instead of "stdin". (#3409)
* Fixed trio.Path.as_uri() on Python 3.14+ to avoid the
deprecated pathlib.PurePath.as_uri() path. (#3460)
* Fixed trio.to_thread.run_sync workers leaking spawner's Context
on py314t+ free-threaded builds. (#3472)
Deprecations and removals
* Trying to use absolute deadlines on a trio.CancelScope
constructed with a relative deadline now raises, after being
deprecated since Trio 0.27.0.
* To switch a cancel scope from being relative to absolute,
replace the trio.CancelScope object instead of trying to mutate
it. (#3403)
* Sat Mar 14 2026 Dirk Müller <dmueller@suse.com>
- update to 0.33.0:
* Start supporting Android's new "android" sys.platform.
* Both :class:`trio.testing.RaisesGroup` and
:class:`trio.testing.Matcher` have been deprecated. Pytest
alternatives pytest.RaisesGroup and pytest.RaisesExc
(respectively) are considered correct replacement.
* Fri Nov 28 2025 John Paul Adrian Glaubitz <adrian.glaubitz@suse.com>
- Update to 0.32.0
* Allow trio.CapacityLimiter to have zero total_tokens. (#3321)
* Fixed a bug where iterating over an @as_safe_channel-derived
ReceiveChannel would raise BrokenResourceError if the channel
was closed by another task. It now shuts down cleanly. (#3331)
* trio.lowlevel.Task.iter_await_frames now works on completed tasks,
by returning an empty list of frames if the underlying coroutine
has been closed. Previously, it raised an internal error. (#3337)
- Update BuildRequires from pyproject.toml
* Tue Sep 23 2025 John Paul Adrian Glaubitz <adrian.glaubitz@suse.com>
- Update to 0.31.0
* Cancelled strings can now display the source and reason for a cancellation.
Trio-internal sources of cancellation will set this string, and CancelScope.cancel
now has a reason string parameter that can be used to attach info to any Cancelled
to help in debugging. (#3232)
* Make ctrl+c work in more situations in the Trio REPL (python -m trio). (#3007)
* Allow pickling trio.Cancelled, as they can show up when you want to pickle something
else. This does not rule out pickling other NoPublicConstructor objects -- create an
issue if necessary. (#3248)
* Decrease import time on Windows by around 10%. (#3263)
* Handle unwrapping SystemExit/KeyboardInterrupt exception gracefully in utility function
raise_single_exception_from_group that reraises last exception from group. (#3275)
* Ensure that the DTLS server does not mutate SSL context. (#3277)
* Avoid having trio.as_safe_channel raise if closing the generator wrapped GeneratorExit
in a BaseExceptionGroup. (#3324)
* Implement bool(trio.Event) and have it raise a DeprecationWarning and tell users to use
trio.Event.is_set instead. This is an alternative to mypy --enable-error-code=truthy-bool
for users who don't use type checking. (#3322)
* When misnesting nurseries you now get a helpful RuntimeError instead of a catastrophic
TrioInternalError. (#3307)
- Drop pyopenssl-25-1-compatibility.patch, merged upstream
- Remove shebang from trio/_tools/sync_requirements.py
* Thu Jul 17 2025 Dirk Müller <dmueller@suse.com>
- add pyopenssl-25-1-compatibility.patch to ignore deprecation
warnings (from pyopenssl)
* Wed Jul 02 2025 John Paul Adrian Glaubitz <adrian.glaubitz@suse.com>
- Update to 0.30.0
* Add @trio.as_safe_channel, a wrapper that can be used to make async generators
safe. This will be the suggested fix for the flake8-async lint rule ASYNC900. (#3197)
* Allow trio to be a types.ModuleType and still have deprecated attributes. (#2135)
* Fixed socket module for some older systems which lack socket.AI_NUMERICSERV.
* Now trio works on legacy (pre-Lion) macOS. (#3133)
* Update type hints for trio.run_process and trio.lowlevel.open_process. (#3183)
* Don't mutate the global runner when MockClock is created. (#3205)
* Fix incorrect return type hint for Nursery.start(). (#3224)
* Update wording in documentation to more accurately reflect Trio's maturity. (#3216)
- Update BuildRequires from pyproject.toml
* Tue Mar 04 2025 John Paul Adrian Glaubitz <adrian.glaubitz@suse.com>
- Update to 0.29.0
* Add trio.lowlevel.in_trio_run() and trio.lowlevel.in_trio_task() and document
the semantics (and differences) thereof. See the documentation. (#2757)
* If trio.testing.RaisesGroup does not get the expected exceptions it now raises
an AssertionError with a helpful message, instead of letting the raised exception/
group fall through. The raised exception is available in the __context__ of the
AssertionError and can be seen in the traceback. (#3145)
* Clear Trio’s cache of worker threads upon os.fork. (#2764)
* Stop using ctypes to mutate tracebacks for strict_exception_groups=False’s exception
collapsing. (#405)
* Fixed spelling error in Windows error code enum for ERROR_INVALID_PARAMETER. (#3166)
* Publicly re-export __version__ for type checking purposes. (#3186)
* The typing of trio.abc.HostnameResolver.getaddrinfo() has been corrected to match
that of the stdlib socket.getaddrinfo, which was updated in mypy 1.15 (via a typeshed
update) to include the possibility of tuple[int, bytes] for the sockaddr field of the
result. This happens in situations where Python was compiled with --disable-ipv6.
* Additionally, the static typing of trio.to_thread.run_sync(), trio.from_thread.run()
and trio.from_thread.run_sync() has been improved and should reflect the underlying
function being run. (#3201)
- Add sed command to remove shebangs from check_type_completeness.py and gen_exports.py
* Tue Jan 28 2025 John Paul Adrian Glaubitz <adrian.glaubitz@suse.com>
- Update to 0.28.0
* :func:inspect.iscoroutinefunction and the like now give correct answers when
called on KI-protected functions.
* Rework KeyboardInterrupt protection to track code objects, rather than frames,
as protected or not. The new implementation no longer needs to access
frame.f_locals dictionaries, so it won't artificially extend the lifetime of
local variables. Since KeyboardInterrupt protection is now imposed statically
(when a protected function is defined) rather than each time the function runs,
its previously-noticeable performance overhead should now be near zero.
The lack of a call-time wrapper has some other benefits as well:
* :func:inspect.iscoroutinefunction and the like now give correct answers when
called on KI-protected functions.
* Calling a synchronous KI-protected function no longer pushes an additional stack
frame, so tracebacks are clearer.
* A synchronous KI-protected function invoked from C code (such as a weakref
finalizer) is now guaranteed to start executing; previously there would be a brief
window in which KeyboardInterrupt could be raised before the protection was
established.
* One minor drawback of the new approach is that multiple instances of the same
closure share a single KeyboardInterrupt protection state (because they share a
single code object). That means that if you apply
trio.lowlevel.enable_ki_protection to some of them
and not others, you won't get the protection semantics you asked for. See the
documentation of trio.lowlevel.enable_ki_protection
for more details and a workaround.
* Rework foreign async generator finalization to track async generator
ids rather than mutating ag_frame.f_locals. This fixes an issue
with the previous implementation: locals' lifetimes will no longer be
extended by materialization in the ag_frame.f_locals dictionary that
the previous finalization dispatcher logic needed to access to do its work.
* Ensure that Pyright recognizes our underscore prefixed attributes for attrs
classes.
* Fix trio.testing.RaisesGroup's typing.
* Improve error message when run after gevent's monkey patching.
* Document that trio.sleep_forever is guaranteed to raise an exception now.
* Remove workaround for OpenSSL 1.1.1 DTLS ClientHello bug.
* Drop support for Python 3.8.
* Switch to using PEP570 for positional-only arguments for trio.socket.SocketType's
methods.
* Improve type annotations in several places by removing Any usage.
* Get and enforce 100% coverage.
* Wed Oct 30 2024 Dirk Müller <dmueller@suse.com>
- update to 0.27.0:
* :func:`trio.move_on_after` and :func:`trio.fail_after`
previously set the deadline relative to initialization time,
instead of more intuitively upon entering the context
manager. This might change timeouts if a program relied on
this behavior. If you want to restore previous behavior you
should instead use trio.move_on_at(trio.current_time() +
...). flake8-async has a new rule to catch this, in case
you're supporting older trio versions. See :ref:`ASYNC122`.
* :meth:`CancelScope.relative_deadline` and
:meth:`CancelScope.is_relative` added, as well as a
relative_deadline parameter to __init__. This allows
initializing scopes ahead of time, but where the specified
relative deadline doesn't count down until the scope is
entered.
* :class:`trio.Lock` and :class:`trio.StrictFIFOLock` will now
raise :exc:`trio.BrokenResourceError` when
:meth:`trio.Lock.acquire` would previously stall due to the
owner of the lock exiting without releasing the lock.
* trio.move_on_at, trio.move_on_after, trio.fail_at and
trio.fail_after now accept shield as a keyword argument. If
specified, it provides an initial value for the
~trio.CancelScope.shield attribute of the trio.CancelScope
object created by the context manager.
* Added :func:`trio.lowlevel.add_parking_lot_breaker` and
:func:`trio.lowlevel.remove_parking_lot_breaker` to allow
creating custom lock/semaphore implementations that will
break their underlying parking lot if a task exits
unexpectedly. :meth:`trio.lowlevel.ParkingLot.break_lot` is
also added, to allow breaking a parking lot intentionally.
* Allow sockets to bind any os.PathLike object.
* Update trio.lowlevel.open_process's documentation to allow
bytes.
* Update :func:`trio.sleep_forever` to be NoReturn.
* Add docstrings for memory channels' statistics() and aclose
methods.
* Sun Sep 08 2024 Dirk Müller <dmueller@suse.com>
- update to 0.26.2:
* Remove remaining hash usage and fix test configuration issue
that prevented it from being caught.
* Switched attrs usage off of hash, which is now deprecated.
* Use PyPI's Trusted Publishers to make releases.
* Added an interactive interpreter python -m trio. This makes
it easier to try things and experiment with trio in the a
Python repl. Use the await keyword without needing to call
trio.run() $ python -m trio Trio 0.21.0+dev, Python 3.10.6
Use "await" directly instead of "trio.run()". Type "help",
"copyright", "credits" or "license" for more information. >>>
import trio >>> await trio.sleep(1); print("hi") # prints
after one second hi See :ref:`interactive debugging` for
further detail. (#2972)
* :class:`trio.testing.RaisesGroup` can now catch an unwrapped
exception with unwrapped=True. This means that the behaviour
of :ref:`except* <except_star>` can be fully replicated in
combination with flatten_subgroups=True (formerly
strict=False). (#2989)
* Fixed a bug where :class:`trio.testing.RaisesGroup(...,
strict=False) <trio.testing.RaisesGroup>` would check the
number of exceptions in the raised ExceptionGroup before
flattening subgroups, leading to incorrectly failed matches.
It now properly supports end ($) regex markers in the match
message, by no longer including " (x sub-exceptions)" in the
string it matches against.
* Deprecated strict parameter from
:class:`trio.testing.RaisesGroup`, previous functionality of
strict=False is now in flatten_subgroups=True.
* Mon Jun 17 2024 Dirk Müller <dmueller@suse.com>
- update to 0.25.1:
* Fix crash when importing trio in embedded Python on Windows,
and other installs that remove docstrings.
* Fri Mar 22 2024 Markéta Machová <mmachova@suse.com>
- Update to 0.25.0
* New helper classes: RaisesGroup and Matcher.
* MultiError has been fully removed, and all relevant trio
functions now raise ExceptionGroups instead.
* The strict_exception_groups parameter now defaults to True
in trio.run and trio.lowlevel.start_guest_run.
* Add trio.testing.wait_all_threads_completed, which blocks
until no threads are running tasks.
* Path is now a subclass of pathlib.PurePath, allowing it to
interoperate with other standard pathlib types.
* Thu Jan 11 2024 Ben Greiner <code@bnavigator.de>
- We don't need isort for the tests: Avoid it for Ring1
- Clean dependencies
* Wed Jan 03 2024 Dirk Müller <dmueller@suse.com>
- update to 0.23.2:
* TypeVarTuple is now used to fully type
:meth:`nursery.start_soon() <trio.Nursery.start_soon>`,
:func:`trio.run()`, :func:`trio.to_thread.run_sync()`, and
other similar functions accepting (func, *args). This means
type checkers will be able to verify types are used
correctly. :meth:`nursery.start() <trio.Nursery.start>` is
not fully typed yet however. (#2881)
* Make pyright recognize :func:`open_memory_channel` as
generic. (#2873)
backlink Unknown interpreted text role "func".
* Make pyright recognize :func:`open_memory_channel` as
generic.
* Unknown interpreted text role "func".
* Moved the metadata into PEP 621-compliant
:file:`pyproject.toml`. (#2860)
* Tue Nov 07 2023 Dirk Müller <dmueller@suse.com>
- update to 0.23.1:
* Don't crash on import in Anaconda interpreters.
* Add type hints.
* When exiting a nursery block, the parent task always waits
for child tasks to exit. This wait cannot be cancelled. However,
previously, if you tried to cancel it, it *would* inject a
`Cancelled` exception, even though it wasn't cancelled.
Most users probably never noticed either way, b