Visitar URL original
Releases · agronholm/anyio · GitHub
Skip to content

Releases

4.16.0

Choose a tag to compare

@github-actions github-actions released this 01 Nov 11:20

New features

  • Added BlockingPortal.call_async() for asynchronously calling into an event loop with optional abandonment on cancellation (#1342; PR by @davidbrochart)
  • Added SOCK_SEQPACKET support to connect_unix() and create_unix_listener() (#1349; PR by @theunkn0wn1)

Other changes

  • Changed UDP sockets on the asyncio backend to make send() wait until the datagram has been passed to the operating system (#1294; PR by @graingert)

Bug fixes

  • Fixed documentation implying that use_uvloop=True falls back to the standard event loop when uvloop (winloop on Windows) is not installed, and showed how to skip the corresponding pytest backend variant when the dependency is missing (#645; PR by @GruffElixir)
  • Fixed get_current_task() on the asyncio backend raising an opaque TypeError: cannot create weak reference to 'NoneType' object instead of a clear error when called from a callback scheduled via loop.call_soon_threadsafe() (e.g. from within from_thread.run_sync()), where asyncio.current_task() is legitimately None (#773; PR by @AmirF194)
  • Fixed CancelScope on the asyncio backend swallowing a native Task.cancel() that was delivered in the same event loop iteration as the scope's own cancellation (such as a move_on_after() deadline expiring), which left the host task with a pending cancellation request that never raised CancelledError (#1214)
  • Fixed UDP socket closing hanging if a datagram send was still in flight (#1237; PR by @graingert)
  • Fixed concurrent aclose_forcefully() calls on asyncio socket streams returning before the underlying socket was closed (#1273; PR by @graingert)
  • Fixed aclose() on sockets not checkpointing, and thus failing to raise a cancellation exception when called inside a cancelled scope (affected UNIX socket streams and UNIX datagram sockets on asyncio, and all sockets on Trio) (#1288; PR by @graingert)
  • Fixed aclose() on asyncio TCP socket listeners not checkpointing, and leaking the listening socket if cancelled while another task was waiting in accept() (#1289; PR by @graingert)
  • Fixed accept() on asyncio UNIX socket listeners hanging forever, and leaving the listening socket registered with the event loop, when the listener was closed by another task (#1289; PR by @graingert)
  • Fixed send() on asyncio TCP and UDP sockets returning normally, despite the data being discarded, when the socket was closed by another task (or, for TCP, the connection was lost) while send() was waiting for the operating system to accept the data (#1289; PR by @graingert)
  • Fixed SocketStream.send() on the asyncio backend handing its data to a paused transport after a previous send() was cancelled (#1299; PR by @graingert)
  • Fixed sleep() treating a negative delay (including -inf) inconsistently across backends (asyncio returned immediately; Trio raised ValueError) by raising ValueError on all backends (#1306; PR by @BetterAndBetterII)
  • Fixed create_tcp_listener() occasionally failing with a message like Could not create 2 listeners with a consistent port when an ephemeral port is requested and IPv6 is enabled and the dual-stack path is not available or a specific local host name was given (#1313)
  • Fixed AsyncFile not shielding against cancellation while closing (#1314)
  • Fixed TemporaryDirectory.cleanup() reacting to cancellation prematurely when the host task was already cancelled, causing the actual cleanup operation to be skipped (#1316; PR by @Yasser-Ameur)
  • Fixed a NaN deadline being accepted on asyncio while Trio raised ValueError, which silently disabled the timeout (fail_after(math.nan) returned instead of raising TimeoutError); CancelScope now rejects it on both backends (#1317; PR by @dylanpulver)
  • Fixed FileReadStream and FileWriteStream leaving files open when cancelled during context manager exit, including unflushed writes (#1318; PR by @Kuang-xianxin)
  • Fixed Condition.notify() and Condition.notify_all() failing when the underlying lock was acquired directly rather than through the condition (#1319; PR by @GruffElixir)
  • Fixed importing AnyIO with loaders that do not provide __file__, such as PyOxidizer, raising TypeError instead of falling back to eager imports (#1322; PR by @skulitom)
  • Fixed text receive streams silently discarding incomplete characters at end-of-file instead of applying the configured decoding error handler (#1339; PR by @Aurelucien)
  • Fixed Semaphore(fast_acquire=True) losing its fast-acquire behavior when instantiated outside a running event loop (#1348; PR by @feiiiiii5)
  • Fixed BlockingPortalProvider permanently failing with an AttributeError on every subsequent use if the first attempt to start its blocking portal failed (#1350; PR by @Yasser-Ameur)
  • Fixed create_udp_socket() silently ignoring the local_port argument when local_host was omitted, making the socket bind to a random ephemeral port instead of the requested one (#1351; PR by @januththedev)
  • Fixed worker threads on the asyncio backend never returning to the idle pool (and thus never being reused or pruned) when a to_thread.run_sync() call was cancelled after it had been queued for the worker but before the worker thread had picked it up (#1352; PR by @Zac-HD)
  • Fixed pytest plugin running Hypothesis async tests only on the first parametrized backend instead of each backend (#1353; PR by @DYNOSuprovo)
  • Fixed TypeError when subclassing an existing TypedAttributeSet subclass, and this subclass contains type annotations (#1358; PR by @pasmud)
  • Fixed Lock.locked() (and Condition.locked()) raising NoEventLoopError when the lock was created outside a running event loop (#1362; PR by @00200200)
  • Fixed connect_tcp() leaking a connected socket when an enclosing cancel scope was cancelled before the connection attempt task group exited (#1364; PR by @charan-rathore)
  • Fixed create_connected_udp_socket() silently ignoring local_port when local_host was not given: the local address was left unset, so the OS picked an ephemeral port instead of the requested one (#1365; PR by @feiiiiii5)
  • Fixed BlockingPortalProvider not passing the exception raised in its with block on to the start_blocking_portal() context manager it wraps (#1366; PR by @feiiiiii5)
  • Fixed anyio.itertools.islice() not consuming the first start items when stop <= start (#1372; PR by @Rodrigo-Palma)
  • Fixed BufferedByteReceiveStream.receive_exactly() and receive_until() returning buffered data after explicit closure instead of raising ClosedResourceError (#1378; PR by @kokotatan)
  • Fixed a TLS stream sending records the peer could no longer decrypt after a cancelled send() lost an already-encrypted record; the stream now raises BrokenResourceError on further use instead (#1385; PR by @Kayvan-Zahiri)
  • Fixed close() on memory object streams not waking up tasks blocked in send() or receive() on the same stream (#1391)
  • Fixed anyio.itertools.product() acquiring and consuming unused input iterables when repeat=0 (#1394; PR by @sricharanreddycheruku)
  • Fixed SpooledTemporaryFile rolling over to disk on writes when max_size is zero (the default) (#1397; PR by @fhgffy)
  • Fixed Trio UDP sockets remaining open when initialization failed or was cancelled (#1400; PR by @adenzhou1350)
  • Fixed SpooledTemporaryFile.rollover() moving the current file position to the end of the file (#1401; PR by @fhgffy)
  • Fixed cancellation during temporary directory creation leaving the directory behind while its context manager is retained (#1403; PR by @adenzhou1350)
  • Fixed cancellation during SpooledTemporaryFile.rollover() losing buffered contents (#1404; PR by @adenzhou1350)
  • Fixed TextSendStream.send() re-emitting the byte order mark on every item with BOM-emitting encodings (utf-16, utf-32,...
Read more

4.15.1

Choose a tag to compare

@github-actions github-actions released this 05 Sep 10:42
  • Implemented a compatibility fix for supporting direct access of anyio.* submodules from the main package even when those submodules were not directly imported first (#1311)

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)