版本历史¶
Version history
This library adheres to Semantic Versioning 2.0.
UNRELEASED
Fixed a misleading
ValueErrorin the context of DNS failures (#815; PR by @graingert)
4.6.2
修复了由( #807 )引起的回归问题,该问题阻止了参数化异步 fixture 的使用
Fixed regression caused by (#807) that prevented the use of parametrized async fixtures
4.6.1
此版本包含了 v4.5.1 和 v4.6.0 中的所有变更,以及:
修复了 TaskGroup 和 CancelScope 在抛出异常时在 traceback 中产生循环引用的问题( #806 )(PR 作者:@graingert)
This release contains all the changes from both v4.5.1 and v4.6.0, plus:
Fixed TaskGroup and CancelScope producing cyclic references in tracebacks when raising exceptions (#806) (PR by @graingert)
4.6.0
此版本是 v4.5.0 的继任版本,已不再支持 Python 3.8,并且不包含 v4.5.1 的变更。
This release is the successor to v4.5.0 with Python 3.8 support dropped, and does not contain the changes from v4.5.1.
Dropped support for Python 3.8 (as #698 cannot be resolved without cancel message support)
Fixed 100% CPU use on asyncio while waiting for an exiting task group to finish while said task group is within a cancelled cancel scope (#695)
Fixed cancel scopes on asyncio not propagating
CancelledErroron exit when the enclosing cancel scope has been effectively cancelled (#698)Fixed asyncio task groups not yielding control to the event loop at exit if there were no child tasks to wait on
Fixed inconsistent task uncancellation with asyncio cancel scopes belonging to a task group when said task group has child tasks running
4.5.1
由于在 v4.6.0 中放弃了对 Python 3.8 的支持,本次过渡版本旨在为 Python 3.8 提供回归修复,并添加了 v4.6.1 中的其他修复。
修复了在 asyncio 中,同一任务中多次获取锁时会挂起,而不是抛出
RuntimeError的问题( #798 )修复了类基于测试中,异步 fixture 的
self与测试的self不同的问题( #633 )(PR 由 @agronholm 和 @graingert 提交)修复了在 Windows 上,当使用 truststore SSL 证书并发生证书验证错误时,
TLSStream抛出TypeError的问题( #795 )更正了
anyio.Path文档中关于当前 Python 版本对其几个方法的限制,并使得在 Python 3.12 之前的版本中不可用is_junction方法( #794 )
As Python 3.8 support was dropped in v4.6.0, this interim release was created to bring a regression fix to Python 3.8, and adds a few other fixes also present in v4.6.1.
Fixed acquring a lock twice in the same task on asyncio hanging instead of raising a
RuntimeError(#798)Fixed an async fixture's
selfbeing different than the test'sselfin class-based tests (#633) (PR by @agronholm and @graingert)Fixed
TypeErrorwithTLSStreamon Windows when a certificate verification error occurs when using a truststore SSL certificate (#795)Corrected documentation on
anyio.Pathregarding the limitations imposed by the current Python version on several of its methods, and made theis_junctionmethod unavailable on Python versions earlier than 3.12 (#794)
4.5.0
Improved the performance of
anyio.Lockandanyio.Semaphoreon asyncio (even up to 50 %)Added the
fast_acquireparameter toanyio.Lockandanyio.Semaphoreto further boost performance at the expense of safety (acquire()will not yield control back if there is no contention)Added support for the
from_uri(),full_match(),parsermethods/properties inanyio.Path, newly added in Python 3.13 (#737)Added support for more keyword arguments for
run_process()andopen_process():startupinfo,creationflags,pass_fds,user,group,extra_groupsandumask(#742)Improved the type annotations and support for
PathLikeinrun_process()andopen_process()to allow for path-like arguments, just likesubprocess.PopenChanged the
ResourceWarningfrom an unclosed memory object stream to include its address for easier identificationChanged
start_blocking_portal()to always use daemonic threads, to accommodate the "loitering event loop" use caseBumped the minimum version of Trio to v0.26.1
Fixed
__repr__()ofMemoryObjectItemReceiver, whenitemis not defined (#767; PR by @Danipulok)Fixed
to_process.run_sync()failing to initialize if__main__.__file__pointed to a file in a nonexistent directory (#696)Fixed
AssertionError: feed_data after feed_eofon asyncio when a subprocess is closed early, before its output has been read (#490)Fixed
TaskInfo.has_pending_cancellation()on asyncio not respecting shielded scopes (#771; PR by @gschaffner)Fixed
SocketStream.receive()returningbytearrayinstead ofbyteswhen using asyncio withProactorEventLoop(Windows) (#776)Fixed quitting the debugger in a pytest test session while in an active task group failing the test instead of exiting the test session (because the exit exception arrives in an exception group)
Fixed support for Linux abstract namespaces in UNIX sockets that was broken in v4.2 (#781; PR by @tapetersen)
Fixed
KeyboardInterrupt(ctrl+c) hanging the asyncio pytest runner
4.4.0
Added the
BlockingPortalProviderclass to aid with constructing synchronous counterparts to asynchronous interfaces that would otherwise require multiple blocking portalsAdded
__slots__toAsyncResourceso that child classes can use__slots__(#733; PR by Justin Su)Added the
TaskInfo.has_pending_cancellation()methodFixed erroneous
RuntimeError: called 'started' twice on the same task statuswhen cancelling a task in a TaskGroup created with thestart()method before the first checkpoint is reached after callingtask_status.started()(#706; PR by Dominik Schwabe)Fixed two bugs with
TaskGroup.start()on asyncio:Fixed erroneous
RuntimeError: called 'started' twice on the same task statuswhen cancelling a task in a TaskGroup created with thestart()method before the first checkpoint is reached after callingtask_status.started()(#706; PR by Dominik Schwabe)Fixed the entire task group being cancelled if a
TaskGroup.start()call gets cancelled (#685, #710)
Fixed a race condition that caused crashes when multiple event loops of the same backend were running in separate threads and simultaneously attempted to use AnyIO for their first time (#425; PR by David Jiricek and Ganden Schaffner)
Fixed cancellation delivery on asyncio incrementing the wrong cancel scope's cancellation counter when cascading a cancel operation to a child scope, thus failing to uncancel the host task (#716)
Fixed erroneous
TypedAttributeLookupErrorif a typed attribute getter raisesKeyErrorFixed the asyncio backend not respecting the
PYTHONASYNCIODEBUGenvironment variable when setting thedebugflag inanyio.run()Fixed
SocketStream.receive()not detecting EOF on asyncio if there is also data in the read buffer (#701)Fixed
MemoryObjectStreamdropping an item if the item is delivered to a recipient that is waiting to receive an item but has a cancellation pending (#728)Emit a
ResourceWarningforMemoryObjectReceiveStreamandMemoryObjectSendStreamthat were garbage collected without being closed (PR by Andrey Kazantcev)Fixed
MemoryObjectSendStream.send()not raisingBrokenResourceErrorwhen the last correspondingMemoryObjectReceiveStreamis closed while waiting to send a falsey item (#731; PR by Ganden Schaffner)
4.3.0
Added support for the Python 3.12
walk_upkeyword argument inanyio.Path.relative_to()(PR by Colin Taylor)Fixed passing
total_tokenstoanyio.CapacityLimiter()as a keyword argument not working on thetriobackend (#515)Fixed
Process.aclose()not performing the minimum level of necessary cleanup when cancelled. Previously:Cancellation of
Process.aclose()could leak an orphan processCancellation of
run_process()could very briefly leak an orphan process.Cancellation of
Process.aclose()orrun_process()on Trio could leave standard streams unclosed
(PR by Ganden Schaffner)
Fixed
Process.stdin.aclose(),Process.stdout.aclose(), andProcess.stderr.aclose()not including a checkpoint on asyncio (PR by Ganden Schaffner)Fixed documentation on how to provide your own typed attributes
4.2.0
Add support for
byte-based paths inconnect_unix,create_unix_listeners,create_unix_datagram_socket, andcreate_connected_unix_datagram_socket. (PR by Lura Skye)Enabled the
EventandCapacityLimiterclasses to be instantiated outside an event loop threadBroadly improved/fixed the type annotations. Among other things, many functions and methods that take variadic positional arguments now make use of PEP 646
TypeVarTupleto allow the positional arguments to be validated by static type checkers. These changes affected numerous methods and functions, including:anyio.run()TaskGroup.start_soon()anyio.from_thread.run()anyio.from_thread.run_sync()anyio.to_thread.run_sync()anyio.to_process.run_sync()BlockingPortal.call()BlockingPortal.start_task_soon()BlockingPortal.start_task()
(also resolves #560)
Fixed various type annotations of
anyio.Pathto match Typeshed:anyio.Path.__lt__()anyio.Path.__le__()anyio.Path.__gt__()anyio.Path.__ge__()anyio.Path.__truediv__()anyio.Path.__rtruediv__()anyio.Path.hardlink_to()anyio.Path.samefile()anyio.Path.symlink_to()anyio.Path.with_segments()
(PR by Ganden Schaffner)
Fixed adjusting the total number of tokens in a
CapacityLimiteron asyncio failing to wake up tasks waiting to acquire the limiter in certain edge cases (fixed with help from Egor Blagov)Fixed
loop_factoryanduse_uvloopoptions not being used on the asyncio backend (#643)Fixed cancellation propagating on asyncio from a task group to child tasks if the task hosting the task group is in a shielded cancel scope (#642)
4.1.0
Adapted to API changes made in Trio v0.23:
Call
trio.to_thread.run_sync()using theabandon_on_cancelkeyword argument instead ofcancellableRemoved a checkpoint when exiting a task group
Renamed the
cancellableargument inanyio.to_thread.run_sync()toabandon_on_cancel(and deprecated the old parameter name)Bumped minimum version of Trio to v0.23
Added support for voluntary thread cancellation via
anyio.from_thread.check_cancelled()Bumped minimum version of trio to v0.23
Exposed the
ResourceGuardclass in the public API (#627)Fixed
RuntimeError: Runner is closedwhen running higher-scoped async generator fixtures in some cases (#619)Fixed discrepancy between
asyncioandtriowhere reraising a cancellation exception in anexcept*block would incorrectly bubble out of its cancel scope (#634)
4.0.0
BACKWARDS INCOMPATIBLE Replaced AnyIO's own
ExceptionGroupclass with the PEP 654BaseExceptionGroupandExceptionGroupBACKWARDS INCOMPATIBLE Changes to cancellation semantics:
Any exceptions raising out of a task groups are now nested inside an
ExceptionGroup(orBaseExceptionGroupif one or moreBaseExceptionwere 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
TaskGroupalways hits a yield point, regardless of whether there are running child tasks to be waited onOn 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()andanyio.Path.is_relative_to()to only accept one argument, as passing multiple arguments is deprecated as of Python 3.12BACKWARDS INCOMPATIBLE Dropped support for spawning tasks from old-style coroutine functions (
@asyncio.coroutine)BACKWARDS INCOMPATIBLE The
policyoption on theasynciobackend was changed toloop_factoryto accommodateasyncio.RunnerChanged
anyio.run()to useasyncio.Runner(or a back-ported version of it on Pythons older than 3.11) on theasynciobackendDropped 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()andanyio.Path.walk()methodsAdded
create_unix_datagram_socketandcreate_connected_unix_datagram_socketto create UNIX datagram sockets (PR by Jean Hominal)Fixed
from_thread.runandfrom_thread.run_syncnot setting sniffio on asyncio. As a result:Fixed
from_thread.run_syncfailing when used to call sniffio-dependent functions on asyncioFixed
from_thread.runfailing when used to call sniffio-dependent functions on asyncio from a thread running trio or curioFixed 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_typeargument ofcreate_memory_object_streamwas deprecated. To indicate the item type handled by the stream, usecreate_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_caughtproperty which tells users if the cancel scope suppressed a cancellation exceptionFixed
fail_after()raising an unwarrantedTimeoutErrorwhen the cancel scope was cancelled before reaching its deadlineFixed
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 outsideFixed tasks started from
BlockingPortalnot notifying synchronous listeners (concurrent.futures.wait()) when they're cancelledRemoved unnecessary extra waiting cycle in
Event.wait()on asyncio in the case where the event was not yet setFixed 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 theto_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
CancelScopeto 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 theCancelledErrorand raise another, thus erasing the original cancel messageWorked 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_typeargument tocreate_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 theto_process.run_sync()call, leading to increased memory consumption (PR by Anael Gorfinkel)
3.7.1
Fixed sending large buffers via UNIX stream sockets on asyncio
Fixed several minor documentation issues (broken links to classes, missing classes or attributes)
3.7.0
Dropped support for Python 3.6
Improved type annotations:
Several functions and methods that were previously annotated as accepting
Coroutine[Any, Any, Any]as the return type of the callable have been amended to acceptAwaitable[Any]instead, to allow a slightly broader set of coroutine-like inputs, likeasync_generator_asendobjects returned from theasend()method of async generators, and to match thetrioannotations:anyio.run()anyio.from_thread.run()TaskGroup.start_soon()TaskGroup.start()BlockingPortal.call()BlockingPortal.start_task_soon()BlockingPortal.start_task()
Note that this change involved only changing the type annotations; run-time functionality was not altered.
The
TaskStatusclass is now a generic protocol, and should be parametrized to indicate the type of the value passed totask_status.started()The
Listenerclass is now covariant in its stream typecreate_memory_object_stream()now allows passing onlyitem_typeObject receive streams are now covariant and object send streams are correspondingly contravariant
Changed
TLSAttribute.shared_ciphersto match the documented semantics ofSSLSocket.shared_ciphersof always returningNonefor client-side streamsFixed
CapacityLimiteron the asyncio backend to order waiting tasks in the FIFO order (instead of LIFO) (PR by Conor Stevenson)Fixed
CancelScope.cancel()not working on asyncio if called before entering the scopeFixed
open_signal_receiver()inconsistently yielding integers instead ofsignal.Signalsinstances on thetriobackendFixed
to_thread.run_sync()hanging on asyncio if the target callable raisesStopIterationFixed
start_blocking_portal()raising an unwarrantedRuntimeError: This portal is not runningif a task raises an exception that causes the event loop to be closedFixed
current_effective_deadline()not returning-infon asyncio when the currently active cancel scope has been cancelled (PR by Ganden Schaffner)Fixed the
OP_IGNORE_UNEXPECTED_EOFflag in an SSL context created by default inTLSStream.wrap()being inadvertently set on Python 3.11.3 and 3.10.11Fixed
CancelScopeto properly handle asyncio task uncancellation on Python 3.11 (PR by Nikolay Bryskin)Fixed
OSErrorwhen trying to usecreate_tcp_listener()to bind to a link-local IPv6 address (and worked around related bugs inuvloop)Worked around a PyPy bug when using
anyio.getaddrinfo()with for IPv6 link-local addresses containing interface names
3.6.2
Pinned Trio to < 0.22 to avoid incompatibility with AnyIO's
ExceptionGroupclass causingAttributeError: 'NonBaseMultiError' object has no attribute '_exceptions'
3.6.1
Fixed exception handler in the asyncio test runner not properly handling a context that does not contain the
exceptionkey
3.6.0
Fixed
TypeErroringet_current_task()on asyncio when using a customTaskfactoryUpdated type annotations on
run_process()andopen_process():commandnow accepts accepts bytes and sequences of bytesstdin,stdoutandstderrnow accept file-like objects (PR by John T. Wodder II)
Changed the pytest plugin to run both the setup and teardown phases of asynchronous generator fixtures within a single task to enable use cases such as cancel scopes and task groups where a context manager straddles the
yield
3.5.0
Added
start_new_sessionkeyword argument torun_process()andopen_process()(PR by Jordan Speicher)Fixed deadlock in synchronization primitives on asyncio which can happen if a task acquiring a primitive is hit with a native (not AnyIO) cancellation with just the right timing, leaving the next acquiring task waiting forever (#398)
Added workaround for bpo-46313 to enable compatibility with OpenSSL 3.0
3.4.0
Added context propagation to/from worker threads in
to_thread.run_sync(),from_thread.run()andfrom_thread.run_sync()(#363; partially based on a PR by Sebastián Ramírez)NOTE: Requires Python 3.7 to work properly on asyncio!
Fixed race condition in
LockandSemaphoreclasses when a task waiting onacquire()is cancelled while another task is waiting to acquire the same primitive (#387)Fixed async context manager's
__aexit__()method not being called inBlockingPortal.wrap_async_context_manager()if the host task is cancelled (#381; PR by Jonathan Slenders)Fixed worker threads being marked as being event loop threads in sniffio
Fixed task parent ID not getting set to the correct value on asyncio
Enabled the test suite to run without IPv6 support, trio or pytest plugin autoloading
3.3.4
Fixed
BrokenResourceErrorinstead ofEndOfStreambeing raised inTLSStreamwhen the peer abruptly closes the connection whileTLSStreamis receiving data withstandard_compatible=Falseset
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.exceptionsattributeChanged the asyncio test runner not to use uvloop by default (to match the behavior of
anyio.run())Fixed
RuntimeErroron asyncio when aCancelledErroris raised from a task spawned through aBlockingPortal(#357)Fixed asyncio warning about a
Futurewith 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
PathclassAdded the
wrap_file()function for wrapping existing files as asynchronous file objectsRelaxed the type of the
pathinitializer argument toFileReadStreamandFileWriteStreamso they accept any path-like object (including the new asynchronousPathclass)Dropped unnecessary dependency on the
async_generatorlibraryChanged the generics in
AsyncFileso that the methods correctly return eitherstrorbytesbased 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_uvloopasyncio backend option toFalseto 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
ResourceWarningabout 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.Awaitableprotocol
3.1.0
Added
envandcwdkeyword 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 oneCancelledErrorwill now be raised instead of anExceptionGroup, allowing asyncio to ignore it when it propagates out of the taskChanged task names to be converted to
strearly on asyncio (PR by Thomas Grainger)Fixed
sniffio._impl.AsyncLibraryNotFoundError: unknown async library, or not in async contexton 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 groupappearing 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_attributesraisingAttributeError(PR by Thomas Grainger)Fixed
await maybe_async(current_task())returningNone(PR by Thomas Grainger)Fixed:
pickle.dumps(current_task())now correctly raisesTypeErrorinstead 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()raisingRuntimeErroron 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.abcfrom 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_soonCapacityLimiter.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
SocketStreamandSocketListenerclasses were made non-genericMade all non-frozen dataclasses hashable with
eq=FalseRemoved
__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
UNIXSocketStreamclass which is capable of sending and receiving file descriptorsAdded the
FileReadStreamandFileWriteStreamclassescreate_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
nameargument toBlockingPortal.start_task_soon()(renamed fromBlockingPortal.spawn_task())Changed
CancelScope.deadlineto be writableAdded the following functions in the
anyio.lowlevelmodule: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,MemoryObjectReceiveStreamandMemoryObjectSendStreamLockandConditioncan 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_tokensproperty is now writable andCapacityLimiter.set_total_tokens()has been deprecatedAdded the
max_valueproperty 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
CancelScopeto raise aRuntimeErrorif 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
RunVarso 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()raisingKeyErroron asyncio when no cancel scope is active
Added the
RunVarclass 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()raisingValueErrorinstead of the expectedNotImplementedErrorFixed
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
ExceptionGroupcontaining too many newlines
2.1.0
Added the
spawn_task()andwrap_async_context_manager()methods toBlockingPortalAdded the
handshake_timeoutanderror_handlerparameters toTLSListenerFixed
Eventobjects on the trio backend not inheriting fromanyio.abc.EventFixed
run_sync_in_worker_thread()raisingUnboundLocalErroron asyncio when cancelledFixed
send()on socket streams not raising any exception on asyncio, and an unwrappedBrokenPipeErroron trio and curio when the peer has disconnectedFixed
MemoryObjectSendStream.send()raisingBrokenResourceErrorwhen the last receiver is closed right after receiving the itemFixed
ValueError: Invalid file descriptor: -1when closing aSocketListeneron 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
TLSStreamreturning an empty bytes object instead of raisingEndOfStreamwhen trying to receive from the stream after a closing handshakeFixed
AttributeErrorwhen cancelling a task group's scope inside an async test fixture on asyncioFixed
wait_all_tasks_blocked()raisingAttributeErroron 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()ofExceptionGroupto 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
SocketStreamand 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. TheTLSRequiredexception has also been removed as it is no longer necessary.BACKWARDS INCOMPATIBLE Buffering functionality (
receive_until()andreceive_exactly()) was split off fromSocketStreaminto 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
EndOfStreaminstead 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_addressport→local_portreuse_addresswas replaced withreuse_port(and setsSO_REUSEPORTinstead ofSO_REUSEADDR)
connect_tcp()had some of its parameters changed:address→remote_addressport→remote_portbind_host→local_addressbind_port→ (removed)autostart_tls→tlstls_hostname(new parameter, when you want to match the certificate against against something else thanremote_address)
connect_tcp()now returns aTLSStreamif TLS was enablednotify_socket_closing()was removed, as it is no longer used by AnyIOSocketStreamhas 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 foron 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)
UDPSockethas 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 foron the UDP socket instead)send()→ requires a tuple for destination now (address, port), for compatibility with the newUnreliableObjectStreaminterface. Thesendto()method works like the oldsend()method.setsockopt()→.extra(SocketAttribute.raw_socket).setsockopt(...)
BACKWARDS INCOMPATIBLE Renamed the
max_sizeparameter tomax_byteswherever it occurred (this was inconsistently namedmax_bytesin some subclasses before)Added memory object streams as a replacement for queues
Added stream wrappers for encoding/decoding unicode strings
Support for the
SO_REUSEPORToption (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,ConditionandSemaphoreclassesBACKWARDS 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-backendscommand line option for the pytest plugin. Use the-koption to do ad-hoc filtering, and theanyio_backendfixture 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
familyandreuse_addressparameters 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
addressparameter inUDPSocket.send()to includeIPAddressobjects (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
addressandpeer_addressproperties to theSocketStreaminterface
1.2.3
Repackaged release (v1.2.2 contained extra files from an experimental branch which broke imports)
1.2.2
Fixed
CancelledErrorleaking from a cancel scope on asyncio if the task previously received a cancellation exceptionFixed
AttributeErrorwhen 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
AssertionErrorinconnect_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 toCapacityLimiterAdded the
anyio.current_default_thread_limiter()functionAdded the
cancellableparameter toanyio.run_in_thread()Implemented the Happy Eyeballs (RFC 6555) algorithm for
anyio.connect_tcp()Fixed
KeyErroron asyncio and curio where entering and exiting a cancel scope happens in different tasksFixed deprecation warnings on Python 3.8 about the
loopargument ofasyncio.Event()Forced the use
WindowsSelectorEventLoopPolicyinasyncio.runwhen on Windows and asyncio to keep network functionality workingWorker threads are now spawned with
daemon=Trueon all backends, not just trioDropped support for trio v0.11
1.1.0
Added the
lockparameter 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
CancelledErrorwithget_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_idattribute toanyio.TaskInfoAdded 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 theSocketStreamAPIFixed mishandling of large buffers by
BaseSocket.sendall()Fixed compatibility with (and upgraded minimum required version to) trio v0.11
1.0.0b1
Initial release