diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d6e88372..a1ec0ba4 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -28,10 +28,9 @@ jobs: - {python: '3.11'} - {python: '3.10'} - {python: '3.9'} - - {python: '3.8'} - {name: PyPy, python: 'pypy-3.10', tox: pypy310} - {name: Minimum Versions, python: '3.12', tox: py-min} - - {name: Development Versions, python: '3.8', tox: py-dev} + - {name: Development Versions, python: '3.9', tox: py-dev} steps: - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 diff --git a/docs/async-await.rst b/docs/async-await.rst index 06a29fcc..16b61945 100644 --- a/docs/async-await.rst +++ b/docs/async-await.rst @@ -23,12 +23,6 @@ method in views that inherit from the :class:`flask.views.View` class, as well as all the HTTP method handlers in views that inherit from the :class:`flask.views.MethodView` class. -.. admonition:: Using ``async`` on Windows on Python 3.8 - - Python 3.8 has a bug related to asyncio on Windows. If you encounter - something like ``ValueError: set_wakeup_fd only works in main thread``, - please upgrade to Python 3.9. - .. admonition:: Using ``async`` with greenlet When using gevent or eventlet to serve an application or patch the diff --git a/docs/extensiondev.rst b/docs/extensiondev.rst index c9dee5ff..3a783b53 100644 --- a/docs/extensiondev.rst +++ b/docs/extensiondev.rst @@ -294,7 +294,7 @@ ecosystem remain consistent and compatible. indicate minimum compatibility support. For example, ``sqlalchemy>=1.4``. 9. Indicate the versions of Python supported using ``python_requires=">=version"``. - Flask itself supports Python >=3.8 as of April 2023, but this will update over time. + Flask itself supports Python >=3.9 as of October 2024, but this will update over time. .. _PyPI: https://pypi.org/search/?c=Framework+%3A%3A+Flask .. _Discord Chat: https://discord.gg/pallets diff --git a/docs/installation.rst b/docs/installation.rst index aeb00ce1..90a314bf 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -5,7 +5,7 @@ Installation Python Version -------------- -We recommend using the latest version of Python. Flask supports Python 3.8 and newer. +We recommend using the latest version of Python. Flask supports Python 3.9 and newer. Dependencies diff --git a/examples/celery/pyproject.toml b/examples/celery/pyproject.toml index 25887ca2..7dc09882 100644 --- a/examples/celery/pyproject.toml +++ b/examples/celery/pyproject.toml @@ -3,7 +3,7 @@ name = "flask-example-celery" version = "1.0.0" description = "Example Flask application with Celery background tasks." readme = "README.md" -requires-python = ">=3.8" +requires-python = ">=3.9" dependencies = ["flask>=2.2.2", "celery[redis]>=5.2.7"] [build-system] diff --git a/pyproject.toml b/pyproject.toml index cddf28cd..660967af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ classifiers = [ "Topic :: Software Development :: Libraries :: Application Frameworks", "Typing :: Typed", ] -requires-python = ">=3.8" +requires-python = ">=3.9" dependencies = [ "Werkzeug>=3.0.0", "Jinja2>=3.1.2", @@ -78,7 +78,7 @@ source = ["flask", "tests"] source = ["src", "*/site-packages"] [tool.mypy] -python_version = "3.8" +python_version = "3.9" files = ["src/flask", "tests/typing"] show_error_codes = true pretty = true @@ -94,7 +94,7 @@ module = [ ignore_missing_imports = true [tool.pyright] -pythonVersion = "3.8" +pythonVersion = "3.9" include = ["src/flask", "tests"] typeCheckingMode = "basic" diff --git a/src/flask/helpers.py b/src/flask/helpers.py index f891eed1..022aefd9 100644 --- a/src/flask/helpers.py +++ b/src/flask/helpers.py @@ -5,7 +5,7 @@ import os import sys import typing as t from datetime import datetime -from functools import lru_cache +from functools import cache from functools import update_wrapper import werkzeug.utils @@ -623,7 +623,7 @@ def get_root_path(import_name: str) -> str: return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return] -@lru_cache(maxsize=None) +@cache def _split_blueprint_path(name: str) -> list[str]: out: list[str] = [name] diff --git a/src/flask/typing.py b/src/flask/typing.py index cf6d4ae6..e7234e96 100644 --- a/src/flask/typing.py +++ b/src/flask/typing.py @@ -12,7 +12,7 @@ ResponseValue = t.Union[ "Response", str, bytes, - t.List[t.Any], + list[t.Any], # Only dict is actually accepted, but Mapping allows for TypedDict. t.Mapping[str, t.Any], t.Iterator[str], @@ -21,21 +21,21 @@ ResponseValue = t.Union[ # the possible types for an individual HTTP header # This should be a Union, but mypy doesn't pass unless it's a TypeVar. -HeaderValue = t.Union[str, t.List[str], t.Tuple[str, ...]] +HeaderValue = t.Union[str, list[str], tuple[str, ...]] # the possible types for HTTP headers HeadersValue = t.Union[ "Headers", t.Mapping[str, HeaderValue], - t.Sequence[t.Tuple[str, HeaderValue]], + t.Sequence[tuple[str, HeaderValue]], ] # The possible types returned by a route function. ResponseReturnValue = t.Union[ ResponseValue, - t.Tuple[ResponseValue, HeadersValue], - t.Tuple[ResponseValue, int], - t.Tuple[ResponseValue, int, HeadersValue], + tuple[ResponseValue, HeadersValue], + tuple[ResponseValue, int], + tuple[ResponseValue, int, HeadersValue], "WSGIApplication", ] @@ -56,21 +56,21 @@ BeforeRequestCallable = t.Union[ t.Callable[[], t.Optional[ResponseReturnValue]], t.Callable[[], t.Awaitable[t.Optional[ResponseReturnValue]]], ] -ShellContextProcessorCallable = t.Callable[[], t.Dict[str, t.Any]] +ShellContextProcessorCallable = t.Callable[[], dict[str, t.Any]] TeardownCallable = t.Union[ t.Callable[[t.Optional[BaseException]], None], t.Callable[[t.Optional[BaseException]], t.Awaitable[None]], ] TemplateContextProcessorCallable = t.Union[ - t.Callable[[], t.Dict[str, t.Any]], - t.Callable[[], t.Awaitable[t.Dict[str, t.Any]]], + t.Callable[[], dict[str, t.Any]], + t.Callable[[], t.Awaitable[dict[str, t.Any]]], ] TemplateFilterCallable = t.Callable[..., t.Any] TemplateGlobalCallable = t.Callable[..., t.Any] TemplateTestCallable = t.Callable[..., bool] -URLDefaultCallable = t.Callable[[str, t.Dict[str, t.Any]], None] +URLDefaultCallable = t.Callable[[str, dict[str, t.Any]], None] URLValuePreprocessorCallable = t.Callable[ - [t.Optional[str], t.Optional[t.Dict[str, t.Any]]], None + [t.Optional[str], t.Optional[dict[str, t.Any]]], None ] # This should take Exception, but that either breaks typing the argument diff --git a/tox.ini b/tox.ini index 1217581c..95324e8e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] envlist = - py3{13,12,11,10,9,8} + py3{13,12,11,10,9} pypy310 py312-min - py38-dev + py39-dev style typing docs