Skip to content

Commit

Permalink
Fixed #34233 -- Dropped support for Python 3.8 and 3.9.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixxm authored Jan 18, 2023
1 parent d547171 commit 3bbe22d
Show file tree
Hide file tree
Showing 38 changed files with 51 additions and 327 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/schedule_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ jobs:
strategy:
matrix:
python-version:
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12-dev'
Expand Down
2 changes: 1 addition & 1 deletion INSTALL
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Thanks for downloading Django.

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

python -m pip install .
Expand Down
5 changes: 2 additions & 3 deletions django/contrib/auth/hashers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
RANDOM_STRING_CHARS,
constant_time_compare,
get_random_string,
md5,
pbkdf2,
)
from django.utils.deprecation import RemovedInDjango51Warning
Expand Down Expand Up @@ -684,7 +683,7 @@ class MD5PasswordHasher(BasePasswordHasher):

def encode(self, password, salt):
self._check_encode_args(password, salt)
hash = md5((salt + password).encode()).hexdigest()
hash = hashlib.md5((salt + password).encode()).hexdigest()
return "%s$%s$%s" % (self.algorithm, salt, hash)

def decode(self, encoded):
Expand Down Expand Up @@ -799,7 +798,7 @@ def salt(self):
def encode(self, password, salt):
if salt != "":
raise ValueError("salt must be empty.")
return md5(password.encode()).hexdigest()
return hashlib.md5(password.encode()).hexdigest()

def decode(self, encoded):
return {
Expand Down
2 changes: 1 addition & 1 deletion django/contrib/staticfiles/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import os
import posixpath
import re
from hashlib import md5
from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit

from django.conf import STATICFILES_STORAGE_ALIAS, settings
from django.contrib.staticfiles.utils import check_settings, matches_patterns
from django.core.exceptions import ImproperlyConfigured
from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage, storages
from django.utils.crypto import md5
from django.utils.functional import LazyObject


Expand Down
2 changes: 1 addition & 1 deletion django/core/cache/backends/filebased.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import tempfile
import time
import zlib
from hashlib import md5

from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
from django.core.files import locks
from django.core.files.move import file_move_safe
from django.utils.crypto import md5


class FileBasedCache(BaseCache):
Expand Down
2 changes: 1 addition & 1 deletion django/core/cache/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.utils.crypto import md5
from hashlib import md5

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

Expand Down
2 changes: 1 addition & 1 deletion django/core/handlers/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys
import tempfile
import traceback
from contextlib import aclosing

from asgiref.sync import ThreadSensitiveContext, sync_to_async

Expand All @@ -19,7 +20,6 @@
parse_cookie,
)
from django.urls import set_script_prefix
from django.utils.asyncio import aclosing
from django.utils.functional import cached_property

logger = logging.getLogger("django.request")
Expand Down
10 changes: 0 additions & 10 deletions django/core/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,16 +275,6 @@ def validate_ipv4_address(value):
raise ValidationError(
_("Enter a valid IPv4 address."), code="invalid", params={"value": value}
)
else:
# Leading zeros are forbidden to avoid ambiguity with the octal
# notation. This restriction is included in Python 3.9.5+.
# TODO: Remove when dropping support for PY39.
if any(octet != "0" and octet[0] == "0" for octet in value.split(".")):
raise ValidationError(
_("Enter a valid IPv4 address."),
code="invalid",
params={"value": value},
)


def validate_ipv6_address(value):
Expand Down
9 changes: 2 additions & 7 deletions django/db/backends/base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,17 @@
import threading
import time
import warnings
import zoneinfo
from collections import deque
from contextlib import contextmanager

from django.db.backends.utils import debug_transaction

try:
import zoneinfo
except ImportError:
from backports import zoneinfo

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db import DEFAULT_DB_ALIAS, DatabaseError, NotSupportedError
from django.db.backends import utils
from django.db.backends.base.validation import BaseDatabaseValidation
from django.db.backends.signals import connection_created
from django.db.backends.utils import debug_transaction
from django.db.transaction import TransactionManagementError
from django.db.utils import DatabaseErrorWrapper
from django.utils.asyncio import async_unsafe
Expand Down
9 changes: 2 additions & 7 deletions django/db/backends/sqlite3/_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import functools
import random
import statistics
import zoneinfo
from datetime import timedelta
from hashlib import sha1, sha224, sha256, sha384, sha512
from hashlib import md5, sha1, sha224, sha256, sha384, sha512
from math import (
acos,
asin,
Expand All @@ -32,14 +33,8 @@
typecast_timestamp,
)
from django.utils import timezone
from django.utils.crypto import md5
from django.utils.duration import duration_microseconds

try:
import zoneinfo
except ImportError:
from backports import zoneinfo


def register(connection):
create_deterministic_function = functools.partial(
Expand Down
2 changes: 1 addition & 1 deletion django/db/backends/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import logging
import time
from contextlib import contextmanager
from hashlib import md5

from django.db import NotSupportedError
from django.utils.crypto import md5
from django.utils.dateparse import parse_time

logger = logging.getLogger("django.db.backends")
Expand Down
6 changes: 1 addition & 5 deletions django/templatetags/tz.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import zoneinfo
from datetime import datetime
from datetime import timezone as datetime_timezone
from datetime import tzinfo

try:
import zoneinfo
except ImportError:
from backports import zoneinfo

from django.template import Library, Node, TemplateSyntaxError
from django.utils import timezone

Expand Down
4 changes: 2 additions & 2 deletions django/test/runner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
import ctypes
import faulthandler
import hashlib
import io
import itertools
import logging
Expand All @@ -27,7 +28,6 @@
from django.test.utils import setup_test_environment
from django.test.utils import teardown_databases as _teardown_databases
from django.test.utils import teardown_test_environment
from django.utils.crypto import new_hash
from django.utils.datastructures import OrderedSet

try:
Expand Down Expand Up @@ -580,7 +580,7 @@ class Shuffler:

@classmethod
def _hash_text(cls, text):
h = new_hash(cls.hash_algorithm, usedforsecurity=False)
h = hashlib.new(cls.hash_algorithm, usedforsecurity=False)
h.update(text.encode("utf-8"))
return h.hexdigest()

Expand Down
27 changes: 0 additions & 27 deletions django/test/testcases.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
)
from django.utils.deprecation import RemovedInDjango51Warning
from django.utils.functional import classproperty
from django.utils.version import PY310
from django.views.static import serve

logger = logging.getLogger("django.test")
Expand Down Expand Up @@ -795,32 +794,6 @@ def assertWarnsMessage(self, expected_warning, expected_message, *args, **kwargs
**kwargs,
)

# A similar method is available in Python 3.10+.
if not PY310:

@contextmanager
def assertNoLogs(self, logger, level=None):
"""
Assert no messages are logged on the logger, with at least the
given level.
"""
if isinstance(level, int):
level = logging.getLevelName(level)
elif level is None:
level = "INFO"
try:
with self.assertLogs(logger, level) as cm:
yield
except AssertionError as e:
msg = e.args[0]
expected_msg = (
f"no logs of level {level} or higher triggered on {logger}"
)
if msg != expected_msg:
raise e
else:
self.fail(f"Unexpected logs found: {cm.output!r}")

def assertFieldOutput(
self,
fieldclass,
Expand Down
25 changes: 0 additions & 25 deletions django/utils/asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,3 @@ def inner(*args, **kwargs):
return decorator(func)
else:
return decorator


try:
from contextlib import aclosing
except ImportError:
# TODO: Remove when dropping support for PY39.
from contextlib import AbstractAsyncContextManager

# Backport of contextlib.aclosing() from Python 3.10. Copyright (C) Python
# Software Foundation (see LICENSE.python).
class aclosing(AbstractAsyncContextManager):
"""
Async context manager for safely finalizing an asynchronously
cleaned-up resource such as an async generator, calling its
``aclose()`` method.
"""

def __init__(self, thing):
self.thing = thing

async def __aenter__(self):
return self.thing

async def __aexit__(self, *exc_info):
await self.thing.aclose()
2 changes: 1 addition & 1 deletion django/utils/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
"""
import time
from collections import defaultdict
from hashlib import md5

from django.conf import settings
from django.core.cache import caches
from django.http import HttpResponse, HttpResponseNotModified
from django.utils.crypto import md5
from django.utils.http import http_date, parse_etags, parse_http_date_safe, quote_etag
from django.utils.log import log_response
from django.utils.regex_helper import _lazy_re_compile
Expand Down
17 changes: 0 additions & 17 deletions django/utils/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from django.conf import settings
from django.utils.encoding import force_bytes
from django.utils.inspect import func_supports_parameter


class InvalidAlgorithm(ValueError):
Expand Down Expand Up @@ -75,19 +74,3 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
password = force_bytes(password)
salt = force_bytes(salt)
return hashlib.pbkdf2_hmac(digest().name, password, salt, iterations, dklen)


# TODO: Remove when dropping support for PY38. inspect.signature() is used to
# detect whether the usedforsecurity argument is available as this fix may also
# have been applied by downstream package maintainers to other versions in
# their repositories.
if func_supports_parameter(hashlib.md5, "usedforsecurity"):
md5 = hashlib.md5
new_hash = hashlib.new
else:

def md5(data=b"", *, usedforsecurity=True):
return hashlib.md5(data)

def new_hash(hash_algorithm, *, usedforsecurity=True):
return hashlib.new(hash_algorithm)
Loading

0 comments on commit 3bbe22d

Please sign in to comment.