diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f3605a420..8b3c6301d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] services: mariadb: @@ -91,11 +91,9 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] database: [postgresql, postgis, psycopg3] exclude: - - python-version: '3.9' - database: psycopg3 - python-version: '3.13' database: postgis - python-version: '3.13' @@ -192,7 +190,7 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@v5 @@ -252,7 +250,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: - python-version: 3.9 + python-version: '3.10' - name: Get pip cache dir id: pip-cache diff --git a/debug_toolbar/_stubs.py b/debug_toolbar/_stubs.py index dee6280d0..07217f39d 100644 --- a/debug_toolbar/_stubs.py +++ b/debug_toolbar/_stubs.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, NamedTuple, Optional, Protocol +from typing import Any, NamedTuple, Protocol from django import template as dj_template from django.http import HttpRequest, HttpResponse @@ -15,7 +15,7 @@ class InspectStack(NamedTuple): index: int -TidyStackTrace = list[tuple[str, int, str, str, Optional[Any]]] +TidyStackTrace = list[tuple[str, int, str, str, Any | None]] class RenderContext(dj_template.context.RenderContext): diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py index 22d345a3f..862a38f9e 100644 --- a/debug_toolbar/middleware.py +++ b/debug_toolbar/middleware.py @@ -4,8 +4,8 @@ import re import socket +from collections.abc import Callable from functools import cache -from typing import Callable from asgiref.sync import ( async_to_sync, diff --git a/debug_toolbar/toolbar.py b/debug_toolbar/toolbar.py index 929ce7b70..ec0472790 100644 --- a/debug_toolbar/toolbar.py +++ b/debug_toolbar/toolbar.py @@ -7,8 +7,8 @@ import logging import re import uuid +from collections.abc import Callable from functools import cache -from typing import Callable from django.apps import apps from django.conf import settings diff --git a/docs/changes.rst b/docs/changes.rst index 705611c82..4cfa9e7ca 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -11,6 +11,7 @@ Pending resources. * Show the cache backend alias and cache backend class name instead of the cache instance in the cache panel. +* Dropped support for the Python 3.9, it has reached its end of life date. 6.1.0 (2025-10-30) ------------------ diff --git a/pyproject.toml b/pyproject.toml index 28e921337..53bc9bcc5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ license = { text = "BSD-3-Clause" } authors = [ { name = "Rob Hudson" }, ] -requires-python = ">=3.9" +requires-python = ">=3.10" classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", @@ -25,7 +25,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -57,7 +56,7 @@ packages = [ path = "debug_toolbar/__init__.py" [tool.ruff] -target-version = "py39" +target-version = "py310" fix = true show-fixes = true diff --git a/tests/base.py b/tests/base.py index c18d3d1ed..152bc32e1 100644 --- a/tests/base.py +++ b/tests/base.py @@ -1,5 +1,4 @@ import contextvars -from typing import Optional import html5lib from asgiref.local import Local @@ -70,7 +69,7 @@ class BaseMixin: client_class = ToolbarTestClient async_client_class = AsyncToolbarTestClient - panel: Optional[Panel] = None + panel: Panel | None = None panel_id = None def setUp(self): diff --git a/tox.ini b/tox.ini index c885f87a1..e7058e0fd 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,6 @@ isolated_build = true envlist = docs packaging - py{39,310,311,312}-dj{42}-{sqlite,postgresql,postgis,mysql} py{310,311}-dj{42,51,52}-{sqlite,postgresql,psycopg3,postgis,mysql} py{312}-dj{42,51,52,60}-{sqlite,postgresql,psycopg3,postgis,mysql} py{313}-dj{51,52,60,main}-{sqlite,psycopg3,postgis3,mysql} @@ -55,28 +54,28 @@ pip_pre = True commands = python -b -W always -m coverage run -m django test -v2 {posargs:tests} -[testenv:py{39,310,311,312,313,314}-dj{42,51,52,60,main}-{postgresql,psycopg3}] +[testenv:py{310,311,312,313,314}-dj{42,51,52,60,main}-{postgresql,psycopg3}] setenv = {[testenv]setenv} DB_BACKEND = postgresql DB_PORT = {env:DB_PORT:5432} -[testenv:py{39,310,311,312,313,314}-dj{42,51,52,60,main}-{postgis,postgis3}] +[testenv:py{310,311,312,313,314}-dj{42,51,52,60,main}-{postgis,postgis3}] setenv = {[testenv]setenv} DB_BACKEND = postgis DB_PORT = {env:DB_PORT:5432} -[testenv:py{39,310,311,312,313,314}-dj{42,51,52,60,main}-mysql] +[testenv:py{310,311,312,313,314}-dj{42,51,52,60,main}-mysql] setenv = {[testenv]setenv} DB_BACKEND = mysql DB_PORT = {env:DB_PORT:3306} -[testenv:py{39,310,311,312,313,314}-dj{42,51,52,60,main}-sqlite] +[testenv:py{310,311,312,313,314}-dj{42,51,52,60,main}-sqlite] setenv = {[testenv]setenv} DB_BACKEND = sqlite3 @@ -101,7 +100,6 @@ skip_install = true [gh-actions] python = - 3.9: py39 3.10: py310 3.11: py311 3.12: py312