Skip to content

Releases: agronholm/anyio

4.15.1

Choose a tag to compare

@github-actions github-actions released this 05 Sep 10:42

4.15.0

Choose a tag to compare

@github-actions github-actions released this 02 Sep 21:46
  • 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()

    • The started task shouldn't get a CancelledError until the first checkpoint after the started() call.
    • A value passed to started() should be available on the TaskHandle and correctly passed back to the caller of start even if cancelled.
    • The CancelledError shouldn't leak out of the 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)

4.14.2

Choose a tag to compare

@github-actions github-actions released this 12 Jul 20:29
  • Changed ByteReceiveStream.receive() implementations to raise a ValueError when max_bytes is not a positive integer (#1191)
  • Fixed 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).
  • Fixed 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 behavior
  • Fixed TLSStream.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)
  • Fixed anyio.open_process() (and run_process()) ignoring the extra_groups argument, as it mistakenly passed the value of the group argument instead (#1209)
  • Fixed 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)
  • Fixed 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)
  • Fixed unnecessary CPU spin when delivering cancellation from CancelScope on asyncio under certain conditions, including improper cancel scope nesting (#1111)

4.14.1

Choose a tag to compare

@github-actions github-actions released this 24 Jun 20:56
  • 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)

4.14.0

Choose a tag to compare

@github-actions github-actions released this 15 Jun 22:00
  • 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.CancelScope
    • anyio.CapacityLimiter
    • anyio.Condition
    • anyio.Event
    • anyio.Lock
    • anyio.ResourceGuard
    • anyio.Semaphore
  • Fixed 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)

4.13.0

Choose a tag to compare

@github-actions github-actions released this 24 Mar 12:59
  • Dropped support for Python 3.9
  • Added a ttl parameter to the anyio.functools.lru_cache wrapper (#1073; PR by @Graeme22)
  • Widened the type annotations of file I/O streams to accept IO[bytes] instead of just BinaryIO (#1078)
  • Fixed 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)
  • Fixed the BrokenResourceError raised by the asyncio SocketStream not having the original exception as its cause (#1055; PR by @veeceey)
  • Fixed the TypeError raised when using "func" as a parameter name in pytest.mark.parametrize when using the pytest plugin (#1068; PR by @JohnnyDeuss)
  • Fixed the pytest plugin not running tests that had the anyio marker added programmatically via pytest_collection_modifyitems (#422; PR by @chbndrhnns)
  • Fixed cancellation exceptions leaking from a CancelScope on asyncio when they are contained in an exception group alongside non-cancellation exceptions (#1091; PR by @gschaffner)
  • Fixed Condition.wait() not passing on a notification when the task is cancelled but already received a notification
  • Fixed inverted condition in the process pool shutdown phase which would cause still-running pooled processes not to be terminated (#1074; PR by @bysiber)

4.12.1

Choose a tag to compare

@github-actions github-actions released this 06 Jan 11:45
  • Changed all functions currently raising the private NoCurrentAsyncBackend exception (since v4.12.0) to instead raise the public NoEventLoopError exception (#1048)
  • Fixed anyio.functools.lru_cache not working with instance methods (#1042)

4.12.0

Choose a tag to compare

@github-actions github-actions released this 30 Nov 13:37
  • Added support for asyncio's task call graphs on Python 3.14 and later when using AnyIO's task groups (#1025)
  • Added an asynchronous implementation of the functools module (#1001)
  • Added support for uvloop=True on Windows via the winloop implementation (#960; PR by @Vizonex)
  • Added support for use as a context manager to anyio.lowlevel.RunVar (#1003)
  • Added __all__ declarations to public submodules (anyio.lowlevel etc.) (#1009)
  • Added the ability to set the token count of a CapacityLimiter to zero (#1019; requires Python 3.10 or later when using Trio)
  • Added parameters case_sensitive and recurse_symlinks along with support for path-like objects to anyio.Path.glob() and anyio.Path.rglob() (#1033; PR by @NorthIsUp)
  • Dropped sniffio as a direct dependency and added the get_available_backends() function (#1021)
  • Fixed Process.stdin.send() not raising ClosedResourceError and BrokenResourceError on asyncio. Previously, a non-AnyIO exception was raised in such cases (#671; PR by @gschaffner)
  • Fixed Process.stdin.send() not checkpointing before writing data on asyncio (#1002; PR by @gschaffner)
  • Fixed a race condition where cancelling a Future from BlockingPortal.start_task_soon() would sometimes not cancel the async function (#1011; PR by @gschaffner)
  • Fixed the presence of the pytest plugin causing breakage with older versions of pytest (<= 6.1.2) (#1028; PR by @saper)
  • Fixed a rarely occurring RuntimeError: Set changed size during iteration while shutting down the process pool when using the asyncio backend (#985)

4.11.0

Choose a tag to compare

@github-actions github-actions released this 23 Sep 09:18
  • Added support for cancellation reasons (the reason parameter to CancelScope.cancel()) (#975)
  • Bumped the minimum version of Trio to v0.31.0
  • Added the ability to enter the event loop from foreign (non-worker) threads by passing the return value of anyio.lowlevel.current_token() to anyio.from_thread.run() and anyio.from_thread.run_sync() as the token keyword argument (#256)
  • Added pytest option (anyio_mode = "auto") to make the pytest plugin automatically handle all async tests (#971)
  • Added the anyio.Condition.wait_for() method for feature parity with asyncio (#974)
  • Changed the default type argument of anyio.abc.TaskStatus from Any to None (#964)
  • Fixed TCP listener behavior to guarantee the same ephemeral port is used for all socket listeners when local_port=0 (#857; PR by @11kkw and @agronholm)
  • Fixed inconsistency between Trio and asyncio where a TCP stream that previously raised a 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)

4.10.0

Choose a tag to compare

@github-actions github-actions released this 04 Aug 08:54
  • Added the feed_data() method to the BufferedByteReceiveStream class, allowing users to inject data directly into the buffer
  • Added various class methods to wrap existing sockets as listeners or socket streams:
    • SocketListener.from_socket()
    • SocketStream.from_socket()
    • UNIXSocketStream.from_socket()
    • UDPSocket.from_socket()
    • ConnectedUDPSocket.from_socket()
    • UNIXDatagramSocket.from_socket()
    • ConnectedUNIXDatagramSocket.from_socket()
  • Added a hierarchy of connectable stream classes for transparently connecting to various remote or local endpoints for exchanging bytes or objects
  • Added context manager mix-in classes (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)
  • Added the ability to specify the thread name in start_blocking_portal() (#818; PR by @davidbrochart)
  • Added 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)
  • Incorporated several documentation improvements from the EuroPython 2025 sprint (special thanks to the sprinters: Emmanuel Okedele, Jan Murre, Euxenia Miruna Goia and Christoffer Fjord)
  • Added a documentation page explaining why one might want to use AnyIO's APIs instead of asyncio's
  • Updated the to_interpreters module to use the public concurrent.interpreters API on Python 3.14 or later
  • Fixed anyio.Path.copy() and anyio.Path.copy_into() failing on Python 3.14.0a7
  • Fixed return annotation of __aexit__ on async context managers. CMs which can suppress exceptions should return bool, or None otherwise. (#913; PR by @Enegg)
  • Fixed rollover boundary check in SpooledTemporaryFile so that rollover only occurs when the buffer size exceeds max_size (#915; PR by @11kkw)
  • Migrated testing and documentation dependencies from extras to dependency groups
  • Fixed compatibility of anyio.to_interpreter with Python 3.14.0b2 (#926; PR by @hroncok)
  • Fixed SyntaxWarning on Python 3.14 about return in finally (#816)
  • Fixed RunVar name conflicts. RunVar instances with the same name should not share storage (#880; PR by @vimfu)
  • Renamed the BrokenWorkerIntepreter exception to BrokenWorkerInterpreter. The old name is available as a deprecated alias. (#938; PR by @ayussh-verma)
  • Fixed an edge case in 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)