Skip to content

4.0.0

Compare
Choose a tag to compare
@github-actions github-actions released this 30 Aug 22:24
· 109 commits to master since this release
  • BACKWARDS INCOMPATIBLE Replaced AnyIO's own ExceptionGroup class with the PEP 654 BaseExceptionGroup and ExceptionGroup
  • BACKWARDS INCOMPATIBLE Changes to cancellation semantics:
    • Any exceptions raising out of a task groups are now nested inside an ExceptionGroup (or BaseExceptionGroup if one or more BaseException were included)
    • Fixed task group not raising a cancellation exception on asyncio at exit if no child tasks were spawned and an outer cancellation scope had been cancelled before
    • Ensured that exiting a TaskGroup always hits a yield point, regardless of whether there are running child tasks to be waited on
    • On asyncio, cancel scopes will defer cancelling tasks that are scheduled to resume with a finished future
    • On asyncio and Python 3.9/3.10, cancel scopes now only suppress cancellation exceptions if the cancel message matches the scope
    • Task groups on all backends now raise a single cancellation exception when an outer cancel scope is cancelled, and no exceptions other than cancellation exceptions are raised in the group
  • BACKWARDS INCOMPATIBLE Changes the pytest plugin to run all tests and fixtures in the same task, allowing fixtures to set context variables for tests and other fixtures
  • BACKWARDS INCOMPATIBLE Changed anyio.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
  • BACKWARDS INCOMPATIBLE Dropped support for spawning tasks from old-style coroutine functions (@asyncio.coroutine)
  • BACKWARDS INCOMPATIBLE The policy option on the asyncio backend was changed to loop_factory to accommodate asyncio.Runner
  • Changed anyio.run() to use asyncio.Runner (or a back-ported version of it on Pythons older than 3.11) on the asyncio backend
  • Dropped support for Python 3.7
  • Added support for Python 3.12
  • Bumped minimum version of trio to v0.22
  • Added the anyio.Path.is_junction() and anyio.Path.walk() methods
  • Added create_unix_datagram_socket and create_connected_unix_datagram_socket to create UNIX datagram sockets (PR by Jean Hominal)
  • Fixed from_thread.run and from_thread.run_sync not setting sniffio on asyncio. As a result:
    • Fixed from_thread.run_sync failing when used to call sniffio-dependent functions on asyncio
    • Fixed from_thread.run failing when used to call sniffio-dependent functions on asyncio from a thread running trio or curio
    • Fixed deadlock when using from_thread.start_blocking_portal(backend="asyncio") in a thread running trio or curio (PR by Ganden Schaffner)
  • Improved type annotations:
    • The 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)
  • Added the CancelScope.cancelled_caught property which tells users if the cancel scope suppressed a cancellation exception
  • Fixed fail_after() raising an unwarranted TimeoutError when the cancel scope was cancelled before reaching its deadline
  • Fixed MemoryObjectReceiveStream.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)
  • Fixed TaskGroup.start() on asyncio not responding to cancellation from the outside
  • Fixed tasks started from BlockingPortal not notifying synchronous listeners (concurrent.futures.wait()) when they're cancelled
  • Removed unnecessary extra waiting cycle in Event.wait() on asyncio in the case where the event was not yet set
  • Fixed processes spawned by 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)

Changes since 4.0.0rc1:

  • Fixed the type annotation of TaskGroup.start_soon() to accept any awaitables (already in v3.7.0 but was missing from 4.0.0rc1)
  • Changed 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 message
  • Worked around a CPython bug that caused TLSListener.handle_handshake_error() on asyncio to log "NoneType: None" instead of the error (PR by Ganden Schaffner)
  • Re-added the 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)
  • Fixed processes spawned by 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)