Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-asgiref for openSUSE:Factory checked in at 2023-11-30 21:59:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-asgiref (Old)
and /work/SRC/openSUSE:Factory/.python-asgiref.new.25432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-asgiref"
Thu Nov 30 21:59:42 2023 rev:10 rq:1129812 version:3.7.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-asgiref/python-asgiref.changes 2023-04-22 22:03:06.386165616 +0200
+++ /work/SRC/openSUSE:Factory/.python-asgiref.new.25432/python-asgiref.changes 2023-11-30 22:00:40.927647124 +0100
@@ -1,0 +2,21 @@
+Wed Nov 29 13:04:33 UTC 2023 - Dirk Müller
+
+- update to 3.7.2:
+ * 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 that version and above)
+ * 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.
+
+-------------------------------------------------------------------
Old:
----
asgiref-3.6.0.tar.gz
New:
----
asgiref-3.7.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-asgiref.spec ++++++
--- /var/tmp/diff_new_pack.TyK56N/_old 2023-11-30 22:00:41.431665691 +0100
+++ /var/tmp/diff_new_pack.TyK56N/_new 2023-11-30 22:00:41.435665839 +0100
@@ -16,32 +16,25 @@
#
-%define skip_python2 1
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%{?sle15_python_module_pythons}
Name: python-asgiref
-Version: 3.6.0
+Version: 3.7.2
Release: 0
Summary: ASGI specs, helper code, and adapters
License: BSD-3-Clause
Group: Development/Languages/Python
URL: https://github.com/django/asgiref/
Source: https://files.pythonhosted.org/packages/source/a/asgiref/asgiref-%{version}.tar.gz
-BuildRequires: %{python_module base >= 3.6}
+BuildRequires: %{python_module base >= 3.7}
+BuildRequires: %{python_module pip}
BuildRequires: %{python_module pytest-asyncio}
BuildRequires: %{python_module pytest}
-BuildRequires: %{python_module setuptools}
+BuildRequires: %{python_module wheel}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
BuildArch: noarch
-%if %{?suse_version} < 1540
-BuildRequires: %{python_module typing_extensions}
-%else
-BuildRequires: %{python_module typing_extensions if %python-base < 3.8}
-%endif
-%if 0%{python_version_nodots} < 38
-Requires: python-typing_extensions
-%endif
+BuildRequires: %{python_module typing-extensions > 4}
+Requires: python-typing-extensions > 4
%python_subpackages
%description
@@ -53,10 +46,10 @@
%setup -q -n asgiref-%{version}
%build
-%python_build
+%pyproject_wheel
%install
-%python_install
+%pyproject_install
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
@@ -65,5 +58,6 @@
%files %{python_files}
%license LICENSE
%doc README.rst
-%{python_sitelib}/*
+%{python_sitelib}/asgiref
+%{python_sitelib}/asgiref-%{version}.dist-info
++++++ asgiref-3.6.0.tar.gz -> asgiref-3.7.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/PKG-INFO new/asgiref-3.7.2/PKG-INFO
--- old/asgiref-3.6.0/PKG-INFO 2022-12-20 10:06:25.459167200 +0100
+++ new/asgiref-3.7.2/PKG-INFO 2023-05-27 19:21:19.747680700 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: asgiref
-Version: 3.6.0
+Version: 3.7.2
Summary: ASGI specs, helper code, and adapters
Home-page: https://github.com/django/asgiref/
Author: Django Software Foundation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/asgiref/__init__.py new/asgiref-3.7.2/asgiref/__init__.py
--- old/asgiref-3.6.0/asgiref/__init__.py 2022-12-20 09:57:26.000000000 +0100
+++ new/asgiref-3.7.2/asgiref/__init__.py 2023-05-27 19:20:44.000000000 +0200
@@ -1 +1 @@
-__version__ = "3.6.0"
+__version__ = "3.7.2"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/asgiref/current_thread_executor.py new/asgiref-3.7.2/asgiref/current_thread_executor.py
--- old/asgiref-3.6.0/asgiref/current_thread_executor.py 2022-04-19 09:47:42.000000000 +0200
+++ new/asgiref-3.7.2/asgiref/current_thread_executor.py 2023-05-23 18:35:51.000000000 +0200
@@ -1,6 +1,17 @@
import queue
+import sys
import threading
from concurrent.futures import Executor, Future
+from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union
+
+if sys.version_info >= (3, 10):
+ from typing import ParamSpec
+else:
+ from typing_extensions import ParamSpec
+
+_T = TypeVar("_T")
+_P = ParamSpec("_P")
+_R = TypeVar("_R")
class _WorkItem:
@@ -9,13 +20,20 @@
Copied from ThreadPoolExecutor (but it's private, so we're not going to rely on importing it)
"""
- def __init__(self, future, fn, args, kwargs):
+ def __init__(
+ self,
+ future: "Future[_R]",
+ fn: Callable[_P, _R],
+ *args: _P.args,
+ **kwargs: _P.kwargs,
+ ):
self.future = future
self.fn = fn
self.args = args
self.kwargs = kwargs
- def run(self):
+ def run(self) -> None:
+ __traceback_hide__ = True # noqa: F841
if not self.future.set_running_or_notify_cancel():
return
try:
@@ -23,7 +41,7 @@
except BaseException as exc:
self.future.set_exception(exc)
# Break a reference cycle with the exception 'exc'
- self = None
+ self = None # type: ignore[assignment]
else:
self.future.set_result(result)
@@ -35,12 +53,12 @@
the thread they came from.
"""
- def __init__(self):
+ def __init__(self) -> None:
self._work_thread = threading.current_thread()
- self._work_queue = queue.Queue()
+ self._work_queue: queue.Queue[Union[_WorkItem, "Future[Any]"]] = queue.Queue()
self._broken = False
- def run_until_future(self, future):
+ def run_until_future(self, future: "Future[Any]") -> None:
"""
Runs the code in the work queue until a result is available from the future.
Should be run from the thread the executor is initialised in.
@@ -59,12 +77,18 @@
work_item = self._work_queue.get()
if work_item is future:
return
+ assert isinstance(work_item, _WorkItem)
work_item.run()
del work_item
finally:
self._broken = True
- def submit(self, fn, *args, **kwargs):
+ def _submit(
+ self,
+ fn: Callable[_P, _R],
+ *args: _P.args,
+ **kwargs: _P.kwargs,
+ ) -> "Future[_R]":
# Check they're not submitting from the same thread
if threading.current_thread() == self._work_thread:
raise RuntimeError(
@@ -74,8 +98,18 @@
if self._broken:
raise RuntimeError("CurrentThreadExecutor already quit or is broken")
# Add to work queue
- f = Future()
- work_item = _WorkItem(f, fn, args, kwargs)
+ f: "Future[_R]" = Future()
+ work_item = _WorkItem(f, fn, *args, **kwargs)
self._work_queue.put(work_item)
# Return the future
return f
+
+ # Python 3.9+ has a new signature for submit with a "/" after `fn`, to enforce
+ # it to be a positional argument. If we ignore[override] mypy on 3.9+ will be
+ # happy but 3.7/3.8 will say that the ignore comment is unused, even when
+ # defining them differently based on sys.version_info.
+ # We should be able to remove this when we drop support for 3.7/3.8.
+ if not TYPE_CHECKING:
+
+ def submit(self, fn, *args, **kwargs):
+ return self._submit(fn, *args, **kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/asgiref/sync.py new/asgiref-3.7.2/asgiref/sync.py
--- old/asgiref-3.6.0/asgiref/sync.py 2022-12-15 10:04:51.000000000 +0100
+++ new/asgiref-3.7.2/asgiref/sync.py 2023-05-27 19:19:57.000000000 +0200
@@ -9,21 +9,48 @@
import warnings
import weakref
from concurrent.futures import Future, ThreadPoolExecutor
-from typing import Any, Callable, Dict, Optional, overload
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Awaitable,
+ Callable,
+ Coroutine,
+ Dict,
+ Generic,
+ List,
+ Optional,
+ TypeVar,
+ Union,
+ overload,
+)
from .current_thread_executor import CurrentThreadExecutor
from .local import Local
+if sys.version_info >= (3, 10):
+ from typing import ParamSpec
+else:
+ from typing_extensions import ParamSpec
-def _restore_context(context):
+if TYPE_CHECKING:
+ # This is not available to import at runtime
+ from _typeshed import OptExcInfo
+
+_F = TypeVar("_F", bound=Callable[..., Any])
+_P = ParamSpec("_P")
+_R = TypeVar("_R")
+
+
+def _restore_context(context: contextvars.Context) -> None:
# Check for changes in contextvars, and set them to the current
# context for downstream consumers
for cvar in context:
+ cvalue = context.get(cvar)
try:
- if cvar.get() != context.get(cvar):
- cvar.set(context.get(cvar))
+ if cvar.get() != cvalue:
+ cvar.set(cvalue)
except LookupError:
- cvar.set(context.get(cvar))
+ cvar.set(cvalue)
# Python 3.12 deprecates asyncio.iscoroutinefunction() as an alias for
@@ -32,29 +59,25 @@
# Until 3.12 is the minimum supported Python version, provide a shim.
# Django 4.0 only supports 3.8+, so don't concern with the _or_partial backport.
-# Type hint: should be generic: whatever T it takes it returns. (Same id)
-def markcoroutinefunction(func: Any) -> Any:
- if hasattr(inspect, "markcoroutinefunction"):
- return inspect.markcoroutinefunction(func)
- else:
+if hasattr(inspect, "markcoroutinefunction"):
+ iscoroutinefunction = inspect.iscoroutinefunction
+ markcoroutinefunction: Callable[[_F], _F] = inspect.markcoroutinefunction
+else:
+ iscoroutinefunction = asyncio.iscoroutinefunction # type: ignore[assignment]
+
+ def markcoroutinefunction(func: _F) -> _F:
func._is_coroutine = asyncio.coroutines._is_coroutine # type: ignore
return func
-def iscoroutinefunction(func: Any) -> bool:
- if hasattr(inspect, "markcoroutinefunction"):
- return inspect.iscoroutinefunction(func)
- else:
- return asyncio.iscoroutinefunction(func)
-
-
-def _iscoroutinefunction_or_partial(func: Any) -> bool:
- # Python < 3.8 does not correctly determine partially wrapped
- # coroutine functions are coroutine functions, hence the need for
- # this to exist. Code taken from CPython.
- if sys.version_info >= (3, 8):
- return iscoroutinefunction(func)
- else:
+if sys.version_info >= (3, 8):
+ _iscoroutinefunction_or_partial = iscoroutinefunction
+else:
+
+ def _iscoroutinefunction_or_partial(func: Any) -> bool:
+ # Python < 3.8 does not correctly determine partially wrapped
+ # coroutine functions are coroutine functions, hence the need for
+ # this to exist. Code taken from CPython.
while inspect.ismethod(func):
func = func.__func__
while isinstance(func, functools.partial):
@@ -104,7 +127,7 @@
SyncToAsync.thread_sensitive_context.reset(self.token)
-class AsyncToSync:
+class AsyncToSync(Generic[_P, _R]):
"""
Utility class which turns an awaitable that only works on the thread with
the event loop into a synchronous callable that works in a subthread.
@@ -128,7 +151,14 @@
# inside create_task, we'll look it up here from the running event loop.
loop_thread_executors: "Dict[asyncio.AbstractEventLoop, CurrentThreadExecutor]" = {}
- def __init__(self, awaitable, force_new_loop=False):
+ def __init__(
+ self,
+ awaitable: Union[
+ Callable[_P, Coroutine[Any, Any, _R]],
+ Callable[_P, Awaitable[_R]],
+ ],
+ force_new_loop: bool = False,
+ ):
if not callable(awaitable) or (
not _iscoroutinefunction_or_partial(awaitable)
and not _iscoroutinefunction_or_partial(
@@ -142,7 +172,7 @@
)
self.awaitable = awaitable
try:
- self.__self__ = self.awaitable.__self__
+ self.__self__ = self.awaitable.__self__ # type: ignore[union-attr]
except AttributeError:
pass
if force_new_loop:
@@ -166,7 +196,9 @@
else:
self.main_event_loop = None
- def __call__(self, *args, **kwargs):
+ def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _R:
+ __traceback_hide__ = True # noqa: F841
+
# You can't call AsyncToSync from a thread with a running event loop
try:
event_loop = asyncio.get_running_loop()
@@ -184,7 +216,7 @@
context = [contextvars.copy_context()]
# Make a future for the return information
- call_result = Future()
+ call_result: "Future[_R]" = Future()
# Get the source thread
source_thread = threading.current_thread()
# Make a CurrentThreadExecutor we'll use to idle in this thread - we
@@ -202,7 +234,12 @@
# in this thread.
try:
awaitable = self.main_wrap(
- args, kwargs, call_result, source_thread, sys.exc_info(), context
+ call_result,
+ source_thread,
+ sys.exc_info(),
+ context,
+ *args,
+ **kwargs,
)
if not (self.main_event_loop and self.main_event_loop.is_running()):
@@ -275,7 +312,7 @@
loop.close()
asyncio.set_event_loop(self.main_event_loop)
- def __get__(self, parent, objtype):
+ def __get__(self, parent: Any, objtype: Any) -> Callable[_P, _R]:
"""
Include self for methods
"""
@@ -283,16 +320,26 @@
return functools.update_wrapper(func, self.awaitable)
async def main_wrap(
- self, args, kwargs, call_result, source_thread, exc_info, context
- ):
+ self,
+ call_result: "Future[_R]",
+ source_thread: threading.Thread,
+ exc_info: "OptExcInfo",
+ context: List[contextvars.Context],
+ *args: _P.args,
+ **kwargs: _P.kwargs,
+ ) -> None:
"""
Wraps the awaitable with something that puts the result into the
result/exception future.
"""
+
+ __traceback_hide__ = True # noqa: F841
+
if context is not None:
_restore_context(context[0])
current_task = SyncToAsync.get_current_task()
+ assert current_task is not None
self.launch_map[current_task] = source_thread
try:
# If we have an exception, run the function inside the except block
@@ -314,7 +361,7 @@
context[0] = contextvars.copy_context()
-class SyncToAsync:
+class SyncToAsync(Generic[_P, _R]):
"""
Utility class which turns a synchronous callable into an awaitable that
runs in a threadpool. It also sets a threadlocal inside the thread so
@@ -347,8 +394,8 @@
# Maintain a contextvar for the current execution context. Optionally used
# for thread sensitive mode.
- thread_sensitive_context: "contextvars.ContextVar[str]" = contextvars.ContextVar(
- "thread_sensitive_context"
+ thread_sensitive_context: "contextvars.ContextVar[ThreadSensitiveContext]" = (
+ contextvars.ContextVar("thread_sensitive_context")
)
# Contextvar that is used to detect if the single thread executor
@@ -359,13 +406,13 @@
# Maintaining a weak reference to the context ensures that thread pools are
# erased once the context goes out of scope. This terminates the thread pool.
- context_to_thread_executor: "weakref.WeakKeyDictionary[object, ThreadPoolExecutor]" = (
+ context_to_thread_executor: "weakref.WeakKeyDictionary[ThreadSensitiveContext, ThreadPoolExecutor]" = (
weakref.WeakKeyDictionary()
)
def __init__(
self,
- func: Callable[..., Any],
+ func: Callable[_P, _R],
thread_sensitive: bool = True,
executor: Optional["ThreadPoolExecutor"] = None,
) -> None:
@@ -387,7 +434,8 @@
except AttributeError:
pass
- async def __call__(self, *args, **kwargs):
+ async def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _R:
+ __traceback_hide__ = True # noqa: F841
loop = asyncio.get_running_loop()
# Work out what thread to run the code in
@@ -395,9 +443,7 @@
if hasattr(AsyncToSync.executors, "current"):
# If we have a parent sync thread above somewhere, use that
executor = AsyncToSync.executors.current
- elif self.thread_sensitive_context and self.thread_sensitive_context.get(
- None
- ):
+ elif self.thread_sensitive_context.get(None):
# If we have a way of retrieving the current context, attempt
# to use a per-context thread pool executor
thread_sensitive_context = self.thread_sensitive_context.get()
@@ -412,15 +458,14 @@
elif loop in AsyncToSync.loop_thread_executors:
# Re-use thread executor for running loop
executor = AsyncToSync.loop_thread_executors[loop]
- elif self.deadlock_context and self.deadlock_context.get(False):
+ elif self.deadlock_context.get(False):
raise RuntimeError(
"Single thread executor already being used, would deadlock"
)
else:
# Otherwise, we run it in a fixed single thread
executor = self.single_thread_executor
- if self.deadlock_context:
- self.deadlock_context.set(True)
+ self.deadlock_context.set(True)
else:
# Use the passed in executor, or the loop's default if it is None
executor = self._executor
@@ -428,12 +473,10 @@
context = contextvars.copy_context()
child = functools.partial(self.func, *args, **kwargs)
func = context.run
- args = (child,)
- kwargs = {}
try:
# Run the code in the right thread
- future = loop.run_in_executor(
+ ret: _R = await loop.run_in_executor(
executor,
functools.partial(
self.thread_handler,
@@ -441,20 +484,19 @@
self.get_current_task(),
sys.exc_info(),
func,
- *args,
- **kwargs,
+ child,
),
)
- ret = await asyncio.wait_for(future, timeout=None)
finally:
_restore_context(context)
- if self.deadlock_context:
- self.deadlock_context.set(False)
+ self.deadlock_context.set(False)
return ret
- def __get__(self, parent, objtype):
+ def __get__(
+ self, parent: Any, objtype: Any
+ ) -> Callable[_P, Coroutine[Any, Any, _R]]:
"""
Include self for methods
"""
@@ -465,6 +507,9 @@
"""
Wraps the sync application with exception handling.
"""
+
+ __traceback_hide__ = True # noqa: F841
+
# Set the threadlocal for AsyncToSync
self.threadlocal.main_event_loop = loop
self.threadlocal.main_event_loop_pid = os.getpid()
@@ -477,6 +522,9 @@
else:
self.launch_map[current_thread] = source_task
parent_set = True
+ source_task = (
+ None # allow the task to be garbage-collected in case of exceptions
+ )
# Run the function
try:
# If we have an exception, run the function inside the except block
@@ -495,7 +543,7 @@
del self.launch_map[current_thread]
@staticmethod
- def get_current_task():
+ def get_current_task() -> Optional["asyncio.Task[Any]"]:
"""
Implementation of asyncio.current_task()
that returns None if there is no task.
@@ -506,33 +554,84 @@
return None
-# Lowercase aliases (and decorator friendliness)
-async_to_sync = AsyncToSync
+@overload
+def async_to_sync(
+ *,
+ force_new_loop: bool = False,
+) -> Callable[
+ [Union[Callable[_P, Coroutine[Any, Any, _R]], Callable[_P, Awaitable[_R]]]],
+ Callable[_P, _R],
+]:
+ ...
+
+
+@overload
+def async_to_sync(
+ awaitable: Union[
+ Callable[_P, Coroutine[Any, Any, _R]],
+ Callable[_P, Awaitable[_R]],
+ ],
+ *,
+ force_new_loop: bool = False,
+) -> Callable[_P, _R]:
+ ...
+
+
+def async_to_sync(
+ awaitable: Optional[
+ Union[
+ Callable[_P, Coroutine[Any, Any, _R]],
+ Callable[_P, Awaitable[_R]],
+ ]
+ ] = None,
+ *,
+ force_new_loop: bool = False,
+) -> Union[
+ Callable[
+ [Union[Callable[_P, Coroutine[Any, Any, _R]], Callable[_P, Awaitable[_R]]]],
+ Callable[_P, _R],
+ ],
+ Callable[_P, _R],
+]:
+ if awaitable is None:
+ return lambda f: AsyncToSync(
+ f,
+ force_new_loop=force_new_loop,
+ )
+ return AsyncToSync(
+ awaitable,
+ force_new_loop=force_new_loop,
+ )
@overload
def sync_to_async(
- func: None = None,
+ *,
thread_sensitive: bool = True,
executor: Optional["ThreadPoolExecutor"] = None,
-) -> Callable[[Callable[..., Any]], SyncToAsync]:
+) -> Callable[[Callable[_P, _R]], Callable[_P, Coroutine[Any, Any, _R]]]:
...
@overload
def sync_to_async(
- func: Callable[..., Any],
+ func: Callable[_P, _R],
+ *,
thread_sensitive: bool = True,
executor: Optional["ThreadPoolExecutor"] = None,
-) -> SyncToAsync:
+) -> Callable[_P, Coroutine[Any, Any, _R]]:
...
def sync_to_async(
- func=None,
- thread_sensitive=True,
- executor=None,
-):
+ func: Optional[Callable[_P, _R]] = None,
+ *,
+ thread_sensitive: bool = True,
+ executor: Optional["ThreadPoolExecutor"] = None,
+) -> Union[
+ Callable[[Callable[_P, _R]], Callable[_P, Coroutine[Any, Any, _R]]],
+ Callable[_P, Coroutine[Any, Any, _R]],
+]:
if func is None:
return lambda f: SyncToAsync(
f,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/asgiref/typing.py new/asgiref-3.7.2/asgiref/typing.py
--- old/asgiref-3.6.0/asgiref/typing.py 2022-12-15 10:04:51.000000000 +0100
+++ new/asgiref-3.7.2/asgiref/typing.py 2023-05-23 18:35:51.000000000 +0200
@@ -1,11 +1,26 @@
import sys
-from typing import Awaitable, Callable, Dict, Iterable, Optional, Tuple, Type, Union
+from typing import (
+ Any,
+ Awaitable,
+ Callable,
+ Dict,
+ Iterable,
+ Optional,
+ Tuple,
+ Type,
+ Union,
+)
if sys.version_info >= (3, 8):
from typing import Literal, Protocol, TypedDict
else:
from typing_extensions import Literal, Protocol, TypedDict
+if sys.version_info >= (3, 11):
+ from typing import NotRequired
+else:
+ from typing_extensions import NotRequired
+
__all__ = (
"ASGIVersions",
"HTTPScope",
@@ -62,6 +77,7 @@
headers: Iterable[Tuple[bytes, bytes]]
client: Optional[Tuple[str, int]]
server: Optional[Tuple[str, Optional[int]]]
+ state: NotRequired[Dict[str, Any]]
extensions: Optional[Dict[str, Dict[object, object]]]
@@ -78,12 +94,14 @@
client: Optional[Tuple[str, int]]
server: Optional[Tuple[str, Optional[int]]]
subprotocols: Iterable[str]
+ state: NotRequired[Dict[str, Any]]
extensions: Optional[Dict[str, Dict[object, object]]]
class LifespanScope(TypedDict):
type: Literal["lifespan"]
asgi: ASGIVersions
+ state: NotRequired[Dict[str, Any]]
WWWScope = Union[HTTPScope, WebSocketScope]
@@ -96,6 +114,11 @@
more_body: bool
+class HTTPResponseDebugEvent(TypedDict):
+ type: Literal["http.response.debug"]
+ info: Dict[str, object]
+
+
class HTTPResponseStartEvent(TypedDict):
type: Literal["http.response.start"]
status: int
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/asgiref.egg-info/PKG-INFO new/asgiref-3.7.2/asgiref.egg-info/PKG-INFO
--- old/asgiref-3.6.0/asgiref.egg-info/PKG-INFO 2022-12-20 10:06:25.000000000 +0100
+++ new/asgiref-3.7.2/asgiref.egg-info/PKG-INFO 2023-05-27 19:21:19.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: asgiref
-Version: 3.6.0
+Version: 3.7.2
Summary: ASGI specs, helper code, and adapters
Home-page: https://github.com/django/asgiref/
Author: Django Software Foundation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/asgiref.egg-info/requires.txt new/asgiref-3.7.2/asgiref.egg-info/requires.txt
--- old/asgiref-3.6.0/asgiref.egg-info/requires.txt 2022-12-20 10:06:25.000000000 +0100
+++ new/asgiref-3.7.2/asgiref.egg-info/requires.txt 2023-05-27 19:21:19.000000000 +0200
@@ -1,6 +1,6 @@
-[:python_version < "3.8"]
-typing_extensions
+[:python_version < "3.11"]
+typing_extensions>=4
[tests]
pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/setup.cfg new/asgiref-3.7.2/setup.cfg
--- old/asgiref-3.6.0/setup.cfg 2022-12-20 10:06:25.459771600 +0100
+++ new/asgiref-3.7.2/setup.cfg 2023-05-27 19:21:19.747680700 +0200
@@ -32,7 +32,7 @@
packages = find:
include_package_data = true
install_requires =
- typing_extensions; python_version < "3.8"
+ typing_extensions>=4; python_version < "3.11"
zip_safe = false
[options.extras_require]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asgiref-3.6.0/tests/test_sync_contextvars.py new/asgiref-3.7.2/tests/test_sync_contextvars.py
--- old/asgiref-3.6.0/tests/test_sync_contextvars.py 2022-07-06 16:22:11.000000000 +0200
+++ new/asgiref-3.7.2/tests/test_sync_contextvars.py 2023-05-23 18:35:51.000000000 +0200
@@ -1,4 +1,5 @@
import asyncio
+import contextvars
import threading
import time
@@ -6,9 +7,7 @@
from asgiref.sync import ThreadSensitiveContext, async_to_sync, sync_to_async
-contextvars = pytest.importorskip("contextvars")
-
-foo = contextvars.ContextVar("foo")
+foo: "contextvars.ContextVar[str]" = contextvars.ContextVar("foo")
@pytest.mark.asyncio