Skip to content

Commit 3bbe22d

Browse files
authored
Fixed #34233 -- Dropped support for Python 3.8 and 3.9.
1 parent d547171 commit 3bbe22d

File tree

38 files changed

+51
-327
lines changed

38 files changed

+51
-327
lines changed

.github/workflows/schedule_tests.yml

-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ jobs:
1616
strategy:
1717
matrix:
1818
python-version:
19-
- '3.8'
20-
- '3.9'
2119
- '3.10'
2220
- '3.11'
2321
- '3.12-dev'

INSTALL

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Thanks for downloading Django.
22

3-
To install it, make sure you have Python 3.8 or greater installed. Then run
3+
To install it, make sure you have Python 3.10 or greater installed. Then run
44
this command from the command prompt:
55

66
python -m pip install .

django/contrib/auth/hashers.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
RANDOM_STRING_CHARS,
1515
constant_time_compare,
1616
get_random_string,
17-
md5,
1817
pbkdf2,
1918
)
2019
from django.utils.deprecation import RemovedInDjango51Warning
@@ -684,7 +683,7 @@ class MD5PasswordHasher(BasePasswordHasher):
684683

685684
def encode(self, password, salt):
686685
self._check_encode_args(password, salt)
687-
hash = md5((salt + password).encode()).hexdigest()
686+
hash = hashlib.md5((salt + password).encode()).hexdigest()
688687
return "%s$%s$%s" % (self.algorithm, salt, hash)
689688

690689
def decode(self, encoded):
@@ -799,7 +798,7 @@ def salt(self):
799798
def encode(self, password, salt):
800799
if salt != "":
801800
raise ValueError("salt must be empty.")
802-
return md5(password.encode()).hexdigest()
801+
return hashlib.md5(password.encode()).hexdigest()
803802

804803
def decode(self, encoded):
805804
return {

django/contrib/staticfiles/storage.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
import os
33
import posixpath
44
import re
5+
from hashlib import md5
56
from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit
67

78
from django.conf import STATICFILES_STORAGE_ALIAS, settings
89
from django.contrib.staticfiles.utils import check_settings, matches_patterns
910
from django.core.exceptions import ImproperlyConfigured
1011
from django.core.files.base import ContentFile
1112
from django.core.files.storage import FileSystemStorage, storages
12-
from django.utils.crypto import md5
1313
from django.utils.functional import LazyObject
1414

1515

django/core/cache/backends/filebased.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
import tempfile
77
import time
88
import zlib
9+
from hashlib import md5
910

1011
from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
1112
from django.core.files import locks
1213
from django.core.files.move import file_move_safe
13-
from django.utils.crypto import md5
1414

1515

1616
class FileBasedCache(BaseCache):

django/core/cache/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from django.utils.crypto import md5
1+
from hashlib import md5
22

33
TEMPLATE_FRAGMENT_KEY_TEMPLATE = "template.cache.%s.%s"
44

django/core/handlers/asgi.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33
import tempfile
44
import traceback
5+
from contextlib import aclosing
56

67
from asgiref.sync import ThreadSensitiveContext, sync_to_async
78

@@ -19,7 +20,6 @@
1920
parse_cookie,
2021
)
2122
from django.urls import set_script_prefix
22-
from django.utils.asyncio import aclosing
2323
from django.utils.functional import cached_property
2424

2525
logger = logging.getLogger("django.request")

django/core/validators.py

-10
Original file line numberDiff line numberDiff line change
@@ -275,16 +275,6 @@ def validate_ipv4_address(value):
275275
raise ValidationError(
276276
_("Enter a valid IPv4 address."), code="invalid", params={"value": value}
277277
)
278-
else:
279-
# Leading zeros are forbidden to avoid ambiguity with the octal
280-
# notation. This restriction is included in Python 3.9.5+.
281-
# TODO: Remove when dropping support for PY39.
282-
if any(octet != "0" and octet[0] == "0" for octet in value.split(".")):
283-
raise ValidationError(
284-
_("Enter a valid IPv4 address."),
285-
code="invalid",
286-
params={"value": value},
287-
)
288278

289279

290280
def validate_ipv6_address(value):

django/db/backends/base/base.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,17 @@
55
import threading
66
import time
77
import warnings
8+
import zoneinfo
89
from collections import deque
910
from contextlib import contextmanager
1011

11-
from django.db.backends.utils import debug_transaction
12-
13-
try:
14-
import zoneinfo
15-
except ImportError:
16-
from backports import zoneinfo
17-
1812
from django.conf import settings
1913
from django.core.exceptions import ImproperlyConfigured
2014
from django.db import DEFAULT_DB_ALIAS, DatabaseError, NotSupportedError
2115
from django.db.backends import utils
2216
from django.db.backends.base.validation import BaseDatabaseValidation
2317
from django.db.backends.signals import connection_created
18+
from django.db.backends.utils import debug_transaction
2419
from django.db.transaction import TransactionManagementError
2520
from django.db.utils import DatabaseErrorWrapper
2621
from django.utils.asyncio import async_unsafe

django/db/backends/sqlite3/_functions.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
import functools
55
import random
66
import statistics
7+
import zoneinfo
78
from datetime import timedelta
8-
from hashlib import sha1, sha224, sha256, sha384, sha512
9+
from hashlib import md5, sha1, sha224, sha256, sha384, sha512
910
from math import (
1011
acos,
1112
asin,
@@ -32,14 +33,8 @@
3233
typecast_timestamp,
3334
)
3435
from django.utils import timezone
35-
from django.utils.crypto import md5
3636
from django.utils.duration import duration_microseconds
3737

38-
try:
39-
import zoneinfo
40-
except ImportError:
41-
from backports import zoneinfo
42-
4338

4439
def register(connection):
4540
create_deterministic_function = functools.partial(

django/db/backends/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import logging
55
import time
66
from contextlib import contextmanager
7+
from hashlib import md5
78

89
from django.db import NotSupportedError
9-
from django.utils.crypto import md5
1010
from django.utils.dateparse import parse_time
1111

1212
logger = logging.getLogger("django.db.backends")

django/templatetags/tz.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1+
import zoneinfo
12
from datetime import datetime
23
from datetime import timezone as datetime_timezone
34
from datetime import tzinfo
45

5-
try:
6-
import zoneinfo
7-
except ImportError:
8-
from backports import zoneinfo
9-
106
from django.template import Library, Node, TemplateSyntaxError
117
from django.utils import timezone
128

django/test/runner.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import argparse
22
import ctypes
33
import faulthandler
4+
import hashlib
45
import io
56
import itertools
67
import logging
@@ -27,7 +28,6 @@
2728
from django.test.utils import setup_test_environment
2829
from django.test.utils import teardown_databases as _teardown_databases
2930
from django.test.utils import teardown_test_environment
30-
from django.utils.crypto import new_hash
3131
from django.utils.datastructures import OrderedSet
3232

3333
try:
@@ -580,7 +580,7 @@ class Shuffler:
580580

581581
@classmethod
582582
def _hash_text(cls, text):
583-
h = new_hash(cls.hash_algorithm, usedforsecurity=False)
583+
h = hashlib.new(cls.hash_algorithm, usedforsecurity=False)
584584
h.update(text.encode("utf-8"))
585585
return h.hexdigest()
586586

django/test/testcases.py

-27
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
)
5454
from django.utils.deprecation import RemovedInDjango51Warning
5555
from django.utils.functional import classproperty
56-
from django.utils.version import PY310
5756
from django.views.static import serve
5857

5958
logger = logging.getLogger("django.test")
@@ -795,32 +794,6 @@ def assertWarnsMessage(self, expected_warning, expected_message, *args, **kwargs
795794
**kwargs,
796795
)
797796

798-
# A similar method is available in Python 3.10+.
799-
if not PY310:
800-
801-
@contextmanager
802-
def assertNoLogs(self, logger, level=None):
803-
"""
804-
Assert no messages are logged on the logger, with at least the
805-
given level.
806-
"""
807-
if isinstance(level, int):
808-
level = logging.getLevelName(level)
809-
elif level is None:
810-
level = "INFO"
811-
try:
812-
with self.assertLogs(logger, level) as cm:
813-
yield
814-
except AssertionError as e:
815-
msg = e.args[0]
816-
expected_msg = (
817-
f"no logs of level {level} or higher triggered on {logger}"
818-
)
819-
if msg != expected_msg:
820-
raise e
821-
else:
822-
self.fail(f"Unexpected logs found: {cm.output!r}")
823-
824797
def assertFieldOutput(
825798
self,
826799
fieldclass,

django/utils/asyncio.py

-25
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,3 @@ def inner(*args, **kwargs):
3737
return decorator(func)
3838
else:
3939
return decorator
40-
41-
42-
try:
43-
from contextlib import aclosing
44-
except ImportError:
45-
# TODO: Remove when dropping support for PY39.
46-
from contextlib import AbstractAsyncContextManager
47-
48-
# Backport of contextlib.aclosing() from Python 3.10. Copyright (C) Python
49-
# Software Foundation (see LICENSE.python).
50-
class aclosing(AbstractAsyncContextManager):
51-
"""
52-
Async context manager for safely finalizing an asynchronously
53-
cleaned-up resource such as an async generator, calling its
54-
``aclose()`` method.
55-
"""
56-
57-
def __init__(self, thing):
58-
self.thing = thing
59-
60-
async def __aenter__(self):
61-
return self.thing
62-
63-
async def __aexit__(self, *exc_info):
64-
await self.thing.aclose()

django/utils/cache.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
"""
1717
import time
1818
from collections import defaultdict
19+
from hashlib import md5
1920

2021
from django.conf import settings
2122
from django.core.cache import caches
2223
from django.http import HttpResponse, HttpResponseNotModified
23-
from django.utils.crypto import md5
2424
from django.utils.http import http_date, parse_etags, parse_http_date_safe, quote_etag
2525
from django.utils.log import log_response
2626
from django.utils.regex_helper import _lazy_re_compile

django/utils/crypto.py

-17
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from django.conf import settings
99
from django.utils.encoding import force_bytes
10-
from django.utils.inspect import func_supports_parameter
1110

1211

1312
class InvalidAlgorithm(ValueError):
@@ -75,19 +74,3 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
7574
password = force_bytes(password)
7675
salt = force_bytes(salt)
7776
return hashlib.pbkdf2_hmac(digest().name, password, salt, iterations, dklen)
78-
79-
80-
# TODO: Remove when dropping support for PY38. inspect.signature() is used to
81-
# detect whether the usedforsecurity argument is available as this fix may also
82-
# have been applied by downstream package maintainers to other versions in
83-
# their repositories.
84-
if func_supports_parameter(hashlib.md5, "usedforsecurity"):
85-
md5 = hashlib.md5
86-
new_hash = hashlib.new
87-
else:
88-
89-
def md5(data=b"", *, usedforsecurity=True):
90-
return hashlib.md5(data)
91-
92-
def new_hash(hash_algorithm, *, usedforsecurity=True):
93-
return hashlib.new(hash_algorithm)

0 commit comments

Comments
 (0)