Skip to content

Commit 99ce7ed

Browse files
authored
drop support for Python 3.8 (#5623)
2 parents e8b91cd + 1d610e4 commit 99ce7ed

File tree

12 files changed

+25
-42
lines changed

12 files changed

+25
-42
lines changed

.github/workflows/tests.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ jobs:
2020
- {python: '3.11'}
2121
- {python: '3.10'}
2222
- {python: '3.9'}
23-
- {python: '3.8'}
2423
- {name: PyPy, python: 'pypy-3.10', tox: pypy310}
2524
- {name: Minimum Versions, python: '3.12', tox: py-min}
2625
- {name: Development Versions, python: '3.9', tox: py-dev}

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Version 3.1.0
33

44
Unreleased
55

6+
- Drop support for Python 3.8. :pr:`5623`
67
- Provide a configuration option to control automatic option
78
responses. :pr:`5496`
89
- ``Flask.open_resource``/``open_instance_resource`` and

docs/async-await.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ method in views that inherit from the :class:`flask.views.View` class, as
2323
well as all the HTTP method handlers in views that inherit from the
2424
:class:`flask.views.MethodView` class.
2525

26-
.. admonition:: Using ``async`` on Windows on Python 3.8
27-
28-
Python 3.8 has a bug related to asyncio on Windows. If you encounter
29-
something like ``ValueError: set_wakeup_fd only works in main thread``,
30-
please upgrade to Python 3.9.
31-
3226
.. admonition:: Using ``async`` with greenlet
3327

3428
When using gevent or eventlet to serve an application or patch the

docs/extensiondev.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ ecosystem remain consistent and compatible.
294294
indicate minimum compatibility support. For example,
295295
``sqlalchemy>=1.4``.
296296
9. Indicate the versions of Python supported using ``python_requires=">=version"``.
297-
Flask itself supports Python >=3.8 as of April 2023, but this will update over time.
297+
Flask itself supports Python >=3.9 as of October 2024, and this will update
298+
over time.
298299

299300
.. _PyPI: https://pypi.org/search/?c=Framework+%3A%3A+Flask
300301
.. _Discord Chat: https://discord.gg/pallets

docs/installation.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Installation
55
Python Version
66
--------------
77

8-
We recommend using the latest version of Python. Flask supports Python 3.8 and newer.
8+
We recommend using the latest version of Python. Flask supports Python 3.9 and newer.
99

1010

1111
Dependencies

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ classifiers = [
1919
"Topic :: Software Development :: Libraries :: Application Frameworks",
2020
"Typing :: Typed",
2121
]
22-
requires-python = ">=3.8"
22+
requires-python = ">=3.9"
2323
dependencies = [
2424
"Werkzeug>=3.0.0",
2525
"Jinja2>=3.1.2",
@@ -78,7 +78,7 @@ source = ["flask", "tests"]
7878
source = ["src", "*/site-packages"]
7979

8080
[tool.mypy]
81-
python_version = "3.8"
81+
python_version = "3.9"
8282
files = ["src/flask", "tests/typing"]
8383
show_error_codes = true
8484
pretty = true
@@ -94,7 +94,7 @@ module = [
9494
ignore_missing_imports = true
9595

9696
[tool.pyright]
97-
pythonVersion = "3.8"
97+
pythonVersion = "3.9"
9898
include = ["src/flask", "tests/typing"]
9999
typeCheckingMode = "basic"
100100

src/flask/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,7 @@ def make_response(self, rv: ft.ResponseReturnValue) -> Response:
12451245

12461246
# extend existing headers with provided headers
12471247
if headers:
1248-
rv.headers.update(headers) # type: ignore[arg-type]
1248+
rv.headers.update(headers)
12491249

12501250
return rv
12511251

src/flask/config.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,20 @@ def from_prefixed_env(
150150
.. versionadded:: 2.1
151151
"""
152152
prefix = f"{prefix}_"
153-
len_prefix = len(prefix)
154153

155154
for key in sorted(os.environ):
156155
if not key.startswith(prefix):
157156
continue
158157

159158
value = os.environ[key]
159+
key = key.removeprefix(prefix)
160160

161161
try:
162162
value = loads(value)
163163
except Exception:
164164
# Keep the value as a string if loading failed.
165165
pass
166166

167-
# Change to key.removeprefix(prefix) on Python >= 3.9.
168-
key = key[len_prefix:]
169-
170167
if "__" not in key:
171168
# A non-nested key, set directly.
172169
self[key] = value

src/flask/helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import sys
66
import typing as t
77
from datetime import datetime
8-
from functools import lru_cache
8+
from functools import cache
99
from functools import update_wrapper
1010

1111
import werkzeug.utils
@@ -623,7 +623,7 @@ def get_root_path(import_name: str) -> str:
623623
return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return]
624624

625625

626-
@lru_cache(maxsize=None)
626+
@cache
627627
def _split_blueprint_path(name: str) -> list[str]:
628628
out: list[str] = [name]
629629

src/flask/sansio/scaffold.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -706,15 +706,6 @@ def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str:
706706
return view_func.__name__
707707

708708

709-
def _path_is_relative_to(path: pathlib.PurePath, base: str) -> bool:
710-
# Path.is_relative_to doesn't exist until Python 3.9
711-
try:
712-
path.relative_to(base)
713-
return True
714-
except ValueError:
715-
return False
716-
717-
718709
def _find_package_path(import_name: str) -> str:
719710
"""Find the path that contains the package or module."""
720711
root_mod_name, _, _ = import_name.partition(".")
@@ -745,7 +736,7 @@ def _find_package_path(import_name: str) -> str:
745736
search_location = next(
746737
location
747738
for location in root_spec.submodule_search_locations
748-
if _path_is_relative_to(package_path, location)
739+
if package_path.is_relative_to(location)
749740
)
750741
else:
751742
# Pick the first path.
@@ -777,7 +768,7 @@ def find_package(import_name: str) -> tuple[str | None, str]:
777768
py_prefix = os.path.abspath(sys.prefix)
778769

779770
# installed to the system
780-
if _path_is_relative_to(pathlib.PurePath(package_path), py_prefix):
771+
if pathlib.PurePath(package_path).is_relative_to(py_prefix):
781772
return py_prefix, package_path
782773

783774
site_parent, site_folder = os.path.split(package_path)

0 commit comments

Comments
 (0)