- **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)