NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #238 most downloaded on PyPI
ASGI specs, helper code, and adapters
Last release 2 months ago
14 Jul 2026
Release timing varies
gaps range from 2 weeks to 1.3 years
Nearly every release is documented
notes for 58 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
11 years old
72 releases · first in 2016
Restored the previous SyncToAsync.__call__ internal code shape, which was relied on by some APM services.
Restored the previous SyncToAsync.call internal code shape, which was relied on by some APM services. (#572)
Note, this change was available whilst maintaining the underlying fix (from #564). It does not constitute an API stability promise. Ideally APMs are not monkey patching internal APIs, and future changes will be made here if needed.
AsyncToSync no longer captures the running event loop on instantiation.
AsyncToSync no longer captures the running event loop on
instantiation. (#562)
This resolves a series of deadlocks that users experienced after asgiref 3.9.0, particularly with pytest-asyncio. pytest-asyncio stops the event loop between tests, and long-running unawaited futures could find themselves trying to schedule work onto a stopped loop, and so would never complete. Ideally, code should be structured to await long-running futures before returning, but this change should help users experiencing issues here.
The loop is now resolved when the callable is invoked rather than when it is
created. If async_to_sync is called from within sync_to_async, the
parent event loop is still used, as before.
The possibility of deadlock therefore remains in some nested patterns. For
example, an async function may call a long-running sync_to_async function
that itself uses async_to_sync; if the outer function returns before the
sync future completes, the parent event loop may already be stopped, and the
nested calls cannot be driven to completion.
This is not a bug in asgiref — the same patterns deadlock in plain asyncio. As
above, restructure your code to await the sync_to_async future before
exiting the driving coroutine.
Fixed an event loop deadlock when exiting ThreadSensitiveContext
while its executor thread was still blocked waiting on the event loop.
(#535)
Dropped support for EOL Python 3.9.
Fixed StatelessServer.run() failing on Python 3.14, where
asyncio.get_event_loop() no longer creates an event loop if none
exists. It now uses asyncio.run(). (#559)
Fixed Local leaking data between unrelated sync threads when
sys.flags.thread_inherit_context is enabled (Python 3.14+), so a newly
started thread inherits a copy of the spawning thread's context. This flag is
on by default on free-threaded builds and opt-in on the regular GIL build.
Local storage is now tagged with its owning thread and re-homed only when
asgiref intentionally moves work across threads (in async_to_sync /
sync_to_async), restoring the documented thread-local behaviour in sync
threads.
asgiref is now tested against the free-threaded builds of Python 3.13 and 3.14 in CI.
The tests extra no longer installs mypy; a new mypy extra is
available for type-checking the codebase.
One column per quarter.
SECURITY FIX CVE-2025-14550: There was a potential DoS vector for users of the asgiref.wsgi.WsgiToAsgi adapter. Malicious requests, including an unrea…
SECURITY FIX CVE-2025-14550: There was a potential DoS vector for users of
the asgiref.wsgi.WsgiToAsgi adapter. Malicious requests, including an unreasonably
large number of values for the same header, could lead to resource exhaustion
when building the WSGI environment.
To mitigate this, the algorithm is changed to be more efficient, and
WsgiToAsgi gains a new optional duplicate_header_limit parameter,
which defaults to 100. This specifies the number of times a single header may
be repeated before the request is rejected as malformed.
You may override duplicate_header_limit when configuring your application::
application = WsgiToAsgi(wsgi_app, duplicate_header_limit=200)
Set duplicate_header_limit=None if you wish to disable this check.
Fixed a regression in 3.11.0 in sync_to_async when wrapping a callable
with an attribute named context. (#537)
sync_to_async gains a context parameter, similar to those for asyncio.create_task, TaskGroup &co, that can be used on Python 3.11+ to control the cont
sync_to_async gains a context parameter, similar to those for
asyncio.create_task, TaskGroup &co, that can be used on Python 3.11+ to
control the context used by the underlying task.
The parent context is already propagated by default but the additional
control is useful if multiple sync_to_async calls need to share the same
context, e.g. when used with asyncio.gather().
Added AsyncSingleThreadContext context manager to ensure multiple AsyncToSync invocations use the same thread.
Fixes wsgi.errors file descriptor in WsgiToAsgi adapter.
Adds support for Python 3.14.
Fixes wsgi.errors file descriptor in WsgiToAsgi adapter.
Fixed deletion of Local values affecting other contexts.
Fixed deletion of Local values affecting other contexts. (#523)
Skip CPython specific garbage collection test on pypy. (#521)
Drops support for (end-of-life) Python 3.8.
Adds support for Python 3.13.
Drops support for (end-of-life) Python 3.8.
Fixes an error with conflicting kwargs between AsyncToSync and the wrapped function. (#471)
Fixes Local isolation between asyncio Tasks. (#478)
Fixes a reference cycle in Local (#508)
Fixes a deadlock in CurrentThreadExecutor with nested async_to_sync → sync_to_async → async_to_sync → create_task calls. (#494)
The ApplicationCommunicator testing utility will now return the task result if it's already completed on send_input and receive_nothing. You may need to catch (e.g.) the asyncio.exceptions.CancelledError if sending messages to already finished consumers in your tests. (#505)
Fixes a regression in 3.8.0 affecting nested task cancellation inside sync_to_async.
Drops support for (end-of-life) Python 3.7.
Adds support for Python 3.12.
Drops support for (end-of-life) Python 3.7.
Fixes task cancellation propagation to subtasks when using synchronous Django middleware.
Allows nesting sync_to_async via asyncio.wait_for.
Corrects WSGI adapter handling of root path.
Handles case where "client" is None in WsgiToAsgi adapter.
The type annotations for SyncToAsync and AsyncToSync have been changed to more accurately reflect the kind of callables they return.
On Python 3.10 and below, the version of the "typing_extensions" package is now constrained to be at least version 4 (as we depend on functionality in
Contextvars are now required for the implementation of sync as Python 3.6 is now no longer a supported version.
Contextvars are now required for the implementation of sync as Python 3.6
is now no longer a supported version.
sync_to_async and async_to_sync now pass-through
Debug and Lifespan State extensions have resulted in a typing change for some request and response types. This change should be backwards-compatible.
asgiref frames will now be hidden in Django tracebacks by default.
Raw performance and garbage collection improvements in Local, SyncToAsync, and AsyncToSync.
Python 3.12 deprecates asyncio.iscoroutinefunction() as an alias for inspect.iscoroutinefunction(), whilst also removing the _is_coroutine marker. The…
Two new functions are added to the asgiref.sync module: iscoroutinefunction()
and markcoroutinefunction().
Python 3.12 deprecates asyncio.iscoroutinefunction() as an alias for
inspect.iscoroutinefunction(), whilst also removing the _is_coroutine marker.
The latter is replaced with the inspect.markcoroutinefunction decorator.
The new asgiref.sync functions are compatibility shims for these
functions that can be used until Python 3.12 is the minimum supported
version.
Note that these functions are considered beta, and as such, whilst
not likely, are subject to change in a point release, until the final release
of Python 3.12. They are included in asgiref now so that they can be
adopted by Django 4.2, in preparation for support of Python 3.12.
The loop argument to asgiref.timeout.timeout is deprecated. As per other
asyncio based APIs, the running event loop is used by default. Note that
asyncio provides timeout utilities from Python 3.11, and these should be
preferred where available.
Support for the ASGI_THREADS environment variable, used by
SyncToAsync, is removed. In general, a running event-loop is not
available to asgiref at import time, and so the default thread pool
executor cannot be configured. Protocol servers, or applications, should set
the default executor as required when configuring the event loop at
application startup.
Allow async-callables class instances to be passed to AsyncToSync without warning
Allow async-callables class instances to be passed to AsyncToSync without warning
Prevent giving async-callable class instances to SyncToAsync
sync_to_async in thread-sensitive mode now works corectly when the outermost thread is synchronous
Python 3.6 is no longer supported, and asyncio calls have been changed to use only the modern versions of the APIs as a result
Python 3.6 is no longer supported, and asyncio calls have been changed to use only the modern versions of the APIs as a result
Several causes of RuntimeErrors in cases where an event loop was assigned to a thread but not running
Speed improvements in the Local class
Fixed an issue with the deadlock detection where it had false positives during exception handling.
asyncio usage has been updated to use the new versions of get_event_loop, ensure_future, wait and gather, avoiding deprecation warnings in Python 3.10…
Calling sync_to_async directly from inside itself (which causes a deadlock when in the default, thread-sensitive mode) now has deadlock detection.
asyncio usage has been updated to use the new versions of get_event_loop, ensure_future, wait and gather, avoiding deprecation warnings in Python 3.10. Python 3.6 installs continue to use the old versions; this is only for 3.7+
sync_to_async and async_to_sync now have improved type hints that pass through the underlying function type correctly.
All Websocket* types are now spelled WebSocket, to match our specs and the official spelling. The old names will work until release 3.5.0, but will raise deprecation warnings.
The typing for WebSocketScope and HTTPScope's extensions key has been
fixed.
The async_to_sync type error is now a warning due the high false negative rate when trying to detect coroutine-returning callables in Python.
The sync conversion functions now correctly detect functools.partial and other wrappers around async functions on earlier Python releases.
SyncToAsync now takes an optional "executor" argument if you want to supply your own executor rather than using the built-in one.
SyncToAsync now takes an optional "executor" argument if you want to supply your own executor rather than using the built-in one.
async_to_sync and sync_to_async now check their arguments are functions of the correct type.
Raising CancelledError inside a SyncToAsync function no longer stops a future call from functioning.
ThreadSensitive now provides context hooks/override options so it can be made to be sensitive in a unit smaller than threads (e.g. per request)
Drop Python 3.5 support.
Add type annotations.
Updated StatelessServer to use ASGI v3 single-callable applications.
sync_to_async now defaults to thread-sensitive mode being on
Fixed bugs due to bad WeakRef handling introduced in 3.2.8
Fixed regression with exception handling in 3.2.8 related to the contextvars fix.
Fixed small memory leak in local.Local
Bug fixed in local.Local where deleted Locals would occasionally inherit their storage into new Locals due to memory reuse.
local.Local now works in all threading situations, no longer requires periodic garbage collection, and works with libraries that monkeypatch threading
__self__ is now preserved on methods by async_to_sync
Pending tasks/async generators are now cancelled when async_to_sync exits
Added support and testing for Python 3.8.
WsgiToAsgi maps multi-part request bodies into a single WSGI input file
root_path scope as SCRIPT_NAMElifespan bettersys.exc_info() is now propagated across thread boundaries
New "thread_sensitive" argument to SyncToAsync allows for pinning of code into the same thread as other thread_sensitive code.
Fixed an incompatibility with Python 3.5 introduced in the last release.
async_timeout has been removed as a dependency, so there are now no required dependencies.
REMOTE_ADDR from the ASGI client.New thread_critical argument to Local to tell it to not inherit contexts across threads/tasks.
Local now cleans up storage of old threads and tasks to prevent a memory leak.
Added asgiref.local module to provide threading.local drop-in replacement.
asgiref.local module to provide threading.local drop-in replacement.Updated to match new ASGI 3.0 spec
Packaging fix to allow old async_timeout dependencies (2.0 as well as 3.0)
WSGI-to-ASGI adapter now works with empty bodies in responses
ApplicationCommunicator now has a receive_nothing() test available
Cancelled tasks now correctly cascade-cancel their children
Cancelled tasks now correctly cascade-cancel their children
Communicator.wait() no longer re-raises CancelledError from inner coroutines
async_to_sync now works inside of threads (but is still not allowed in threads that have an active event loop)
Fixed issues with async_to_sync not setting the event loop correctly
Fixed issues with async_to_sync not setting the event loop correctly
Stop async_to_sync being called from threads with an active event loop
Values are now correctly returned from sync_to_async and async_to_sync
Values are now correctly returned from sync_to_async and async_to_sync
ASGI_THREADS environment variable now works correctly
Add an ApplicationCommunicator.wait() method to allow you to wait for an application instance to exit before seeing what it did.
Allow AsyncToSync to work if called from a non-async-wrapped sync context.
Allow AsyncToSync constructor to be called inside SyncToAsync.
Add asgiref.testing module with ApplicationCommunicator testing helper
asgiref.testing module with ApplicationCommunicator testing helperBugfix release to have HTTP response content message as the correct "http.response.content" not the older "http.response.chunk".
Complete rewrite for new async-based ASGI mechanisms and removal of channel layers.
Conformance test suite now allows for retries and tests group_send's behaviour with capacity
Error with sending to multi-process channels with the same message fixed
Process-specific channel behaviour has been changed, and the base layer and conformance suites updated to match.
Improved channel and group name validation
In-memory layer deepcopies messages so they cannot be mutated post-send
receive_many is now receiveNothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →