From 09ed8e952c728091cfac9b0ddc154dc2b4c734bc Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Thu, 12 Oct 2023 21:11:06 +0200 Subject: [PATCH] Dropped Python 3.7 support Includes mypy error fix. --- .github/workflows/tests.yml | 1 - .pre-commit-config.yaml | 4 ++-- README.rst | 2 +- asgiref/current_thread_executor.py | 4 ++-- asgiref/sync.py | 31 ++++++------------------------ asgiref/typing.py | 8 +++----- setup.cfg | 3 +-- setup.py | 2 +- specs/asgi.rst | 14 -------------- tox.ini | 2 +- 10 files changed, 17 insertions(+), 54 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ae2640f1..f2b5cc85 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,6 @@ jobs: fail-fast: false matrix: python-version: - - 3.7 - 3.8 - 3.9 - '3.10' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 20968656..5c8b0d91 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,13 +3,13 @@ repos: rev: v3.3.1 hooks: - id: pyupgrade - args: ["--py37-plus"] + args: ["--py38-plus"] - repo: https://github.com/psf/black rev: 22.12.0 hooks: - id: black - args: ["--target-version=py37"] + args: ["--target-version=py38"] - repo: https://github.com/pycqa/isort rev: 5.11.5 diff --git a/README.rst b/README.rst index 5fcca634..46b1714b 100644 --- a/README.rst +++ b/README.rst @@ -96,7 +96,7 @@ file handles for incoming POST bodies). Dependencies ------------ -``asgiref`` requires Python 3.7 or higher. +``asgiref`` requires Python 3.8 or higher. Contributing diff --git a/asgiref/current_thread_executor.py b/asgiref/current_thread_executor.py index c9a97dd5..67a7926f 100644 --- a/asgiref/current_thread_executor.py +++ b/asgiref/current_thread_executor.py @@ -106,9 +106,9 @@ def _submit( # 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 + # happy but 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. + # We should be able to remove this when we drop support for 3.8. if not TYPE_CHECKING: def submit(self, fn, *args, **kwargs): diff --git a/asgiref/sync.py b/asgiref/sync.py index 2a819a53..5406b7d3 100644 --- a/asgiref/sync.py +++ b/asgiref/sync.py @@ -57,7 +57,6 @@ def _restore_context(context: contextvars.Context) -> None: # inspect.iscoroutinefunction(), whilst also removing the _is_coroutine marker. # The latter is replaced with the inspect.markcoroutinefunction decorator. # 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. if hasattr(inspect, "markcoroutinefunction"): iscoroutinefunction = inspect.iscoroutinefunction @@ -70,22 +69,6 @@ def markcoroutinefunction(func: _F) -> _F: return func -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): - func = func.func - - return iscoroutinefunction(func) - - class ThreadSensitiveContext: """Async context manager to manage context for thread sensitive mode @@ -93,8 +76,8 @@ class ThreadSensitiveContext: thread sensitive mode. By default, a single thread pool executor is shared within a process. - In Python 3.7+, the ThreadSensitiveContext() context manager may be used to - specify a thread pool per context. + The ThreadSensitiveContext() context manager may be used to specify a + thread pool per context. This context manager is re-entrant, so only the outer-most call to ThreadSensitiveContext will set the context. @@ -157,10 +140,8 @@ def __init__( force_new_loop: bool = False, ): if not callable(awaitable) or ( - not _iscoroutinefunction_or_partial(awaitable) - and not _iscoroutinefunction_or_partial( - getattr(awaitable, "__call__", awaitable) - ) + not iscoroutinefunction(awaitable) + and not iscoroutinefunction(getattr(awaitable, "__call__", awaitable)) ): # Python does not have very reliable detection of async functions # (lots of false negatives) so this is just a warning. @@ -400,8 +381,8 @@ def __init__( ) -> None: if ( not callable(func) - or _iscoroutinefunction_or_partial(func) - or _iscoroutinefunction_or_partial(getattr(func, "__call__", func)) + or iscoroutinefunction(func) + or iscoroutinefunction(getattr(func, "__call__", func)) ): raise TypeError("sync_to_async can only be applied to sync functions.") self.func = func diff --git a/asgiref/typing.py b/asgiref/typing.py index 46cb1642..71c25ed8 100644 --- a/asgiref/typing.py +++ b/asgiref/typing.py @@ -5,17 +5,15 @@ Callable, Dict, Iterable, + Literal, Optional, + Protocol, Tuple, Type, + TypedDict, 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: diff --git a/setup.cfg b/setup.cfg index 680d706e..83a3ed7f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,7 +16,6 @@ classifiers = Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 @@ -28,7 +27,7 @@ project_urls = Changelog = https://github.com/django/asgiref/blob/master/CHANGELOG.txt [options] -python_requires = >=3.7 +python_requires = >=3.8 packages = find: include_package_data = true install_requires = diff --git a/setup.py b/setup.py index d6490095..6822ccc6 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,3 @@ -from setuptools import setup # type: ignore[import] +from setuptools import setup # type: ignore[import-untyped] setup() diff --git a/specs/asgi.rst b/specs/asgi.rst index 9e1be52c..a67626a0 100644 --- a/specs/asgi.rst +++ b/specs/asgi.rst @@ -294,20 +294,6 @@ Note that messages received by a server after the connection has been closed are not considered errors. In this case the ``send`` awaitable callable should act as a no-op. - -Extra Coroutines ----------------- - -Frameworks or applications may want to run extra coroutines in addition to the -coroutine launched for each application instance. Since there is no way to -parent these to the instance's coroutine in Python 3.7, applications should -ensure that all coroutines launched as part of running an application are terminated -either before or at the same time as the application's coroutine. - -Any coroutines that continue to run outside of this window have no guarantees -about their lifetime and may be killed at any time. - - Extensions ---------- diff --git a/tox.ini b/tox.ini index ec0a89af..e0e17111 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py{37,38,39,310,311}-{test,mypy} + py{38,39,310,311}-{test,mypy} qa [testenv]