NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #22 most downloaded on PyPI
High-level concurrency and networking framework on top of asyncio or Trio
Last release 29 days ago
05 Sep 2026
Ships fairly regularly
a new release about every 2 months
Nearly every release is documented
notes for 54 of 55 stable releases
1 version withdrawn
withdrawn after publishing
8 years old
72 releases · first in 2018
Implemented a compatibility fix for supporting direct access of anyio.* submodules from the main package even when those submodules were not directly
anyio.* submodules from the main package even when those submodules were not directly imported first (#1311 <https://github.com/agronholm/anyio/issues/1311\>)Fixed the pytest plugin importing the deprecated _pytest.python.CallSpec2 alias, which triggers PytestRemovedIn10Warning on pytest>=9.2 and crashes py…
Added support for the newer keyword-only arguments on anyio.Path methods to match the standard library pathlib.Path:
follow_symlinks on exists() (Python 3.12+)follow_symlinks on is_dir() (Python 3.13+)follow_symlinks on is_file() (Python 3.13+)follow_symlinks on owner() (Python 3.13+)follow_symlinks on group() (Python 3.13+)newline on read_text() (Python 3.13+)(#1286, #1293; PR by @jaideeppyne)
Added amap, gather, and as_completed utility functions to simplify common patterns (#1173; PR by @Graeme22)
Added --anyio-mode command-line option as an alternative to the anyio_mode ini setting, and fix the pytest plugin's auto mode detection to recognize the mode when set via either mechanism(e.g: pytest_asyncio). (#1242; PR by @EmmanuelNiyonshuti)
Added the anyio.Future synchronization primitive which behaves similar to asyncio.Future, allowing tasks to wait for a value (or exception) from another task (#1146; PR by @Vizonex)
Added guidance for managing multiple memory object stream producers and consumers with cloned streams (#330; PR by @nightcityblade)
Added StapledObjectStream.send_nowait() that delegates to the underlying ObjectSendStream, if it implements it (#1241; PR by @davidbrochart)
Added the move_on_at() and fail_at() functions to complement move_on_after() and fail_after()
Changed the default name for a task spawned with TaskGroup.create_task(func()) to match the default task name for the analogous task spawned with TaskGroup.start_soon(func) or TaskGroup.start(func) in more situations. Previously, the default name of a TaskGroup.create_task task never included the module name. (The default name for a task spawned with TaskGroup.start_soon or TaskGroup.start typically includes the module name.) (#1234; PR by @gschaffner)
Changed the anyio and anyio.abc modules to lazily (much like 810) import the necessary submodules. This is done by parsing the AST of the module and building a lookup table from the if TYPE_CHECKING: block. A fallback mode has been provided for installations where the source code is unavailable (e.g. PyInstaller). (#1169)
Fixed free-threading compatibility issues arising from the fact that on Python 3.14 free-threading builds, newly created threads inherit the current context by default, causing AnyIO to behave erroneously in relation to start_blocking_portal() and anyio.to_thread.run_sync() (#1224; PR by @EmmanuelNiyonshuti)
Fixed SpooledTemporaryFile.readinto() and readinto1() reading twice before rollover, so the destination buffer was overwritten by the second read and the file position advanced twice, silently losing data (#1215; PR by @c-tonneslan)
Added a reason parameter to fail_after (and the new fail_at) allowing for added exception context when raising TimeoutError (#1227; PR by @Graeme22)
Fixed the default TaskHandle.name missing part of the task name for tasks started with TaskGroup.start on Trio (#1231; PR by @gschaffner)
Fixed anyio.run leaking, or at least, delaying collection of loop and root_task due to the root task being cached in a RunVar. (#1203; PR by @tapetersen)
Fixed anyio.Path.with_stem() silently producing a wrong path (e.g. Path(".txt")) instead of raising ValueError when given an empty stem on a path with a non-empty suffix, unlike pathlib.PurePath.with_stem (#1200; PR by @Sanjays2402)
Fixed UNIXSocketStream.aclose() raising asyncio.InvalidStateError when a concurrent receive or send operation had just been cancelled on the asyncio backend (#1267; PR by @alloutflo)
Fixed the pytest plugin importing the deprecated _pytest.python.CallSpec2 alias, which triggers PytestRemovedIn10Warning on pytest>=9.2 and crashes pytest at startup when filterwarnings = error is configured (#1271; PR by @matthewfeickert)
Fixed an asyncio worker thread race that could raise RuntimeError when the event loop closed between checking its state and scheduling the worker result (#1265; PR by @hansu650)
Fixed CapacityLimiter on the asyncio backend over-granting tokens when total_tokens was raised while the limiter was over-subscribed (#1223; PR by @zelinewang)
Fixed asyncio task groups leaking unawaited coroutines when a custom task constructor fails; default task creation is unaffected (#1274; PR by @dsfaccini)
Fixed inconsistencies between Trio and asyncio when target TaskGroup is cancelled before a task created with .start() calls TaskStatus.started()
CancelledError until the first checkpoint after the started() call.started() should be available on the TaskHandle and correctly passed back to the caller of start even if cancelled.TaskGroup.start() call to the calling task.(#1197; PR by @tapetersen)
Fixed TemporaryDirectory not cleaning up when the host task was cancelled while exiting the context manager, as the cleanup now runs in a shielded cancel scope (#1304; PR by @smurfix)
One column per quarter.
Changed ByteReceiveStream.receive() implementations to raise a ValueError when max_bytes is not a positive integer
ByteReceiveStream.receive() implementations to raise a ValueError when max_bytes is not a positive integer (#1191)CapacityLimiter.total_tokens rejecting float("inf") when the limiter was instantiated outside of an event loop. The adapter setter checked for infinity by identity (value is math.inf), so only the exact math.inf singleton was accepted, while every backend setter (using math.isinf()) accepts any positive infinity (#1189; PR by @greymoth-jp).to_process.run_sync() deadlocking when the worker function writes enough data to sys.stderr to fill the (undrained) pipe buffer. The worker process now redirects sys.stderr to os.devnull as well, matching the documented behaviorTLSStream.wrap() matching an internationalized (unicode) host name against the peer certificate using IDNA 2003 (via the standard library) instead of IDNA 2008, which could cause the host name to be matched against the wrong certificate (#1208)anyio.open_process() (and run_process()) ignoring the extra_groups argument, as it mistakenly passed the value of the group argument instead (#1209)CapacityLimiter.acquire_nowait() and CapacityLimiter.acquire_nowait_on_behalf_of() raising trio.WouldBlock instead of anyio.WouldBlock on the trio backend when there are no tokens available (#1218)CapacityLimiter on the asyncio backend over-granting tokens (borrowed_tokens exceeding total_tokens and available_tokens going negative) when a non-blocking acquire was made in the window between a token being released and the notified waiter resuming. The freed token is now reserved for the woken waiter right away, so the non-blocking acquire correctly raises WouldBlock (#1170; PR by @gaoflow)CancelScope on asyncio under certain conditions, including improper cancel scope nesting (#1111)Fixed teardown of higher-scoped async fixtures failing on asyncio with RuntimeError: Attempted to exit cancel scope in a different task than it was en
RuntimeError: Attempted to exit cancel scope in a different task than it was entered in when an async test raise an outcome exception (e.g., pytest.skip(), pytest.xfail(), or pytest.fail()) (#1179; PR by @EmmanuelNiyonshuti)CapacityLimiter.total_tokens rejecting a value of 0 when the limiter was instantiated outside of an event loop, contradicting the documented behavior of allowing 0 total tokens (#1183; PR by @nyxst4ck)Fixed teardown of higher-scoped async fixtures failing on asyncio with RuntimeError: Attempted to exit cancel scope in a different task than it was entered in when an async test raise an outcome exception (e.g., pytest.skip() , pytest.xfail() , or pytest.fail() ) ( #1179 ; PR by @EmmanuelNiyonshuti)
Fixed CapacityLimiter.total_tokens rejecting a value of 0 when the limiter was instantiated outside of an event loop, contradicting the documented behavior of allowing 0 total tokens ( #1183 ; PR by @nyxst4ck)
Fixed Process.wait() on asyncio waiting for stdout/stderr kept open (e.g. if a grandchild inherited it), instead of returning once the process exits like the other backends do ( #1174 ; PR by @tapetersen)
Fixed Process.aclose() deadlocking on the asyncio backend when the subprocess is blocked on writing to a stdout or stderr pipe whose buffer is full; closing the process’s standard streams now also closes the underlying pipe transports ( #1166 ; PR by @tapetersen)
Added an asynchronous implementation of the itertools module ( #998 ; PR by @11kkw )
Added support for Python 3.15
Added an asynchronous implementation of the itertools module (#998; PR by @11kkw)
Added the local_port parameter to connect_tcp() to allow binding to a specific local port before connecting (#1067; PR by @nullwiz)
Added support for custom capacity limiters in async path and file I/O functions and classes
Added the create_task() task group method for easier asyncio migration (returns a TaskHandle) (#1098)
Changed TaskGroup.start_soon() to return a TaskHandle
Added an option for TaskGroup.start() to return a TaskHandle (which then contains the start value in the start_value property)
Added the cancel() convenience method to TaskGroup as a shortcut for cancelling the task group's cancel scope
Improved the error message when a known backend is not installed to suggest the install command (#1115; PR by @EmmanuelNiyonshuti)
Improved anyio.Path to preserve subclass types by returning Self in methods that return path objects (#1130; PR by @EmmanuelNiyonshuti)
Changed the parameter type annotation in anyio.Path.write_bytes() to accept any ReadableBuffer, thus allowing it to accept bytearray and memoryview to match pathlib.Path.write_bytes() (#1135; PR by @SAY-5)
Changed several type annotations to only accept callables returning coroutine-like objects instead of arbitrary awaitables:
TaskGroup.start_soon()TaskGroup.start()anyio.from_thread.run()This reverts an earlier change from v3.7.0 which was made in error. (#1153)
Changed anyio.run to support callables returning arbitrary awaitables at runtime on all backends. Previously, this only worked on asyncio (#1171; PR by @gschaffner)
Changed several classes (and their subclasses) to have __slots__ (with __weakref__):
anyio.CancelScopeanyio.CapacityLimiteranyio.Conditionanyio.Eventanyio.Lockanyio.ResourceGuardanyio.SemaphoreFixed cancellation exception escaping a cancel scope when triggered via check_cancelled() in a worker thread (#1113)
Fixed TaskGroup raising AttributeError instead of a clear error when entered more than once (#1109; PR by @Bahtya)
Fixed lost type information when passing arguments to lru_cache (#1104; PR by @Graeme22)
Fixed test resumption after KeyboardInterrupt in async generator fixtures on the asyncio backend (#1060; PR by @EmmanuelNiyonshuti)
Fixed import of __main__ in to_process workers when entrypoint script doesn't end in .py, such as when using console_script entrypoints. (#1027; PR by @tapetersen)
Fixed SocketListener.from_socket() returning a TCP listener for AF_UNIX listening sockets, causing accept() to fail with ENOTSUP (#1132; PR by @kudato)
Fixed UDPSocket.aclose() and ConnectedUDPSocket.aclose() on asyncio returning before the underlying socket FD was actually released (#1147; PR by @matias-arrelid)
Fixed trio backend test runner hanging indefinitely instead of raising an error when dynamically accessing an async fixture via request.getfixturevalue (#1148; PR by @EmmanuelNiyonshuti)
Fixed cancelling tasks started through a BlockingPortal after the portal has been stopped (#1013; PR by @puneetdixit200)
Fixed backend_options being ignored when running the Trio backend via anyio.run(); the options are now passed as keyword arguments to trio.run() again, as documented (a regression from AnyIO 3) (#1161; PR by @Zac-HD)
Fixed asyncio Lock and Semaphore deadlocks caused by cancelled waiters left queued during release (#1145; PR by @rasmusfaber, @x42005e1f and @agronholm)
Added a ttl parameter to the anyio.functools.lru_cache wrapper ( #1073 ; PR by @Graeme22 )
ttl parameter to the anyio.functools.lru_cache wrapper (#1073; PR by @Graeme22)IO[bytes] instead of just BinaryIO (#1078)anyio.Path not being compatible with Python 3.15 due to the removal of pathlib.Path.is_reserved() and the addition of pathlib.Path.__vfspath__() (#1061; PR by @veeceey)BrokenResourceError raised by the asyncio SocketStream not having the original exception as its cause (#1055; PR by @veeceey)TypeError raised when using "func" as a parameter name in pytest.mark.parametrize when using the pytest plugin (#1068; PR by @JohnnyDeuss)anyio marker added programmatically via pytest_collection_modifyitems (#422; PR by @chbndrhnns)CancelScope on asyncio when they are contained in an exception group alongside non-cancellation exceptions (#1091; PR by @gschaffner)Condition.wait() not passing on a notification when the task is cancelled but already received a notificationChanged all functions currently raising the private NoCurrentAsyncBackend exception (since v4.12.0) to instead raise the public NoEventLoopError excep
Added support for asyncio's task call graphs on Python 3.14 and later when using AnyIO's task groups
functools module (#1001)uvloop=True on Windows via the winloop implementation (#960; PR by @Vizonex)anyio.lowlevel.RunVar (#1003)__all__ declarations to public submodules (anyio.lowlevel etc.) (#1009)CapacityLimiter to zero (#1019; requires Python 3.10 or later when using Trio)case_sensitive and recurse_symlinks along with support for path-like objects to anyio.Path.glob() and anyio.Path.rglob() (#1033; PR by @NorthIsUp)sniffio as a direct dependency and added the get_available_backends() function (#1021)Process.stdin.send() not raising ClosedResourceError and BrokenResourceError on asyncio. Previously, a non-AnyIO exception was raised in such cases (#671; PR by @gschaffner)Process.stdin.send() not checkpointing before writing data on asyncio (#1002; PR by @gschaffner)Future from BlockingPortal.start_task_soon() would sometimes not cancel the async function (#1011; PR by @gschaffner)RuntimeError: Set changed size during iteration while shutting down the process pool when using the asyncio backend (#985)Added support for cancellation reasons (the reason parameter to CancelScope.cancel() )
reason parameter to CancelScope.cancel()) (#975)anyio.lowlevel.current_token() to anyio.from_thread.run() and anyio.from_thread.run_sync() as the token keyword argument (#256)anyio_mode = "auto") to make the pytest plugin automatically handle all async tests (#971)anyio.Condition.wait_for() method for feature parity with asyncio (#974)anyio.abc.TaskStatus from Any to None (#964)local_port=0 (#857; PR by @11kkw and @agronholm)BrokenResourceError on send() would still raise BrokenResourceError after the stream was closed on asyncio, but ClosedResourceError on Trio. They now both raise a ClosedResourceError in this scenario. (#671)Renamed the BrokenWorkerIntepreter exception to BrokenWorkerInterpreter . The old name is available as a deprecated alias. ( #938 ; PR by @ayussh-verm…
feed_data() method to the BufferedByteReceiveStream class, allowing users to inject data directly into the bufferSocketListener.from_socket()SocketStream.from_socket()UNIXSocketStream.from_socket()UDPSocket.from_socket()ConnectedUDPSocket.from_socket()UNIXDatagramSocket.from_socket()ConnectedUNIXDatagramSocket.from_socket()anyio.ContextManagerMixin and anyio.AsyncContextManagerMixin) to help write classes that embed other context managers, particularly cancel scopes or task groups (#905; PR by @agronholm and @tapetersen)start_blocking_portal() (#818; PR by @davidbrochart)anyio.notify_closing to allow waking anyio.wait_readable and anyio.wait_writable before closing a socket. Among other things, this prevents an OSError on the ProactorEventLoop. (#896; PR by @graingert)to_interpreters module to use the public concurrent.interpreters API on Python 3.14 or lateranyio.Path.copy() and anyio.Path.copy_into() failing on Python 3.14.0a7__aexit__ on async context managers. CMs which can suppress exceptions should return bool, or None otherwise. (#913; PR by @Enegg)SpooledTemporaryFile so that rollover only occurs when the buffer size exceeds max_size (#915; PR by @11kkw)anyio.to_interpreter with Python 3.14.0b2 (#926; PR by @hroncok)SyntaxWarning on Python 3.14 about return in finally (#816)BrokenWorkerIntepreter exception to BrokenWorkerInterpreter. The old name is available as a deprecated alias. (#938; PR by @ayussh-verma)CapacityLimiter on asyncio where a task, waiting to acquire a limiter gets cancelled and is subsequently granted a token from the limiter, but before the cancellation is delivered, and then fails to notify the next waiting task (#947)Added async support for temporary file handling ( #344 ; PR by @11kkw )
pytest plugin:
free_tcp_port_factory: session scoped fixture returning a callable that generates unused TCP port numbersfree_udp_port_factory: session scoped fixture returning a callable that generates unused UDP port numbersfree_tcp_port: function scoped fixture that invokes the free_tcp_port_factory fixture to generate a free TCP port numberfree_udp_port: function scoped fixture that invokes the free_udp_port_factory fixture to generate a free UDP port numberstdin argument to anyio.run_process() akin to what anyio.open_process(), asyncio.create_subprocess(), trio.run_process(), and subprocess.run() already accept (PR by @jmehnle)info property to anyio.Path on Python 3.14anyio.getaddrinfo() to ignore (invalid) IPv6 name resolution results when IPv6 support is disabled in PythonEndOfStream raised from MemoryObjectReceiveStream.receive() to leave out the AttributeError from the exception chain which was merely an implementation detail and caused some confusionTaskGroup nesting on asyncio due to exception chaining when raising ExceptionGroups in TaskGroup.__aexit__ (#863; PR by @tapetersen)anyio.Path.iterdir() making a blocking call in Python 3.13 (#873; PR by @cbornet and @agronholm)connect_tcp() producing cyclic references in tracebacks when raising exceptions (#809; PR by @graingert)anyio.to_thread.run_sync() needlessly holding on to references of the context, function, arguments and others until the next work item on asyncio (PR by @Wankupi)Added experimental support for running functions in subinterpreters on Python 3.13 and later
copy(), copy_into(), move() and move_into() methods in anyio.Path, available in Python 3.14TaskGroup on asyncio to always spawn tasks non-eagerly, even if using a task factory created via asyncio.create_eager_task_factory(), to preserve expected Trio-like task scheduling semantics (PR by @agronholm and @graingert)SO_RCVBUF, SO_SNDBUF and TCP_NODELAY on the selector thread waker socket pair (this should improve the performance of wait_readable() and wait_writable() when using the ProactorEventLoop) (#836; PR by @graingert)AssertionError when using nest-asyncio (#840)__exit__ method (#847; PR by @Enegg)…a .fileno() method or an integer handle, and deprecated their now obsolete versions (wait_socket_readable() and wait_socket_writable()) (PR by @davidb…
TaskGroup to work with asyncio's eager task factories (#764)wait_readable() and wait_writable() functions which will accept an object with a .fileno() method or an integer handle, and deprecated their now obsolete versions (wait_socket_readable() and wait_socket_writable()) (PR by @davidbrochart)EventAdapter (an Event with no bound async backend) to allow set() to work even before an async backend is bound to it (#819)wait_readable() and wait_writable() on ProactorEventLoop (used on asyncio + Windows by default)ValueError in the context of DNS failures (#815; PR by @graingert)readinto() and readinto1() methods in the anyio.AsyncFile class (#825)TaskInfo.has_pending_cancellation() on asyncio returning false positives in cleanup code on Python >= 3.11 (#832; PR by @gschaffner)asyncio.Task.uncancel when propagating a CancelledError on exit to a cancelled parent scope (#790; PR by @gschaffner)Nothing published for this version
Fixed regression caused by (\#807) that prevented the use of parametrized async fixtures
This release contains all the changes from both v4.5.1 and v4.6.0, plus:
This release contains all the changes from both v4.5.1 and v4.6.0, plus:
Dropped support for Python 3.8 (as \#698 cannot be resolved without cancel message support)
CancelledError on exit when the enclosing cancel scope has been effectively cancelled (#698)This release is the successor to v4.5.0 with Python 3.8 support dropped, and does not contain the changes from v4.5.1.
Dropped support for Python 3.8 (as #698 cannot be resolved without cancel message support)
Fixed 100% CPU use on asyncio while waiting for an exiting task group to finish while said task group is within a cancelled cancel scope ( #695 )
Fixed cancel scopes on asyncio not propagating CancelledError on exit when the enclosing cancel scope has been effectively cancelled ( #698 )
Fixed asyncio task groups not yielding control to the event loop at exit if there were no child tasks to wait on
Fixed inconsistent task uncancellation with asyncio cancel scopes belonging to a task group when said task group has child tasks running
Fixed regression caused by (\#807) that prevented the use of parametrized async fixtures.
As Python 3.8 support was dropped in v4.6.0, this interim release was created to bring a regression fix to Python 3.8, and adds a few other fixes also
As Python 3.8 support was dropped in v4.6.0, this interim release was created to bring a regression fix to Python 3.8, and adds a few other fixes also present in v4.6.1.
RuntimeError (#798)self being different than the test's self in class-based tests (#633) (PR by @agronholm and @graingert)TypeError with TLSStream on Windows when a certificate verification error occurs when using a truststore SSL certificate (#795)anyio.Path regarding the limitations imposed by the current Python version on several of its methods, and made the is_junction method unavailable on Python versions earlier than 3.12 (#794)Improved the performance of anyio.Lock and anyio.Semaphore on asyncio (even up to 50 %)
anyio.Lock and anyio.Semaphore on asyncio (even up to 50 %)fast_acquire parameter to anyio.Lock and anyio.Semaphore to further boost performance at the expense of safety (acquire() will not yield control back if there is no contention)from_uri(), full_match(), parser methods/properties in anyio.Path, newly added in Python 3.13 (#737)run_process() and open_process(): startupinfo, creationflags, pass_fds, user, group, extra_groups and umask (#742)PathLike in run_process() and open_process() to allow for path-like arguments, just like subprocess.PopenResourceWarning from an unclosed memory object stream to include its address for easier identificationstart_blocking_portal() to always use daemonic threads, to accommodate the "loitering event loop" use case__repr__() of MemoryObjectItemReceiver, when item is not defined (#767; PR by @Danipulok)to_process.run_sync() failing to initialize if __main__.__file__ pointed to a file in a nonexistent directory (#696)AssertionError: feed_data after feed_eof on asyncio when a subprocess is closed early, before its output has been read (#490)TaskInfo.has_pending_cancellation() on asyncio not respecting shielded scopes (#771; PR by @gschaffner)SocketStream.receive() returning bytearray instead of bytes when using asyncio with ProactorEventLoop (Windows) (#776)KeyboardInterrupt (ctrl+c) hanging the asyncio pytest runnerAdded the BlockingPortalProvider class to aid with constructing synchronous counterparts to asynchronous interfaces that would otherwise require multi
BlockingPortalProvider class to aid with constructing synchronous counterparts to asynchronous interfaces that would otherwise require multiple blocking portals__slots__ to AsyncResource so that child classes can use __slots__ (#733; PR by Justin Su)TaskInfo.has_pending_cancellation() methodRuntimeError: called 'started' twice on the same task status when cancelling a task in a TaskGroup created with the start() method before the first checkpoint is reached after calling task_status.started() (#706; PR by Dominik Schwabe)TaskGroup.start() on asyncio:
RuntimeError: called 'started' twice on the same task status when cancelling a task in a TaskGroup created with the start() method before the first checkpoint is reached after calling task_status.started() (#706; PR by Dominik Schwabe)TaskGroup.start() call gets cancelled (#685, #710)TypedAttributeLookupError if a typed attribute getter raises KeyErrorPYTHONASYNCIODEBUG environment variable when setting the debug flag in anyio.run()SocketStream.receive() not detecting EOF on asyncio if there is also data in the read buffer (#701)MemoryObjectStream dropping an item if the item is delivered to a recipient that is waiting to receive an item but has a cancellation pending (#728)ResourceWarning for MemoryObjectReceiveStream and MemoryObjectSendStream that were garbage collected without being closed (PR by Andrey Kazantcev)MemoryObjectSendStream.send() not raising BrokenResourceError when the last corresponding MemoryObjectReceiveStream is closed while waiting to send a falsey item (#731; PR by Ganden Schaffner)Added support for the Python 3.12 walk_up keyword argument in anyio.Path.relative_to() (PR by Colin Taylor)
Added support for the Python 3.12 walk_up keyword argument in anyio.Path.relative_to() (PR by Colin Taylor)
Fixed passing total_tokens to anyio.CapacityLimiter() as a keyword argument not working on the trio backend (#515)
Fixed Process.aclose() not performing the minimum level of necessary cleanup when cancelled. Previously:
Process.aclose() could leak an orphan processrun_process() could very briefly leak an orphan process.Process.aclose() or run_process() on Trio could leave standard streams unclosed(PR by Ganden Schaffner)
Fixed Process.stdin.aclose(), Process.stdout.aclose(), and Process.stderr.aclose() not including a checkpoint on asyncio (PR by Ganden Schaffner)
Fixed documentation on how to provide your own typed attributes
Add support for byte-based paths in connect_unix, create_unix_listeners, create_unix_datagram_socket, and create_connected_unix_datagram_socket. (PR b
Add support for byte-based paths in connect_unix, create_unix_listeners, create_unix_datagram_socket, and create_connected_unix_datagram_socket. (PR by Lura Skye)
Enabled the Event and CapacityLimiter classes to be instantiated outside an event loop thread
Broadly improved/fixed the type annotations. Among other things, many functions and methods that take variadic positional arguments now make use of PEP 646 TypeVarTuple to allow the positional arguments to be validated by static type checkers. These changes affected numerous methods and functions, including:
anyio.run()TaskGroup.start_soon()anyio.from_thread.run()anyio.from_thread.run_sync()anyio.to_thread.run_sync()anyio.to_process.run_sync()BlockingPortal.call()BlockingPortal.start_task_soon()BlockingPortal.start_task()(also resolves #560)
Fixed various type annotations of anyio.Path to match Typeshed:
anyio.Path.__lt__()anyio.Path.__le__()anyio.Path.__gt__()anyio.Path.__ge__()anyio.Path.__truediv__()anyio.Path.__rtruediv__()anyio.Path.hardlink_to()anyio.Path.samefile()anyio.Path.symlink_to()anyio.Path.with_segments()(PR by Ganden Schaffner)
Fixed adjusting the total number of tokens in a CapacityLimiter on asyncio failing to wake up tasks waiting to acquire the limiter in certain edge cases (fixed with help from Egor Blagov)
Fixed loop_factory and use_uvloop options not being used on the asyncio backend (#643)
Fixed cancellation propagating on asyncio from a task group to child tasks if the task hosting the task group is in a shielded cancel scope (#642)
Renamed the cancellable argument in anyio.to_thread.run_sync() to abandon_on_cancel (and deprecated the old parameter name)
trio.to_thread.run_sync() using the abandon_on_cancel keyword argument instead of cancellablecancellable argument in anyio.to_thread.run_sync() to abandon_on_cancel (and deprecated the old parameter name)anyio.from_thread.check_cancelled()ResourceGuard class in the public API (#627)RuntimeError: Runner is closed when running higher-scoped async generator fixtures in some cases (#619)asyncio and trio where reraising a cancellation exception in an except* block would incorrectly bubble out of its cancel scope (#634)BACKWARDS INCOMPATIBLE Replaced AnyIO\'s own ExceptionGroup class with the PEP 654 BaseExceptionGroup and ExceptionGroup
ExceptionGroup class with the PEP 654 BaseExceptionGroup and ExceptionGroupExceptionGroup (or BaseExceptionGroup if one or more BaseException were included)TaskGroup always hits a yield point, regardless of whether there are running child tasks to be waited onanyio.Path.relative_to() and anyio.Path.is_relative_to() to only accept one argument, as passing multiple arguments is deprecated as of Python 3.12@asyncio.coroutine)policy option on the asyncio backend was changed to loop_factory to accommodate asyncio.Runneranyio.run() to use asyncio.Runner (or a back-ported version of it on Pythons older than 3.11) on the asyncio backendanyio.Path.is_junction() and anyio.Path.walk() methodscreate_unix_datagram_socket and create_connected_unix_datagram_socket to create UNIX datagram sockets (PR by Jean Hominal)from_thread.run and from_thread.run_sync not setting sniffio on asyncio. As a result:
from_thread.run_sync failing when used to call sniffio-dependent functions on asynciofrom_thread.run failing when used to call sniffio-dependent functions on asyncio from a thread running trio or curiofrom_thread.start_blocking_portal(backend="asyncio") in a thread running trio or curio (PR by Ganden Schaffner)item_type argument of create_memory_object_stream was deprecated. To indicate the item type handled by the stream, use create_memory_object_stream[T_Item]() instead. Type checking should no longer fail when annotating memory object streams with uninstantiable item types (PR by Ganden Schaffner)CancelScope.cancelled_caught property which tells users if the cancel scope suppressed a cancellation exceptionfail_after() raising an unwarranted TimeoutError when the cancel scope was cancelled before reaching its deadlineMemoryObjectReceiveStream.receive() causing the receiving task on asyncio to remain in a cancelled state if the operation was cancelled after an item was queued to be received by the task (but before the task could actually receive the item)TaskGroup.start() on asyncio not responding to cancellation from the outsideBlockingPortal not notifying synchronous listeners (concurrent.futures.wait()) when they're cancelledEvent.wait() on asyncio in the case where the event was not yet setanyio.to_process() being "lost" as unusable to the process pool when processes that have idled over 5 minutes are pruned at part of the to_process.run_sync() call, leading to increased memory consumption (PR by Anael Gorfinkel)Changes since 4.0.0rc1:
TaskGroup.start_soon() to accept any awaitables (already in v3.7.0 but was missing from 4.0.0rc1)CancelScope to also consider the cancellation count (in addition to the cancel message) on asyncio to determine if a cancellation exception should be swallowed on scope exit, to combat issues where third party libraries catch the CancelledError and raise another, thus erasing the original cancel messageTLSListener.handle_handshake_error() on asyncio to log "NoneType: None" instead of the error (PR by Ganden Schaffner)item_type argument to create_memory_object_stream() (but using it raises a deprecation warning and does nothing with regards to the static types of the returned streams)anyio.to_process() being "lost" as unusable to the process pool when processes that have idled over 5 minutes are pruned at part of the to_process.run_sync() call, leading to increased memory consumption (PR by Anael Gorfinkel)Nothing published for this version
- Fixed sending large buffers via UNIX stream sockets on asyncio
Fixed sending large buffers via UNIX stream sockets on asyncio
Fixed several minor documentation issues (broken links to classes, missing classes or attributes)
- Dropped support for Python 3.6
Dropped support for Python 3.6
Improved type annotations:
Several functions and methods that were previously annotated as accepting Coroutine[Any, Any, Any] as the return type of the callable have been amended to accept Awaitable[Any] instead, to allow a slightly broader set of coroutine-like inputs, like async_generator_asend objects returned from the asend() method of async generators, and to match the trio annotations:
anyio.run()
anyio.from_thread.run()
TaskGroup.start_soon()
TaskGroup.start()
BlockingPortal.call()
BlockingPortal.start_task_soon()
BlockingPortal.start_task()
Note that this change involved only changing the type annotations; run-time functionality was not altered.
The TaskStatus class is now a generic protocol, and should be parametrized to indicate the type of the value passed to task_status.started()
The Listener class is now covariant in its stream type
create_memory_object_stream() now allows passing only item_type
Object receive streams are now covariant and object send streams are correspondingly contravariant
Changed TLSAttribute.shared_ciphers to match the documented semantics of SSLSocket.shared_ciphers of always returning None for client-side streams
Fixed CapacityLimiter on the asyncio backend to order waiting tasks in the FIFO order (instead of LIFO) (PR by Conor Stevenson)
Fixed CancelScope.cancel() not working on asyncio if called before entering the scope
Fixed open_signal_receiver() inconsistently yielding integers instead of signal.Signals instances on the trio backend
Fixed to_thread.run_sync() hanging on asyncio if the target callable raises StopIteration
Fixed start_blocking_portal() raising an unwarranted RuntimeError: This portal is not running if a task raises an exception that causes the event loop to be closed
Fixed current_effective_deadline() not returning -inf on asyncio when the currently active cancel scope has been cancelled (PR by Ganden Schaffner)
Fixed the OP_IGNORE_UNEXPECTED_EOF flag in an SSL context created by default in TLSStream.wrap() being inadvertently set on Python 3.11.3 and 3.10.11
Fixed CancelScope to properly handle asyncio task uncancellation on Python 3.11 (PR by Nikolay Bryskin)
Fixed OSError when trying to use create_tcp_listener() to bind to a link-local IPv6 address (and worked around related bugs in uvloop )
Worked around a PyPy bug when using anyio.getaddrinfo() with for IPv6 link-local addresses containing interface names
Nothing published for this version
- Pinned Trio to < 0.22 to avoid incompatibility with AnyIO’s ExceptionGroup class causing AttributeError: 'NonBaseMultiError' object has no attribute
Pinned Trio to < 0.22 to avoid incompatibility with AnyIO’s ExceptionGroup class causing AttributeError: 'NonBaseMultiError' object has no attribute '_exceptions'
- Fixed exception handler in the asyncio test runner not properly handling a context that does not contain the exception key
Fixed exception handler in the asyncio test runner not properly handling a context that does not contain the exception key
- Fixed TypeError in get_current_task() on asyncio when using a custom Task factory
Fixed TypeError in get_current_task() on asyncio when using a custom Task factory
Updated type annotations on run_process() and open_process() :
command now accepts accepts bytes and sequences of bytes
stdin , stdout and stderr now accept file-like objects (PR by John T. Wodder II)
Changed the pytest plugin to run both the setup and teardown phases of asynchronous generator fixtures within a single task to enable use cases such as cancel scopes and task groups where a context manager straddles the yield
- Added start_new_session keyword argument to run_process() and open_process() (PR by Jordan Speicher)
Added start_new_session keyword argument to run_process() and open_process() (PR by Jordan Speicher)
Fixed deadlock in synchronization primitives on asyncio which can happen if a task acquiring a primitive is hit with a native (not AnyIO) cancellation with just the right timing, leaving the next acquiring task waiting forever ( #398 )
Added workaround for bpo-46313 to enable compatibility with OpenSSL 3.0
- Added context propagation to/from worker threads in to_thread.run_sync() , from_thread.run() and from_thread.run_sync() ( #363 ; partially based on
Added context propagation to/from worker threads in to_thread.run_sync() , from_thread.run() and from_thread.run_sync() ( #363 ; partially based on a PR by Sebastián Ramírez)
NOTE : Requires Python 3.7 to work properly on asyncio!
Fixed race condition in Lock and Semaphore classes when a task waiting on acquire() is cancelled while another task is waiting to acquire the same primitive ( #387 )
Fixed async context manager’s aexit() method not being called in BlockingPortal.wrap_async_context_manager() if the host task is cancelled ( #381 ; PR by Jonathan Slenders)
Fixed worker threads being marked as being event loop threads in sniffio
Fixed task parent ID not getting set to the correct value on asyncio
Enabled the test suite to run without IPv6 support, trio or pytest plugin autoloading
- Fixed BrokenResourceError instead of EndOfStream being raised in TLSStream when the peer abruptly closes the connection while TLSStream is receiving
Fixed BrokenResourceError instead of EndOfStream being raised in TLSStream when the peer abruptly closes the connection while TLSStream is receiving data with standard_compatible=False set
- Fixed UNIX socket listener not setting accepted sockets to non-blocking mode on asyncio
Fixed UNIX socket listener not setting accepted sockets to non-blocking mode on asyncio
Changed unconnected UDP sockets to be always bound to a local port (on “any” interface) to avoid errors on asyncio + Windows
- Fixed cancellation problem on asyncio where level-triggered cancellation for all parent cancel scopes would not resume after exiting a shielded nest
Fixed cancellation problem on asyncio where level-triggered cancellation for all parent cancel scopes would not resume after exiting a shielded nested scope ( #370 )
- Added missing documentation for the ExceptionGroup.exceptions attribute
Added missing documentation for the ExceptionGroup.exceptions attribute
Changed the asyncio test runner not to use uvloop by default (to match the behavior of anyio.run() )
Fixed RuntimeError on asyncio when a CancelledError is raised from a task spawned through a BlockingPortal ( #357 )
Fixed asyncio warning about a Future with an exception that was never retrieved which happened when a socket was already written to but the peer abruptly closed the connection
- Added asynchronous Path class
Added asynchronous Path class
Added the wrap_file() function for wrapping existing files as asynchronous file objects
Relaxed the type of the path initializer argument to FileReadStream and FileWriteStream so they accept any path-like object (including the new asynchronous Path class)
Dropped unnecessary dependency on the async_generator library
Changed the generics in AsyncFile so that the methods correctly return either str or bytes based on the argument to open_file()
Fixed an asyncio bug where under certain circumstances, a stopping worker thread would still accept new assignments, leading to a hang
- Fixed idle thread pruning on asyncio sometimes causing an expired worker thread to be assigned a task
Fixed idle thread pruning on asyncio sometimes causing an expired worker thread to be assigned a task
- Fixed the type annotation of DeprecatedAwaitable(|List|Float).__await__ to match the typing.Awaitable protocol
Added Python 3.10 compatibility
Added the ability to close memory object streams synchronously (including support for use as a synchronous context manager)
Changed the default value of the use_uvloop asyncio backend option to False to prevent unsafe event loop policy changes in different threads
Fixed to_thread.run_sync() hanging on the second call on asyncio when used with loop.run_until_complete()
Fixed to_thread.run_sync() prematurely marking a worker thread inactive when a task await on the result is cancelled
Fixed ResourceWarning about an unclosed socket when UNIX socket connect fails on asyncio
Fixed the type annotation of open_signal_receiver() as a synchronous context manager
Fixed the type annotation of DeprecatedAwaitable(|List|Float).await to match the typing.Awaitable protocol
- Fixed a deprecation warning message to refer to maybe_async() and not maybe_awaitable() (PR by Thomas Grainger)
Added env and cwd keyword arguments to run_process() and open_process .
Added support for mutation of CancelScope.shield (PR by John Belmonte)
Added the sleep_forever() and sleep_until() functions
Changed asyncio task groups so that if the host and child tasks have only raised CancelledErrors , just one CancelledError will now be raised instead of an ExceptionGroup , allowing asyncio to ignore it when it propagates out of the task
Changed task names to be converted to str early on asyncio (PR by Thomas Grainger)
Fixed sniffio._impl.AsyncLibraryNotFoundError: unknown async library, or not in async context on asyncio and Python 3.6 when to_thread.run_sync() is used from loop.run_until_complete()
Fixed odd ExceptionGroup: 0 exceptions were raised in the task group appearing under certain circumstances on asyncio
Fixed wait_all_tasks_blocked() returning prematurely on asyncio when a previously blocked task is cancelled (PR by Thomas Grainger)
Fixed declared return type of TaskGroup.start() (it was declared as None , but anything can be returned from it)
Fixed TextStream.extra_attributes raising AttributeError (PR by Thomas Grainger)
Fixed await maybe_async(current_task()) returning None (PR by Thomas Grainger)
Fixed: pickle.dumps(current_task()) now correctly raises TypeError instead of pickling to None (PR by Thomas Grainger)
Fixed return type annotation of Event.wait() ( bool → None ) (PR by Thomas Grainger)
Fixed return type annotation of RunVar.get() to return either the type of the default value or the type of the contained value (PR by Thomas Grainger)
Fixed a deprecation warning message to refer to maybe_async() and not maybe_awaitable() (PR by Thomas Grainger)
Filled in argument and return types for all functions and methods previously missing them (PR by Thomas Grainger)
- Fixed to_thread.run_sync() raising RuntimeError on asyncio when no “root” task could be found for setting up a cleanup callback. This was a problem
Fixed to_thread.run_sync() raising RuntimeError on asyncio when no “root” task could be found for setting up a cleanup callback. This was a problem at least on Tornado and possibly also Twisted in asyncio compatibility mode. The life of worker threads is now bound to the the host task of the topmost cancel scope hierarchy starting from the current one, or if no cancel scope is active, the current task.
- BACKWARDS INCOMPATIBLE Submodules under anyio.abc. have been made private (use only anyio.abc from now on).
Curio support has been dropped (see the FAQ as for why)
API changes:
BACKWARDS INCOMPATIBLE Submodules under anyio.abc. have been made private (use only anyio.abc from now on).
BACKWARDS INCOMPATIBLE The following method was previously a coroutine method and has been converted into a synchronous one:
MemoryObjectReceiveStream.receive_nowait()
The following functions and methods are no longer asynchronous but can still be awaited on (doing so will emit a deprecation warning):
current_time()
current_effective_deadline()
get_current_task()
get_running_tasks()
CancelScope.cancel()
CapacityLimiter.acquire_nowait()
CapacityLimiter.acquire_on_behalf_of_nowait()
Condition.release()
Event.set()
Lock.release()
MemoryObjectSendStream.send_nowait()
Semaphore.release()
The following functions now return synchronous context managers instead of asynchronous context managers (and emit deprecation warnings if used as async context managers):
fail_after()
move_on_after()
open_cancel_scope() (now just CancelScope() ; see below)
open_signal_receiver()
The following functions and methods have been renamed/moved (will now emit deprecation warnings when you use them by their old names):
create_blocking_portal() → anyio.from_thread.BlockingPortal()
create_capacity_limiter() → anyio.CapacityLimiter()
create_event() → anyio.Event()
create_lock() → anyio.Lock()
create_condition() → anyio.Condition()
create_semaphore() → anyio.Semaphore()
current_default_worker_thread_limiter() → anyio.to_thread.current_default_thread_limiter()
open_cancel_scope() → anyio.CancelScope()
run_sync_in_worker_thread() → anyio.to_thread.run_sync()
run_async_from_thread() → anyio.from_thread.run()
run_sync_from_thread() → anyio.from_thread.run_sync()
BlockingPortal.spawn_task → BlockingPortal.start_task_soon
CapacityLimiter.set_total_tokens() → limiter.total_tokens = ...
TaskGroup.spawn() → TaskGroup.start_soon()
BACKWARDS INCOMPATIBLE start_blocking_portal() must now be used as a context manager (it no longer returns a BlockingPortal, but a context manager that yields one)
BACKWARDS INCOMPATIBLE The BlockingPortal.stop_from_external_thread() method (use portal.call(portal.stop) instead now)
BACKWARDS INCOMPATIBLE The SocketStream and SocketListener classes were made non-generic
Made all non-frozen dataclasses hashable with eq=False
Removed slots from BlockingPortal
See the migration documentation for instructions on how to deal with these changes.
Improvements to running synchronous code:
Added the run_sync_from_thread() function
Added the run_sync_in_process() function for running code in worker processes (big thanks to Richard Sheridan for his help on this one!)
Improvements to sockets and streaming:
Added the UNIXSocketStream class which is capable of sending and receiving file descriptors
Added the FileReadStream and FileWriteStream classes
create_unix_listener() now removes any existing socket at the given path before proceeding (instead of raising OSError: Address already in use )
Improvements to task groups and cancellation:
Added the TaskGroup.start() method and a corresponding BlockingPortal.start_task() method
Added the name argument to BlockingPortal.start_task_soon() (renamed from BlockingPortal.spawn_task() )
Changed CancelScope.deadline to be writable
Added the following functions in the anyio.lowlevel module:
checkpoint()
checkpoint_if_cancelled()
cancel_shielded_checkpoint()
Improvements and changes to synchronization primitives:
Added the Lock.acquire_nowait() , Condition.acquire_nowait() and Semaphore.acquire_nowait() methods
Added the statistics() method to Event , Lock , Condition , Semaphore , CapacityLimiter , MemoryObjectReceiveStream and MemoryObjectSendStream
Lock and Condition can now only be released by the task that acquired them. This behavior is now consistent on all backends whereas previously only Trio enforced this.
The CapacityLimiter.total_tokens property is now writable and CapacityLimiter.set_total_tokens() has been deprecated
Added the max_value property to Semaphore
Asyncio specific improvements (big thanks to Thomas Grainger for his effort on most of these!):
Cancel scopes are now properly enforced with native asyncio coroutine functions (without any explicit AnyIO checkpoints)
Changed the asyncio CancelScope to raise a RuntimeError if a cancel scope is being exited before it was even entered
Changed the asyncio test runner to capture unhandled exceptions from asynchronous callbacks and unbound native tasks which are then raised after the test function (or async fixture setup or teardown) completes
Changed the asyncio TaskGroup.start_soon() (formerly spawn() ) method to call the target function immediately before starting the task, for consistency across backends
Changed the asyncio TaskGroup.start_soon() (formerly spawn() ) method to avoid the use of a coroutine wrapper on Python 3.8+ and added a hint for hiding the wrapper in tracebacks on earlier Pythons (supported by Pytest, Sentry etc.)
Changed the default thread limiter on asyncio to use a RunVar so it is scoped to the current event loop, thus avoiding potential conflict among multiple running event loops
Thread pooling is now used on asyncio with run_sync_in_worker_thread()
Fixed current_effective_deadline() raising KeyError on asyncio when no cancel scope is active
Added the RunVar class for scoping variables to the running event loop
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
- Added the maybe_async() and maybe_async_cm() functions to facilitate forward
Added the maybe_async() and maybe_async_cm() functions to facilitate forward
- Added the spawn_task() and wrap_async_context_manager() methods to BlockingPortal
Added the spawn_task() and wrap_async_context_manager() methods to BlockingPortal
Added the handshake_timeout and error_handler parameters to TLSListener
Fixed Event objects on the trio backend not inheriting from anyio.abc.Event
Fixed run_sync_in_worker_thread() raising UnboundLocalError on asyncio when cancelled
Fixed send() on socket streams not raising any exception on asyncio, and an unwrapped BrokenPipeError on trio and curio when the peer has disconnected
Fixed MemoryObjectSendStream.send() raising BrokenResourceError when the last receiver is closed right after receiving the item
Fixed ValueError: Invalid file descriptor: -1 when closing a SocketListener on asyncio
- Fixed one more case of AttributeError: 'async_generator_asend' object has no attribute 'cr_await' on asyncio
Fixed one more case of AttributeError: 'async_generator_asend' object has no attribute 'cr_await' on asyncio
- Fixed broken MultiListener.extra() (PR by daa)
Fixed broken MultiListener.extra() (PR by daa)
Fixed TLSStream returning an empty bytes object instead of raising EndOfStream when trying to receive from the stream after a closing handshake
Fixed AttributeError when cancelling a task group’s scope inside an async test fixture on asyncio
Fixed wait_all_tasks_blocked() raising AttributeError on asyncio if a native task is waiting on an async generator’s asend() method
- BACKWARDS INCOMPATIBLE Some functions have been renamed or removed (see further below for socket/fileio API changes):
General new features:
Added support for subprocesses
Added support for “blocking portals” which allow running functions in the event loop thread from external threads
Added the anyio.aclose_forcefully() function for closing asynchronous resources as quickly as possible
General changes/fixes:
BACKWARDS INCOMPATIBLE Some functions have been renamed or removed (see further below for socket/fileio API changes):
finalize() → (removed; use contextlib.aclosing() instead)
receive_signals() → open_signal_receiver()
run_in_thread() → run_sync_in_worker_thread()
current_default_thread_limiter() → current_default_worker_thread_limiter()
ResourceBusyError → BusyResourceError
BACKWARDS INCOMPATIBLE Exception classes were moved to the top level package
Dropped support for Python 3.5
Bumped minimum versions of trio and curio to v0.16 and v1.4, respectively
Changed the repr() of ExceptionGroup to match trio’s MultiError
Backend specific changes and fixes:
asyncio : Added support for ProactorEventLoop . This allows asyncio applications to use AnyIO on Windows even without using AnyIO as the entry point.
asyncio : The asyncio backend now uses asyncio.run() behind the scenes which properly shuts down async generators and cancels any leftover native tasks
curio : Worked around the limitation where a task can only be cancelled twice (any cancellations beyond that were ignored)
asyncio + curio : a cancellation check now calls sleep(0) , allowing the scheduler to switch to a different task
asyncio + curio : Host name resolution now uses IDNA 2008 (with UTS 46 compatibility mapping, just like trio)
asyncio + curio : Fixed a bug where a task group would abandon its subtasks if its own cancel scope was cancelled while it was waiting for subtasks to finish
asyncio + curio : Fixed recursive tracebacks when a single exception from an inner task group is reraised in an outer task group
Socket/stream changes:
BACKWARDS INCOMPATIBLE The stream class structure was completely overhauled. There are now separate abstract base classes for receive and send streams, byte streams and reliable and unreliable object streams. Stream wrappers are much better supported by this new ABC structure and a new “typed extra attribute” system that lets you query the wrapper chain for the attributes you want via .extra(...) .
BACKWARDS INCOMPATIBLE Socket server functionality has been refactored into a network-agnostic listener system
BACKWARDS INCOMPATIBLE TLS functionality has been split off from SocketStream and can now work over any bidirectional bytes-based stream – you can now establish a TLS encrypted communications pathway over UNIX sockets or even memory object streams. The TLSRequired exception has also been removed as it is no longer necessary.
BACKWARDS INCOMPATIBLE Buffering functionality ( receive_until() and receive_exactly() ) was split off from SocketStream into a stream wrapper class ( anyio.streams.buffered.BufferedByteReceiveStream )
BACKWARDS INCOMPATIBLE IPv6 addresses are now reported as 2-tuples. If original 4-tuple form contains a nonzero scope ID, it is appended to the address with % as the separator.
BACKWARDS INCOMPATIBLE Byte streams (including socket streams) now raise EndOfStream instead of returning an empty bytes object when the stream has been closed from the other end
BACKWARDS INCOMPATIBLE The socket API has changes:
create_tcp_server() → create_tcp_listener()
create_unix_server() → create_unix_listener()
create_udp_socket() had some of its parameters changed:
interface → local_address
port → local_port
reuse_address was replaced with reuse_port (and sets SO_REUSEPORT instead of SO_REUSEADDR )
connect_tcp() had some of its parameters changed:
address → remote_address
port → remote_port
bind_host → local_address
bind_port → (removed)
autostart_tls → tls
tls_hostname (new parameter, when you want to match the certificate against against something else than remote_address )
connect_tcp() now returns a TLSStream if TLS was enabled
notify_socket_closing() was removed, as it is no longer used by AnyIO
SocketStream has changes to its methods and attributes:
address → .extra(SocketAttribute.local_address)
alpn_protocol → .extra(TLSAttribute.alpn_protocol)
close() → aclose()
get_channel_binding → .extra(TLSAttribute.channel_binding_tls_unique)
cipher → .extra(TLSAttribute.cipher)
getpeercert → .extra(SocketAttribute.peer_certificate) or .extra(SocketAttribute.peer_certificate_binary)
getsockopt() → .extra(SocketAttribute.raw_socket).getsockopt(...)
peer_address → .extra(SocketAttribute.remote_address)
receive_chunks() → (removed; use async for on the stream instead)
receive_delimited_chunks() → (removed)
receive_exactly() → BufferedReceiveStream.receive_exactly()
receive_some() → receive()
receive_until() → BufferedReceiveStream.receive_until()
send_all() → send()
setsockopt() → .extra(SocketAttribute.raw_socket).setsockopt(...)
shared_ciphers → .extra(TLSAttribute.shared_ciphers)
server_side → .extra(TLSAttribute.server_side)
start_tls() → stream = TLSStream.wrap(...)
tls_version → .extra(TLSAttribute.tls_version)
UDPSocket has changes to its methods and attributes:
address → .extra(SocketAttribute.local_address)
getsockopt() → .extra(SocketAttribute.raw_socket).getsockopt(...)
port → .extra(SocketAttribute.local_port)
receive() no longer takes a maximum bytes argument
receive_packets() → (removed; use async for on the UDP socket instead)
send() → requires a tuple for destination now (address, port), for compatibility with the new UnreliableObjectStream interface. The sendto() method works like the old send() method.
setsockopt() → .extra(SocketAttribute.raw_socket).setsockopt(...)
BACKWARDS INCOMPATIBLE Renamed the max_size parameter to max_bytes wherever it occurred (this was inconsistently named max_bytes in some subclasses before)
Added memory object streams as a replacement for queues
Added stream wrappers for encoding/decoding unicode strings
Support for the SO_REUSEPORT option (allows binding more than one socket to the same address/port combination, as long as they all have this option set) has been added to TCP listeners and UDP sockets
The send_eof() method was added to all (bidirectional) streams
File I/O changes:
BACKWARDS INCOMPATIBLE Asynchronous file I/O functionality now uses a common code base ( anyio.AsyncFile ) instead of backend-native classes
BACKWARDS INCOMPATIBLE The File I/O API has changes to its functions and methods:
aopen() → open_file()
AsyncFileclose() → AsyncFileaclose()
Task synchronization changes:
BACKWARDS INCOMPATIBLE Queues were replaced by memory object streams
BACKWARDS INCOMPATIBLE Added the acquire() and release() methods to the Lock , Condition and Semaphore classes
BACKWARDS INCOMPATIBLE Removed the Event.clear() method. You must now replace the event object with a new one rather than clear the old one.
Fixed Condition.wait() not working on asyncio and curio (PR by Matt Westcott)
Testing changes:
BACKWARDS INCOMPATIBLE Removed the --anyio-backends command line option for the pytest plugin. Use the -k option to do ad-hoc filtering, and the anyio_backend fixture to control which backends you wish to run the tests by default.
The pytest plugin was refactored to run the test and all its related async fixtures inside the same event loop, making async fixtures much more useful
Fixed Hypothesis support in the pytest plugin (it was not actually running the Hypothesis tests at all)
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
- Added async name resolution functions ( anyio.getaddrinfo() and anyio.getnameinfo() )
Added async name resolution functions ( anyio.getaddrinfo() and anyio.getnameinfo() )
Added the family and reuse_address parameters to anyio.create_udp_socket() (Enables multicast support; test contributed by Matthias Urlichs)
Fixed fail.after(0) not raising a timeout error on asyncio and curio
Fixed move_on_after() and fail_after() getting stuck on curio in some circumstances
Fixed socket operations not allowing timeouts to cancel the task
Fixed API documentation on Stream.receive_until() which claimed that the delimiter will be included in the returned data when it really isn’t
Harmonized the default task names across all backends
wait_all_tasks_blocked() no longer considers tasks waiting on sleep(0) to be blocked on asyncio and curio
Fixed the type of the address parameter in UDPSocket.send() to include IPAddress objects (which were already supported by the backing implementation)
Fixed UDPSocket.send() to resolve host names using anyio.getaddrinfo() before calling socket.sendto() to avoid blocking on synchronous name resolution
Switched to using anyio.getaddrinfo() for name lookups
- Fixed warnings caused by trio 0.15
Fixed warnings caused by trio 0.15
Worked around a compatibility issue between uvloop and Python 3.9 (missing shutdown_default_executor() method)
- Fixed compatibility with Curio 1.0
Fixed compatibility with Curio 1.0
Made it possible to assert fine grained control over which AnyIO backends and backend options are being used with each test
Added the address and peer_address properties to the SocketStream interface
Your coding agent can read these notes before it upgrades. Set up the MCP server →