Migrating from AnyIO 2 to AnyIO 3
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:
CancelScope.cancel()
When migrating to AnyIO 3, simply remove the await
from each call to these.
Note
For backwards compatibility reasons, current_time()
,
current_effective_deadline()
and get_running_tasks()
return objects which are
awaitable versions of their original types (float
and 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 maybe_async()
or float()
/ list()
on the returned
value as appropriate.
The following async context managers changed to regular context managers:
open_cancel_scope()
(now justCancelScope()
)
When migrating, just change async with
into a plain with
.
With the exception of
MemoryObjectReceiveStream.receive_nowait()
,
all of them can still be used like before – they will raise 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: maybe_async()
and
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:
...
Starting tasks
The TaskGroup.spawn()
coroutine method has been deprecated in favor of the synchronous
method 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 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 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 TaskGroup.spawn()
, the BlockingPortal.spawn_task()
method has also been renamed
to start_task_soon()
, so as to be consistent with task groups.
The create_blocking_portal()
factory function was also deprecated in favor of instantiating
BlockingPortal
directly.
For code requiring cross compatibility, catching the deprecation warning (as above) should work.
Synchronization primitives
Synchronization primitive factories (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
→to_thread.current_default_thread_limiter()
(NOTE: the function was renamed too!)run_sync_in_worker_thread()
→to_thread.run_sync()
run_async_from_thread()
→from_thread.run()
run_sync_from_thread()
→from_thread.run_sync()
The old versions are still in place but emit deprecation warnings when called.