Migrating from AnyIO 2 to AnyIO 3 ================================= .. py:currentmodule:: anyio AnyIO 3 changed some functions and methods in a way that needs some adaptation in your code. All deprecated functions and methods will be removed in AnyIO 4. Asynchronous functions converted to synchronous ----------------------------------------------- AnyIO 3 changed several previously asynchronous functions and methods into regular ones for two reasons: #. to better serve use cases where synchronous callbacks are used by third party libraries #. to better match the API of trio_ The following functions and methods were changed: * :func:`current_time` * :func:`current_effective_deadline` * :meth:`CancelScope.cancel() <.abc.CancelScope.cancel>` * :meth:`CapacityLimiter.acquire_nowait` * :meth:`CapacityLimiter.acquire_on_behalf_of_nowait` * :meth:`Condition.release` * :meth:`Event.set` * :func:`get_current_task` * :func:`get_running_tasks` * :meth:`Lock.release` * :meth:`MemoryObjectReceiveStream.receive_nowait() <.streams.memory.MemoryObjectReceiveStream.receive_nowait>` * :meth:`MemoryObjectSendStream.send_nowait() <.streams.memory.MemoryObjectSendStream.send_nowait>` * :func:`open_signal_receiver` * :meth:`Semaphore.release` When migrating to AnyIO 3, simply remove the ``await`` from each call to these. .. note:: For backwards compatibility reasons, :func:`current_time`, :func:`current_effective_deadline` and :func:`get_running_tasks` return objects which are awaitable versions of their original types (:class:`float` and :class:`list`, respectively). These awaitable versions are subclasses of the original types so they should behave as their originals, but if you absolutely need the pristine original types, you can either use :func:`maybe_async` or ``float()`` / ``list()`` on the returned value as appropriate. The following async context managers changed to regular context managers: * :func:`fail_after` * :func:`move_on_after` * :func:`open_cancel_scope` (now just ``CancelScope()``) When migrating, just change ``async with`` into a plain ``with``. With the exception of :meth:`MemoryObjectReceiveStream.receive_nowait() <.streams.memory.MemoryObjectReceiveStream.receive_nowait>`, all of them can still be used like before – they will raise :exc:`DeprecationWarning` when used this way on AnyIO 3, however. If you're writing a library that needs to be compatible with both major releases, you will need to use the compatibility functions added in AnyIO 2.2: :func:`maybe_async` and :func:`maybe_async_cm`. These will let you safely use functions/methods and context managers (respectively) regardless of which major release is currently installed. Example 1 – setting an event:: from anyio.abc import Event from anyio import maybe_async async def foo(event: Event): await maybe_async(event.set()) ... Example 2 – opening a cancel scope:: from anyio import CancelScope, maybe_async_cm async def foo(): async with maybe_async_cm(CancelScope()) as scope: ... .. _trio: https://github.com/python-trio/trio Starting tasks -------------- The :meth:`TaskGroup.spawn` coroutine method has been deprecated in favor of the synchronous method :meth:`TaskGroup.start_soon` (which mirrors ``start_soon()`` in trio's nurseries). If you're fully migrating to AnyIO 3, simply switch to calling the new method (and remove the ``await``). If your code needs to work with both AnyIO 2 and 3, you can keep using :meth:`~TaskGroup.spawn` (until AnyIO 4) and suppress the deprecation warning:: import warnings async def foo(): async with create_task_group() as tg: with warnings.catch_warnings(): await tg.spawn(otherfunc) Blocking portal changes ----------------------- AnyIO now **requires** :func:`.from_thread.start_blocking_portal` to be used as a context manager:: from anyio import sleep from anyio.from_thread import start_blocking_portal with start_blocking_portal() as portal: portal.call(sleep, 1) As with :meth:`TaskGroup.spawn`, the :meth:`BlockingPortal.spawn_task` method has also been renamed to :meth:`~BlockingPortal.start_task_soon`, so as to be consistent with task groups. The :func:`create_blocking_portal` factory function was also deprecated in favor of instantiating :class:`BlockingPortal` directly. For code requiring cross compatibility, catching the deprecation warning (as above) should work. Synchronization primitives -------------------------- Synchronization primitive factories (:func:`create_event` etc.) were deprecated in favor of instantiating the classes directly. So convert code like this:: from anyio import create_event async def main(): event = create_event() into this:: from anyio import Event async def main(): event = Event() or, if you need to work with both AnyIO 2 and 3:: try: from anyio import Event create_event = Event except ImportError: from anyio import create_event from anyio.abc import Event async def foo() -> Event: return create_event() Threading functions moved ------------------------- Threading functions were restructured to submodules, following the example of trio: * ``current_default_worker_thread_limiter`` → :func:`.to_thread.current_default_thread_limiter` (NOTE: the function was renamed too!) * ``run_sync_in_worker_thread()`` → :func:`.to_thread.run_sync` * ``run_async_from_thread()`` → :func:`.from_thread.run` * ``run_sync_from_thread()`` → :func:`.from_thread.run_sync` The old versions are still in place but emit deprecation warnings when called.