Skip to content

Commit 98462de

Browse files
Merge pull request #1421 from tim-schilling/version-updates
Drop support for Python 3.8, added support for Django 5.1
2 parents 64cdeb4 + e0d6723 commit 98462de

File tree

12 files changed

+54
-50
lines changed

12 files changed

+54
-50
lines changed

.github/workflows/test.yml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,15 @@ jobs:
1111
strategy:
1212
fail-fast: false
1313
matrix:
14-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13-dev']
15-
django-version: ['4.2', '5.0', 'main']
14+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
15+
django-version: ['4.2', '5.0', '5.1', 'main']
1616

1717
exclude:
18-
# Exclude py3.8 and py3.9 for Django main and 5.0
19-
- python-version: '3.8'
20-
django-version: '5.0'
18+
# Exclude py3.9 for Django main and 5+
2119
- python-version: '3.9'
2220
django-version: '5.0'
23-
- python-version: '3.8'
24-
django-version: 'main'
21+
- python-version: '3.9'
22+
django-version: '5.1'
2523
- python-version: '3.9'
2624
django-version: 'main'
2725

@@ -101,7 +99,7 @@ jobs:
10199
- name: Set up newest stable Python version
102100
uses: actions/setup-python@v5
103101
with:
104-
python-version: 3.11
102+
python-version: 3.13
105103
cache: 'pip'
106104
# Invalidate the cache when this file updates, as the dependencies' versions
107105
# are pinned in the step below
@@ -113,7 +111,7 @@ jobs:
113111
# Install this project in editable mode, so that its package metadata can be queried
114112
pip install -e .
115113
# Install the latest minor version of Django we support
116-
pip install Django==5.0
114+
pip install Django==5.1
117115
118116
- name: Check translation files are updated
119117
run: python -m simple_history.tests.generated_file_checks.check_translations

.pre-commit-config.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
22
repos:
33
- repo: https://github.com/PyCQA/bandit
4-
rev: 1.7.9
4+
rev: 1.7.10
55
hooks:
66
- id: bandit
77
exclude: /.*tests/
88

99
- repo: https://github.com/psf/black-pre-commit-mirror
10-
rev: 24.8.0
10+
rev: 24.10.0
1111
hooks:
1212
- id: black
1313
language_version: python3.9
@@ -25,7 +25,7 @@ repos:
2525
- id: isort
2626

2727
- repo: https://github.com/pre-commit/pre-commit-hooks
28-
rev: v4.6.0
28+
rev: v5.0.0
2929
hooks:
3030
- id: requirements-txt-fixer
3131
files: requirements/.*\.txt$
@@ -40,11 +40,11 @@ repos:
4040
- id: detect-private-key
4141

4242
- repo: https://github.com/tox-dev/pyproject-fmt
43-
rev: 2.2.3
43+
rev: v2.5.0
4444
hooks:
4545
- id: pyproject-fmt
4646
- repo: https://github.com/abravalheri/validate-pyproject
47-
rev: v0.19
47+
rev: v0.23
4848
hooks:
4949
- id: validate-pyproject
5050

@@ -56,7 +56,7 @@ repos:
5656
- "--strict"
5757

5858
- repo: https://github.com/asottile/pyupgrade
59-
rev: v3.17.0
59+
rev: v3.19.0
6060
hooks:
6161
- id: pyupgrade
62-
args: [--py38-plus]
62+
args: [--py39-plus]

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Unreleased
1010
- Fixed issue with deferred fields causing DoesNotExist error (gh-678)
1111
- Added HistoricOneToOneField (gh-1394)
1212
- Updated all djangoproject.com links to reference the stable version (gh-1420)
13+
- Dropped support for Python 3.8, which reached end-of-life on 2024-10-07 (gh-1421)
14+
- Added support for Django 5.1 (gh-1388)
1315

1416
3.7.0 (2024-05-29)
1517
------------------

README.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ This app supports the following combinations of Django and Python:
4545
========== ========================
4646
Django Python
4747
========== ========================
48-
4.2 3.8, 3.9, 3.10, 3.11, 3.12, 3.13-dev
49-
5.0 3.10, 3.11, 3.12, 3.13-dev
50-
main 3.10, 3.11, 3.12, 3.13-dev
48+
4.2 3.9, 3.10, 3.11, 3.12, 3.13
49+
5.0 3.10, 3.11, 3.12, 3.13
50+
5.1 3.10, 3.11, 3.12, 3.13
51+
main 3.10, 3.11, 3.12, 3.13
5152
========== ========================
5253

5354
Getting Help

docs/index.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ This app supports the following combinations of Django and Python:
4141
========== =======================
4242
Django Python
4343
========== =======================
44-
4.2 3.8, 3.9, 3.10, 3.11, 3.12, 3.13-dev
45-
5.0 3.10, 3.11, 3.12, 3.13-dev
46-
main 3.10, 3.11, 3.12, 3.13-dev
44+
4.2 3.9, 3.10, 3.11, 3.12, 3.13
45+
5.0 3.10, 3.11, 3.12, 3.13
46+
5.1 3.10, 3.11, 3.12, 3.13
47+
main 3.10, 3.11, 3.12, 3.13
4748
========== =======================
4849

4950
Contribute

pyproject.toml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ maintainers = [
1515
authors = [
1616
{ name = "Corey Bertram", email = "[email protected]" },
1717
]
18-
requires-python = ">=3.8"
18+
requires-python = ">=3.9"
1919
classifiers = [
2020
"Development Status :: 5 - Production/Stable",
2121
"Environment :: Web Environment",
@@ -26,13 +26,11 @@ classifiers = [
2626
"License :: OSI Approved :: BSD License",
2727
"Programming Language :: Python",
2828
"Programming Language :: Python :: 3 :: Only",
29-
"Programming Language :: Python :: 3.8",
3029
"Programming Language :: Python :: 3.9",
3130
"Programming Language :: Python :: 3.10",
3231
"Programming Language :: Python :: 3.11",
3332
"Programming Language :: Python :: 3.12",
34-
# DEV: uncomment this when the `pyproject-fmt` pre-commit hook stops removing it
35-
#"Programming Language :: Python :: 3.13",
33+
"Programming Language :: Python :: 3.13",
3634
]
3735
dynamic = [
3836
"readme",
@@ -83,12 +81,12 @@ fragments = [
8381
[tool.black]
8482
line-length = 88
8583
target-version = [
86-
"py38",
84+
"py39",
8785
]
8886

8987
[tool.isort]
9088
profile = "black"
91-
py_version = "38"
89+
py_version = "39"
9290

9391
[tool.coverage.run]
9492
parallel = true

simple_history/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from typing import Any, Sequence
1+
from collections.abc import Sequence
2+
from typing import Any
23

34
from django import http
45
from django.apps import apps as django_apps

simple_history/models.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
import importlib
33
import uuid
44
import warnings
5+
from collections.abc import Iterable, Sequence
56
from dataclasses import dataclass
67
from functools import partial
7-
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Sequence, Type, Union
8+
from typing import TYPE_CHECKING, Any, Union
89

910
import django
1011
from django.apps import apps
@@ -899,10 +900,14 @@ def related_manager_cls(self):
899900

900901
class HistoricRelationModelManager(related_model._default_manager.__class__):
901902
def get_queryset(self):
903+
cache_name = (
904+
# DEV: Remove this when support for Django 5.0 has been dropped
905+
self.field.remote_field.get_cache_name()
906+
if django.VERSION < (5, 1)
907+
else self.field.remote_field.cache_name
908+
)
902909
try:
903-
return self.instance._prefetched_objects_cache[
904-
self.field.remote_field.get_cache_name()
905-
]
910+
return self.instance._prefetched_objects_cache[cache_name]
906911
except (AttributeError, KeyError):
907912
history = getattr(
908913
self.instance, SIMPLE_HISTORY_REVERSE_ATTR_NAME, None
@@ -1088,7 +1093,7 @@ def _get_field_changes_for_diff(
10881093
old_history: "HistoricalChanges",
10891094
fields: Iterable[str],
10901095
foreign_keys_are_objs: bool,
1091-
) -> List["ModelChange"]:
1096+
) -> list["ModelChange"]:
10921097
"""Helper method for ``diff_against()``."""
10931098
changes = []
10941099

@@ -1129,7 +1134,7 @@ def _get_m2m_field_changes_for_diff(
11291134
old_history: "HistoricalChanges",
11301135
m2m_fields: Iterable[str],
11311136
foreign_keys_are_objs: bool,
1132-
) -> List["ModelChange"]:
1137+
) -> list["ModelChange"]:
11331138
"""Helper method for ``diff_against()``."""
11341139
changes = []
11351140

@@ -1198,7 +1203,7 @@ def get_value(obj, through_field):
11981203

11991204
@dataclass(frozen=True)
12001205
class DeletedObject:
1201-
model: Type[models.Model]
1206+
model: type[models.Model]
12021207
pk: Any
12031208

12041209
def __str__(self):
@@ -1223,7 +1228,7 @@ def __str__(self):
12231228
# The PK of the through model's related objects.
12241229
#
12251230
# - Any of the other possible values of a model field.
1226-
ModelChangeValue = Union[Any, DeletedObject, List[Dict[str, Union[Any, DeletedObject]]]]
1231+
ModelChangeValue = Union[Any, DeletedObject, list[dict[str, Union[Any, DeletedObject]]]]
12271232

12281233

12291234
@dataclass(frozen=True)

simple_history/template_utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import dataclasses
22
from os.path import commonprefix
3-
from typing import Any, Dict, Final, List, Tuple, Type, Union
3+
from typing import Any, Final, Union
44

55
from django.db.models import ManyToManyField, Model
66
from django.utils.html import conditional_escape
@@ -40,7 +40,7 @@ class HistoricalRecordContextHelper:
4040

4141
def __init__(
4242
self,
43-
model: Type[Model],
43+
model: type[Model],
4444
historical_record: HistoricalChanges,
4545
*,
4646
max_displayed_delta_change_chars=DEFAULT_MAX_DISPLAYED_DELTA_CHANGE_CHARS,
@@ -50,7 +50,7 @@ def __init__(
5050

5151
self.max_displayed_delta_change_chars = max_displayed_delta_change_chars
5252

53-
def context_for_delta_changes(self, delta: ModelDelta) -> List[Dict[str, Any]]:
53+
def context_for_delta_changes(self, delta: ModelDelta) -> list[dict[str, Any]]:
5454
"""
5555
Return the template context for ``delta.changes``.
5656
By default, this is a list of dicts with the keys ``"field"``,
@@ -119,7 +119,7 @@ def prepare_delta_change_value(
119119

120120
def stringify_delta_change_values(
121121
self, change: ModelChange, old: Any, new: Any
122-
) -> Tuple[SafeString, SafeString]:
122+
) -> tuple[SafeString, SafeString]:
123123
"""
124124
Called by ``format_delta_change()`` after ``old`` and ``new`` have been
125125
prepared by ``prepare_delta_change_value()``.
@@ -196,7 +196,7 @@ def __init__(
196196
)
197197
assert self.min_diff_len >= 0 # nosec
198198

199-
def common_shorten_repr(self, *args: Any) -> Tuple[str, ...]:
199+
def common_shorten_repr(self, *args: Any) -> tuple[str, ...]:
200200
"""
201201
Returns ``args`` with each element converted into a string representation.
202202
If any of the strings are longer than ``self.max_length``, they're all shortened

simple_history/tests/tests/test_template_utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import datetime
2-
from typing import Tuple
32

43
from django.test import TestCase
54
from django.utils.dateparse import parse_datetime
@@ -225,7 +224,7 @@ def test_context_dict(
225224
)
226225

227226
def test__context_for_delta_changes__preserves_html_safe_strings(self):
228-
def get_context_dict_old_and_new(old_value, new_value) -> Tuple[str, str]:
227+
def get_context_dict_old_and_new(old_value, new_value) -> tuple[str, str]:
229228
# The field doesn't really matter, as long as it exists on the model
230229
# passed to `HistoricalRecordContextHelper`
231230
change = ModelChange("question", old_value, new_value)

0 commit comments

Comments
 (0)