Version history
This library adheres to Semantic Versioning 2.0.
3.3.4
Fixed
BrokenResourceError
instead ofEndOfStream
being raised inTLSStream
when the peer abruptly closes the connection whileTLSStream
is receiving data withstandard_compatible=False
set
3.3.3
Fixed UNIX socket listener not setting accepted sockets to non-blocking mode on asyncio
Changed unconnected UDP sockets to be always bound to a local port (on “any” interface) to avoid errors on asyncio + Windows
3.3.2
Fixed cancellation problem on asyncio where level-triggered cancellation for all parent cancel scopes would not resume after exiting a shielded nested scope (#370)
3.3.1
Added missing documentation for the
ExceptionGroup.exceptions
attributeChanged the asyncio test runner not to use uvloop by default (to match the behavior of
anyio.run()
)Fixed
RuntimeError
on asyncio when aCancelledError
is raised from a task spawned through aBlockingPortal
(#357)Fixed asyncio warning about a
Future
with an exception that was never retrieved which happened when a socket was already written to but the peer abruptly closed the connection
3.3.0
Added asynchronous
Path
classAdded the
wrap_file()
function for wrapping existing files as asynchronous file objectsRelaxed the type of the
path
initializer argument toFileReadStream
andFileWriteStream
so they accept any path-like object (including the new asynchronousPath
class)Dropped unnecessary dependency on the
async_generator
libraryChanged the generics in
AsyncFile
so that the methods correctly return eitherstr
orbytes
based on the argument toopen_file()
Fixed an asyncio bug where under certain circumstances, a stopping worker thread would still accept new assignments, leading to a hang
3.2.1
Fixed idle thread pruning on asyncio sometimes causing an expired worker thread to be assigned a task
3.2.0
Added Python 3.10 compatibility
Added the ability to close memory object streams synchronously (including support for use as a synchronous context manager)
Changed the default value of the
use_uvloop
asyncio backend option toFalse
to prevent unsafe event loop policy changes in different threadsFixed
to_thread.run_sync()
hanging on the second call on asyncio when used withloop.run_until_complete()
Fixed
to_thread.run_sync()
prematurely marking a worker thread inactive when a task await on the result is cancelledFixed
ResourceWarning
about an unclosed socket when UNIX socket connect fails on asyncioFixed the type annotation of
open_signal_receiver()
as a synchronous context managerFixed the type annotation of
DeprecatedAwaitable(|List|Float).__await__
to match thetyping.Awaitable
protocol
3.1.0
Added
env
andcwd
keyword arguments torun_process()
andopen_process
.Added support for mutation of
CancelScope.shield
(PR by John Belmonte)Added the
sleep_forever()
andsleep_until()
functionsChanged asyncio task groups so that if the host and child tasks have only raised
CancelledErrors
, just oneCancelledError
will now be raised instead of anExceptionGroup
, allowing asyncio to ignore it when it propagates out of the taskChanged task names to be converted to
str
early on asyncio (PR by Thomas Grainger)Fixed
sniffio._impl.AsyncLibraryNotFoundError: unknown async library, or not in async context
on asyncio and Python 3.6 whento_thread.run_sync()
is used fromloop.run_until_complete()
Fixed odd
ExceptionGroup: 0 exceptions were raised in the task group
appearing under certain circumstances on asyncioFixed
wait_all_tasks_blocked()
returning prematurely on asyncio when a previously blocked task is cancelled (PR by Thomas Grainger)Fixed declared return type of
TaskGroup.start()
(it was declared asNone
, but anything can be returned from it)Fixed
TextStream.extra_attributes
raisingAttributeError
(PR by Thomas Grainger)Fixed
await maybe_async(current_task())
returningNone
(PR by Thomas Grainger)Fixed:
pickle.dumps(current_task())
now correctly raisesTypeError
instead of pickling toNone
(PR by Thomas Grainger)Fixed return type annotation of
Event.wait()
(bool
→None
) (PR by Thomas Grainger)Fixed return type annotation of
RunVar.get()
to return either the type of the default value or the type of the contained value (PR by Thomas Grainger)Fixed a deprecation warning message to refer to
maybe_async()
and notmaybe_awaitable()
(PR by Thomas Grainger)Filled in argument and return types for all functions and methods previously missing them (PR by Thomas Grainger)
3.0.1
Fixed
to_thread.run_sync()
raisingRuntimeError
on asyncio when no “root” task could be found for setting up a cleanup callback. This was a problem at least on Tornado and possibly also Twisted in asyncio compatibility mode. The life of worker threads is now bound to the the host task of the topmost cancel scope hierarchy starting from the current one, or if no cancel scope is active, the current task.
3.0.0
Curio support has been dropped (see the FAQ as for why)
API changes:
BACKWARDS INCOMPATIBLE Submodules under
anyio.abc.
have been made private (use onlyanyio.abc
from now on).BACKWARDS INCOMPATIBLE The following method was previously a coroutine method and has been converted into a synchronous one:
MemoryObjectReceiveStream.receive_nowait()
The following functions and methods are no longer asynchronous but can still be awaited on (doing so will emit a deprecation warning):
current_time()
current_effective_deadline()
get_current_task()
get_running_tasks()
CancelScope.cancel()
CapacityLimiter.acquire_nowait()
CapacityLimiter.acquire_on_behalf_of_nowait()
Condition.release()
Event.set()
Lock.release()
MemoryObjectSendStream.send_nowait()
Semaphore.release()
The following functions now return synchronous context managers instead of asynchronous context managers (and emit deprecation warnings if used as async context managers):
fail_after()
move_on_after()
open_cancel_scope()
(now justCancelScope()
; see below)open_signal_receiver()
The following functions and methods have been renamed/moved (will now emit deprecation warnings when you use them by their old names):
create_blocking_portal()
→anyio.from_thread.BlockingPortal()
create_capacity_limiter()
→anyio.CapacityLimiter()
create_event()
→anyio.Event()
create_lock()
→anyio.Lock()
create_condition()
→anyio.Condition()
create_semaphore()
→anyio.Semaphore()
current_default_worker_thread_limiter()
→anyio.to_thread.current_default_thread_limiter()
open_cancel_scope()
→anyio.CancelScope()
run_sync_in_worker_thread()
→anyio.to_thread.run_sync()
run_async_from_thread()
→anyio.from_thread.run()
run_sync_from_thread()
→anyio.from_thread.run_sync()
BlockingPortal.spawn_task
→BlockingPortal.start_task_soon
CapacityLimiter.set_total_tokens()
→limiter.total_tokens = ...
TaskGroup.spawn()
→TaskGroup.start_soon()
BACKWARDS INCOMPATIBLE
start_blocking_portal()
must now be used as a context manager (it no longer returns a BlockingPortal, but a context manager that yields one)BACKWARDS INCOMPATIBLE The
BlockingPortal.stop_from_external_thread()
method (useportal.call(portal.stop)
instead now)BACKWARDS INCOMPATIBLE The
SocketStream
andSocketListener
classes were made non-genericMade all non-frozen dataclasses hashable with
eq=False
Removed
__slots__
fromBlockingPortal
See the migration documentation for instructions on how to deal with these changes.
Improvements to running synchronous code:
Added the
run_sync_from_thread()
functionAdded the
run_sync_in_process()
function for running code in worker processes (big thanks to Richard Sheridan for his help on this one!)
Improvements to sockets and streaming:
Added the
UNIXSocketStream
class which is capable of sending and receiving file descriptorsAdded the
FileReadStream
andFileWriteStream
classescreate_unix_listener()
now removes any existing socket at the given path before proceeding (instead of raisingOSError: Address already in use
)
Improvements to task groups and cancellation:
Added the
TaskGroup.start()
method and a correspondingBlockingPortal.start_task()
methodAdded the
name
argument toBlockingPortal.start_task_soon()
(renamed fromBlockingPortal.spawn_task()
)Changed
CancelScope.deadline
to be writableAdded the following functions in the
anyio.lowlevel
module:checkpoint()
checkpoint_if_cancelled()
cancel_shielded_checkpoint()
Improvements and changes to synchronization primitives:
Added the
Lock.acquire_nowait()
,Condition.acquire_nowait()
andSemaphore.acquire_nowait()
methodsAdded the
statistics()
method toEvent
,Lock
,Condition
,Semaphore
,CapacityLimiter
,MemoryObjectReceiveStream
andMemoryObjectSendStream
Lock
andCondition
can now only be released by the task that acquired them. This behavior is now consistent on all backends whereas previously only Trio enforced this.The
CapacityLimiter.total_tokens
property is now writable andCapacityLimiter.set_total_tokens()
has been deprecatedAdded the
max_value
property toSemaphore
Asyncio specific improvements (big thanks to Thomas Grainger for his effort on most of these!):
Cancel scopes are now properly enforced with native asyncio coroutine functions (without any explicit AnyIO checkpoints)
Changed the asyncio
CancelScope
to raise aRuntimeError
if a cancel scope is being exited before it was even enteredChanged the asyncio test runner to capture unhandled exceptions from asynchronous callbacks and unbound native tasks which are then raised after the test function (or async fixture setup or teardown) completes
Changed the asyncio
TaskGroup.start_soon()
(formerlyspawn()
) method to call the target function immediately before starting the task, for consistency across backendsChanged the asyncio
TaskGroup.start_soon()
(formerlyspawn()
) method to avoid the use of a coroutine wrapper on Python 3.8+ and added a hint for hiding the wrapper in tracebacks on earlier Pythons (supported by Pytest, Sentry etc.)Changed the default thread limiter on asyncio to use a
RunVar
so it is scoped to the current event loop, thus avoiding potential conflict among multiple running event loopsThread pooling is now used on asyncio with
run_sync_in_worker_thread()
Fixed
current_effective_deadline()
raisingKeyError
on asyncio when no cancel scope is active
Added the
RunVar
class for scoping variables to the running event loop
2.2.0
Added the
maybe_async()
andmaybe_async_cm()
functions to facilitate forward compatibility with AnyIO 3Fixed socket stream bug on asyncio where receiving a half-close from the peer would shut down the entire connection
Fixed native task names not being set on asyncio on Python 3.8+
Fixed
TLSStream.send_eof()
raisingValueError
instead of the expectedNotImplementedError
Fixed
open_signal_receiver()
on asyncio and curio hanging if the cancel scope was cancelled before the function could runFixed Trio test runner causing unwarranted test errors on
BaseException
(PR by Matthias Urlichs)Fixed formatted output of
ExceptionGroup
containing too many newlines
2.1.0
Added the
spawn_task()
andwrap_async_context_manager()
methods toBlockingPortal
Added the
handshake_timeout
anderror_handler
parameters toTLSListener
Fixed
Event
objects on the trio backend not inheriting fromanyio.abc.Event
Fixed
run_sync_in_worker_thread()
raisingUnboundLocalError
on asyncio when cancelledFixed
send()
on socket streams not raising any exception on asyncio, and an unwrappedBrokenPipeError
on trio and curio when the peer has disconnectedFixed
MemoryObjectSendStream.send()
raisingBrokenResourceError
when the last receiver is closed right after receiving the itemFixed
ValueError: Invalid file descriptor: -1
when closing aSocketListener
on asyncio
2.0.2
Fixed one more case of
AttributeError: 'async_generator_asend' object has no attribute 'cr_await'
on asyncio
2.0.1
Fixed broken
MultiListener.extra()
(PR by daa)Fixed
TLSStream
returning an empty bytes object instead of raisingEndOfStream
when trying to receive from the stream after a closing handshakeFixed
AttributeError
when cancelling a task group’s scope inside an async test fixture on asyncioFixed
wait_all_tasks_blocked()
raisingAttributeError
on asyncio if a native task is waiting on an async generator’sasend()
method
2.0.0
General new features:
Added support for subprocesses
Added support for “blocking portals” which allow running functions in the event loop thread from external threads
Added the
anyio.aclose_forcefully()
function for closing asynchronous resources as quickly as possible
General changes/fixes:
BACKWARDS INCOMPATIBLE Some functions have been renamed or removed (see further below for socket/fileio API changes):
finalize()
→ (removed; usecontextlib.aclosing()
instead)receive_signals()
→open_signal_receiver()
run_in_thread()
→run_sync_in_worker_thread()
current_default_thread_limiter()
→current_default_worker_thread_limiter()
ResourceBusyError
→BusyResourceError
BACKWARDS INCOMPATIBLE Exception classes were moved to the top level package
Dropped support for Python 3.5
Bumped minimum versions of trio and curio to v0.16 and v1.4, respectively
Changed the
repr()
ofExceptionGroup
to match trio’sMultiError
Backend specific changes and fixes:
asyncio
: Added support forProactorEventLoop
. This allows asyncio applications to use AnyIO on Windows even without using AnyIO as the entry point.asyncio
: The asyncio backend now usesasyncio.run()
behind the scenes which properly shuts down async generators and cancels any leftover native taskscurio
: Worked around the limitation where a task can only be cancelled twice (any cancellations beyond that were ignored)asyncio
+curio
: a cancellation check now callssleep(0)
, allowing the scheduler to switch to a different taskasyncio
+curio
: Host name resolution now uses IDNA 2008 (with UTS 46 compatibility mapping, just like trio)asyncio
+curio
: Fixed a bug where a task group would abandon its subtasks if its own cancel scope was cancelled while it was waiting for subtasks to finishasyncio
+curio
: Fixed recursive tracebacks when a single exception from an inner task group is reraised in an outer task group
Socket/stream changes:
BACKWARDS INCOMPATIBLE The stream class structure was completely overhauled. There are now separate abstract base classes for receive and send streams, byte streams and reliable and unreliable object streams. Stream wrappers are much better supported by this new ABC structure and a new “typed extra attribute” system that lets you query the wrapper chain for the attributes you want via
.extra(...)
.BACKWARDS INCOMPATIBLE Socket server functionality has been refactored into a network-agnostic listener system
BACKWARDS INCOMPATIBLE TLS functionality has been split off from
SocketStream
and can now work over any bidirectional bytes-based stream – you can now establish a TLS encrypted communications pathway over UNIX sockets or even memory object streams. TheTLSRequired
exception has also been removed as it is no longer necessary.BACKWARDS INCOMPATIBLE Buffering functionality (
receive_until()
andreceive_exactly()
) was split off fromSocketStream
into a stream wrapper class (anyio.streams.buffered.BufferedByteReceiveStream
)BACKWARDS INCOMPATIBLE IPv6 addresses are now reported as 2-tuples. If original 4-tuple form contains a nonzero scope ID, it is appended to the address with
%
as the separator.BACKWARDS INCOMPATIBLE Byte streams (including socket streams) now raise
EndOfStream
instead of returning an empty bytes object when the stream has been closed from the other endBACKWARDS INCOMPATIBLE The socket API has changes:
create_tcp_server()
→create_tcp_listener()
create_unix_server()
→create_unix_listener()
create_udp_socket()
had some of its parameters changed:interface
→local_address
port
→local_port
reuse_address
was replaced withreuse_port
(and setsSO_REUSEPORT
instead ofSO_REUSEADDR
)
connect_tcp()
had some of its parameters changed:address
→remote_address
port
→remote_port
bind_host
→local_address
bind_port
→ (removed)autostart_tls
→tls
tls_hostname
(new parameter, when you want to match the certificate against against something else thanremote_address
)
connect_tcp()
now returns aTLSStream
if TLS was enablednotify_socket_closing()
was removed, as it is no longer used by AnyIOSocketStream
has changes to its methods and attributes:address
→.extra(SocketAttribute.local_address)
alpn_protocol
→.extra(TLSAttribute.alpn_protocol)
close()
→aclose()
get_channel_binding
→.extra(TLSAttribute.channel_binding_tls_unique)
cipher
→.extra(TLSAttribute.cipher)
getpeercert
→.extra(SocketAttribute.peer_certificate)
or.extra(SocketAttribute.peer_certificate_binary)
getsockopt()
→.extra(SocketAttribute.raw_socket).getsockopt(...)
peer_address
→.extra(SocketAttribute.remote_address)
receive_chunks()
→ (removed; useasync for
on the stream instead)receive_delimited_chunks()
→ (removed)receive_exactly()
→BufferedReceiveStream.receive_exactly()
receive_some()
→receive()
receive_until()
→BufferedReceiveStream.receive_until()
send_all()
→send()
setsockopt()
→.extra(SocketAttribute.raw_socket).setsockopt(...)
shared_ciphers
→.extra(TLSAttribute.shared_ciphers)
server_side
→.extra(TLSAttribute.server_side)
start_tls()
→stream = TLSStream.wrap(...)
tls_version
→.extra(TLSAttribute.tls_version)
UDPSocket
has changes to its methods and attributes:address
→.extra(SocketAttribute.local_address)
getsockopt()
→.extra(SocketAttribute.raw_socket).getsockopt(...)
port
→.extra(SocketAttribute.local_port)
receive()
no longer takes a maximum bytes argumentreceive_packets()
→ (removed; useasync for
on the UDP socket instead)send()
→ requires a tuple for destination now (address, port), for compatibility with the newUnreliableObjectStream
interface. Thesendto()
method works like the oldsend()
method.setsockopt()
→.extra(SocketAttribute.raw_socket).setsockopt(...)
BACKWARDS INCOMPATIBLE Renamed the
max_size
parameter tomax_bytes
wherever it occurred (this was inconsistently namedmax_bytes
in some subclasses before)Added memory object streams as a replacement for queues
Added stream wrappers for encoding/decoding unicode strings
Support for the
SO_REUSEPORT
option (allows binding more than one socket to the same address/port combination, as long as they all have this option set) has been added to TCP listeners and UDP socketsThe
send_eof()
method was added to all (bidirectional) streams
File I/O changes:
BACKWARDS INCOMPATIBLE Asynchronous file I/O functionality now uses a common code base (
anyio.AsyncFile
) instead of backend-native classesBACKWARDS INCOMPATIBLE The File I/O API has changes to its functions and methods:
aopen()
→open_file()
AsyncFileclose()
→AsyncFileaclose()
Task synchronization changes:
BACKWARDS INCOMPATIBLE Queues were replaced by memory object streams
BACKWARDS INCOMPATIBLE Added the
acquire()
andrelease()
methods to theLock
,Condition
andSemaphore
classesBACKWARDS INCOMPATIBLE Removed the
Event.clear()
method. You must now replace the event object with a new one rather than clear the old one.Fixed
Condition.wait()
not working on asyncio and curio (PR by Matt Westcott)
Testing changes:
BACKWARDS INCOMPATIBLE Removed the
--anyio-backends
command line option for the pytest plugin. Use the-k
option to do ad-hoc filtering, and theanyio_backend
fixture to control which backends you wish to run the tests by default.The pytest plugin was refactored to run the test and all its related async fixtures inside the same event loop, making async fixtures much more useful
Fixed Hypothesis support in the pytest plugin (it was not actually running the Hypothesis tests at all)
1.4.0
Added async name resolution functions (
anyio.getaddrinfo()
andanyio.getnameinfo()
)Added the
family
andreuse_address
parameters toanyio.create_udp_socket()
(Enables multicast support; test contributed by Matthias Urlichs)Fixed
fail.after(0)
not raising a timeout error on asyncio and curioFixed
move_on_after()
andfail_after()
getting stuck on curio in some circumstancesFixed socket operations not allowing timeouts to cancel the task
Fixed API documentation on
Stream.receive_until()
which claimed that the delimiter will be included in the returned data when it really isn’tHarmonized the default task names across all backends
wait_all_tasks_blocked()
no longer considers tasks waiting onsleep(0)
to be blocked on asyncio and curioFixed the type of the
address
parameter inUDPSocket.send()
to includeIPAddress
objects (which were already supported by the backing implementation)Fixed
UDPSocket.send()
to resolve host names usinganyio.getaddrinfo()
before callingsocket.sendto()
to avoid blocking on synchronous name resolutionSwitched to using
anyio.getaddrinfo()
for name lookups
1.3.1
Fixed warnings caused by trio 0.15
Worked around a compatibility issue between uvloop and Python 3.9 (missing
shutdown_default_executor()
method)
1.3.0
Fixed compatibility with Curio 1.0
Made it possible to assert fine grained control over which AnyIO backends and backend options are being used with each test
Added the
address
andpeer_address
properties to theSocketStream
interface
1.2.3
Repackaged release (v1.2.2 contained extra files from an experimental branch which broke imports)
1.2.2
Fixed
CancelledError
leaking from a cancel scope on asyncio if the task previously received a cancellation exceptionFixed
AttributeError
when cancelling a generator-based task (asyncio)Fixed
wait_all_tasks_blocked()
not working with generator-based tasks (asyncio)Fixed an unnecessary delay in
connect_tcp()
if an earlier attempt succeedsFixed
AssertionError
inconnect_tcp()
if multiple connection attempts succeed simultaneously
1.2.1
Fixed cancellation errors leaking from a task group when they are contained in an exception group
Fixed trio v0.13 compatibility on Windows
Fixed inconsistent queue capacity across backends when capacity was defined as 0 (trio = 0, others = infinite)
Fixed socket creation failure crashing
connect_tcp()
1.2.0
Added the possibility to parametrize regular pytest test functions against the selected list of backends
Added the
set_total_tokens()
method toCapacityLimiter
Added the
anyio.current_default_thread_limiter()
functionAdded the
cancellable
parameter toanyio.run_in_thread()
Implemented the Happy Eyeballs (RFC 6555) algorithm for
anyio.connect_tcp()
Fixed
KeyError
on asyncio and curio where entering and exiting a cancel scope happens in different tasksFixed deprecation warnings on Python 3.8 about the
loop
argument ofasyncio.Event()
Forced the use
WindowsSelectorEventLoopPolicy
inasyncio.run
when on Windows and asyncio to keep network functionality workingWorker threads are now spawned with
daemon=True
on all backends, not just trioDropped support for trio v0.11
1.1.0
Added the
lock
parameter toanyio.create_condition()
(PR by Matthias Urlichs)Added async iteration for queues (PR by Matthias Urlichs)
Added capacity limiters
Added the possibility of using capacity limiters for limiting the maximum number of threads
Fixed compatibility with trio v0.12
Fixed IPv6 support in
create_tcp_server()
,connect_tcp()
andcreate_udp_socket()
Fixed mishandling of task cancellation while the task is running a worker thread on asyncio and curio
1.0.0
Fixed pathlib2 compatibility with
anyio.aopen()
Fixed timeouts not propagating from nested scopes on asyncio and curio (PR by Matthias Urlichs)
Fixed incorrect call order in socket close notifications on asyncio (mostly affecting Windows)
Prefixed backend module names with an underscore to better indicate privateness
1.0.0rc2
Fixed some corner cases of cancellation where behavior on asyncio and curio did not match with that of trio. Thanks to Joshua Oreman for help with this.
Fixed
current_effective_deadline()
not taking shielded cancellation scopes into account on asyncio and curioFixed task cancellation not happening right away on asyncio and curio when a cancel scope is entered when the deadline has already passed
Fixed exception group containing only cancellation exceptions not being swallowed by a timed out cancel scope on asyncio and curio
Added the
current_time()
functionReplaced
CancelledError
withget_cancelled_exc_class()
Added support for Hypothesis
Added support for PEP 561
Use uvloop for the asyncio backend by default when available (but only on CPython)
1.0.0rc1
Fixed
setsockopt()
passing options to the underlying method in the wrong mannerFixed cancellation propagation from nested task groups
Fixed
get_running_tasks()
returning tasks from other event loopsAdded the
parent_id
attribute toanyio.TaskInfo
Added the
get_current_task()
functionAdded guards to protect against concurrent read/write from/to sockets by multiple tasks
Added the
notify_socket_close()
function
1.0.0b2
Added introspection of running tasks via
anyio.get_running_tasks()
Added the
getsockopt()
andsetsockopt()
methods to theSocketStream
APIFixed mishandling of large buffers by
BaseSocket.sendall()
Fixed compatibility with (and upgraded minimum required version to) trio v0.11
1.0.0b1
Initial release