summaryrefslogtreecommitdiff
path: root/django/utils
diff options
context:
space:
mode:
Diffstat (limited to 'django/utils')
-rw-r--r--django/utils/autoreload.py8
-rw-r--r--django/utils/http.py74
-rw-r--r--django/utils/module_loading.py5
-rw-r--r--django/utils/version.py2
4 files changed, 5 insertions, 84 deletions
diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py
index faa3252c71..3847252632 100644
--- a/django/utils/autoreload.py
+++ b/django/utils/autoreload.py
@@ -231,15 +231,11 @@ def get_child_arguments():
exe_entrypoint = py_script.with_suffix('.exe')
if exe_entrypoint.exists():
# Should be executed directly, ignoring sys.executable.
- # TODO: Remove str() when dropping support for PY37.
- # args parameter accepts path-like on Windows from Python 3.8.
- return [str(exe_entrypoint), *sys.argv[1:]]
+ return [exe_entrypoint, *sys.argv[1:]]
script_entrypoint = py_script.with_name('%s-script.py' % py_script.name)
if script_entrypoint.exists():
# Should be executed as usual.
- # TODO: Remove str() when dropping support for PY37.
- # args parameter accepts path-like on Windows from Python 3.8.
- return [*args, str(script_entrypoint), *sys.argv[1:]]
+ return [*args, script_entrypoint, *sys.argv[1:]]
raise RuntimeError('Script %s does not exist.' % py_script)
else:
args += sys.argv
diff --git a/django/utils/http.py b/django/utils/http.py
index 962716eb00..5397bb8190 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -7,7 +7,7 @@ from binascii import Error as BinasciiError
from email.utils import formatdate
from urllib.parse import (
ParseResult, SplitResult, _coerce_args, _splitnetloc, _splitparams,
- scheme_chars, unquote, urlencode as original_urlencode, uses_params,
+ scheme_chars, urlencode as original_urlencode, uses_params,
)
from django.utils.datastructures import MultiValueDict
@@ -343,78 +343,6 @@ def _url_has_allowed_host_and_scheme(url, allowed_hosts, require_https=False):
(not scheme or scheme in valid_schemes))
-# TODO: Remove when dropping support for PY37.
-def parse_qsl(
- qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8',
- errors='replace', max_num_fields=None,
-):
- """
- Return a list of key/value tuples parsed from query string.
-
- Backport of urllib.parse.parse_qsl() from Python 3.8.
- Copyright (C) 2020 Python Software Foundation (see LICENSE.python).
-
- ----
-
- Parse a query given as a string argument.
-
- Arguments:
-
- qs: percent-encoded query string to be parsed
-
- keep_blank_values: flag indicating whether blank values in
- percent-encoded queries should be treated as blank strings. A
- true value indicates that blanks should be retained as blank
- strings. The default false value indicates that blank values
- are to be ignored and treated as if they were not included.
-
- strict_parsing: flag indicating what to do with parsing errors. If false
- (the default), errors are silently ignored. If true, errors raise a
- ValueError exception.
-
- encoding and errors: specify how to decode percent-encoded sequences
- into Unicode characters, as accepted by the bytes.decode() method.
-
- max_num_fields: int. If set, then throws a ValueError if there are more
- than n fields read by parse_qsl().
-
- Returns a list, as G-d intended.
- """
- qs, _coerce_result = _coerce_args(qs)
-
- # If max_num_fields is defined then check that the number of fields is less
- # than max_num_fields. This prevents a memory exhaustion DOS attack via
- # post bodies with many fields.
- if max_num_fields is not None:
- num_fields = 1 + qs.count('&') + qs.count(';')
- if max_num_fields < num_fields:
- raise ValueError('Max number of fields exceeded')
-
- pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
- r = []
- for name_value in pairs:
- if not name_value and not strict_parsing:
- continue
- nv = name_value.split('=', 1)
- if len(nv) != 2:
- if strict_parsing:
- raise ValueError("bad query field: %r" % (name_value,))
- # Handle case of a control-name with no equal sign.
- if keep_blank_values:
- nv.append('')
- else:
- continue
- if len(nv[1]) or keep_blank_values:
- name = nv[0].replace('+', ' ')
- name = unquote(name, encoding=encoding, errors=errors)
- name = _coerce_result(name)
- value = nv[1].replace('+', ' ')
- value = unquote(value, encoding=encoding, errors=errors)
- value = _coerce_result(value)
- r.append((name, value))
- return r
-
-
def escape_leading_slashes(url):
"""
If redirecting to an absolute path (two leading slashes), a slash must be
diff --git a/django/utils/module_loading.py b/django/utils/module_loading.py
index df8e65098d..9f58c06856 100644
--- a/django/utils/module_loading.py
+++ b/django/utils/module_loading.py
@@ -72,10 +72,9 @@ def module_has_submodule(package, module_name):
full_module_name = package_name + '.' + module_name
try:
return importlib_find(full_module_name, package_path) is not None
- except (ModuleNotFoundError, AttributeError):
+ except ModuleNotFoundError:
# When module_name is an invalid dotted path, Python raises
- # ModuleNotFoundError. AttributeError is raised on PY36 (fixed in PY37)
- # if the penultimate part of the path is not a package.
+ # ModuleNotFoundError.
return False
diff --git a/django/utils/version.py b/django/utils/version.py
index 4b26586b36..68708df7aa 100644
--- a/django/utils/version.py
+++ b/django/utils/version.py
@@ -9,8 +9,6 @@ from distutils.version import LooseVersion
# or later". So that third-party apps can use these values, each constant
# should remain as long as the oldest supported Django version supports that
# Python version.
-PY36 = sys.version_info >= (3, 6)
-PY37 = sys.version_info >= (3, 7)
PY38 = sys.version_info >= (3, 8)
PY39 = sys.version_info >= (3, 9)