[compat] Make parse_qs[l] match Py3.10 for Py>=2.6

* support only default separator '&', not r'[&;]', like 3.10+
* support max_num_fields, like 3.8+
This commit is contained in:
dirkf 2023-04-16 21:20:07 +01:00
parent 9bbe366275
commit dc990a61cc

View File

@ -2398,12 +2398,12 @@ try:
except ImportError:
import BaseHTTPServer as compat_http_server
# urllib.parse
try:
from urllib.parse import unquote_to_bytes as compat_urllib_parse_unquote_to_bytes
from urllib.parse import unquote as compat_urllib_parse_unquote
from urllib.parse import unquote_plus as compat_urllib_parse_unquote_plus
from urllib.parse import urlencode as compat_urllib_parse_urlencode
from urllib.parse import parse_qs as compat_parse_qs
except ImportError: # Python 2
_asciire = (compat_urllib_parse._asciire if hasattr(compat_urllib_parse, '_asciire')
else re.compile(r'([\x00-\x7f]+)'))
@ -2493,14 +2493,38 @@ except ImportError: # Python 2
return compat_urllib_parse._urlencode(encode_elem(query), doseq=doseq)
setattr(compat_urllib_parse, '_urlencode',
getattr(compat_urllib_parse, 'urlencode'))
for name, fix in (
('unquote_to_bytes', compat_urllib_parse_unquote_to_bytes),
('parse_unquote', compat_urllib_parse_unquote),
('unquote_plus', compat_urllib_parse_unquote_plus),
('urlencode', compat_urllib_parse_urlencode)):
setattr(compat_urllib_parse, name, fix)
finally:
try:
# arguments changed in 3.8 and 3.10
from urllib.parse import parse_qs as _parse_qs
_parse_qs('a=b', separator='&')
compat_parse_qs = _parse_qs
except (ImportError, TypeError): # Python 2, < 3.10
# HACK: The following is the correct parse_qs implementation from cpython 3's stdlib.
# Python 2's version is apparently totally broken
# Also use this implementation for Py < 3.10
# * support only default separator '&', not r'[&;]', like 3.10+
# * support max_num_fields, like 3.8+
def _parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
encoding='utf-8', errors='replace'):
qs, _coerce_result = qs, compat_str
pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
encoding='utf-8', errors='replace',
max_num_fields=None, separator='&'):
if not isinstance(separator, (compat_str, str)):
raise ValueError('Separator must be of type string or bytes')
# DoS protection, if anyone cares
if qs and max_num_fields is not None and qs.count(separator) >= max_num_fields:
raise ValueError('Too many fields')
_coerce_result = compat_str
r = []
for name_value in pairs:
for name_value in qs.split(separator):
if not name_value and not strict_parsing:
continue
nv = name_value.split('=', 1)
@ -2525,10 +2549,11 @@ except ImportError: # Python 2
return r
def compat_parse_qs(qs, keep_blank_values=False, strict_parsing=False,
encoding='utf-8', errors='replace'):
encoding='utf-8', errors='replace',
max_num_fields=None, separator='&'):
parsed_result = {}
pairs = _parse_qsl(qs, keep_blank_values, strict_parsing,
encoding=encoding, errors=errors)
encoding, errors, max_num_fields, separator)
for name, value in pairs:
if name in parsed_result:
parsed_result[name].append(value)
@ -2536,14 +2561,9 @@ except ImportError: # Python 2
parsed_result[name] = [value]
return parsed_result
setattr(compat_urllib_parse, '_urlencode',
getattr(compat_urllib_parse, 'urlencode'))
for name, fix in (
('unquote_to_bytes', compat_urllib_parse_unquote_to_bytes),
('parse_unquote', compat_urllib_parse_unquote),
('unquote_plus', compat_urllib_parse_unquote_plus),
('urlencode', compat_urllib_parse_urlencode),
('parse_qs', compat_parse_qs)):
('parse_qs', compat_parse_qs),
('parse_qsl', _parse_qsl)):
setattr(compat_urllib_parse, name, fix)
compat_urllib_parse_parse_qs = compat_parse_qs