Skip to content

Commit 262ee8b

Browse files
committed
address code review
1 parent 5cb83bc commit 262ee8b

3 files changed

Lines changed: 37 additions & 7 deletions

File tree

‎Lib/test/test_urllib.py‎

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,19 +1258,41 @@ def test_unquote_with_unicode(self):
12581258
"using unquote(): %r != %r" % (expect, result))
12591259

12601260
def test_unquote_ascii_and_non_ascii_agree(self):
1261-
# ASCII input takes a fast path; a non-ASCII prefix forces the
1262-
# general path. Both must decode the escapes the same way.
1261+
# ASCII input takes a fast path; with a non-UTF-8 encoding, a
1262+
# non-ASCII prefix forces the general path. Both must decode the
1263+
# escapes the same way.
12631264
for given in ['%41%zz%', 'a%20b%2Fc%E2%82%AC', '%F3%B1', '%C3%BC+%2B']:
1264-
for encoding, errors in [('utf-8', 'replace'),
1265-
('latin-1', 'strict'),
1266-
('ascii', 'ignore')]:
1265+
for encoding, errors in [('latin-1', 'strict'),
1266+
('ascii', 'ignore'),
1267+
('cp1252', 'replace')]:
12671268
with self.subTest(given=given, encoding=encoding,
12681269
errors=errors):
12691270
expect = urllib.parse.unquote(given, encoding, errors)
12701271
result = urllib.parse.unquote('\u00e9' + given,
12711272
encoding, errors)
12721273
self.assertEqual(result, '\u00e9' + expect)
12731274

1275+
def test_unquote_non_ascii_utf8(self):
1276+
# Non-ASCII input decoded as UTF-8 takes a fast path that encodes
1277+
# the whole string at once. Literal characters must not combine
1278+
# with adjacent invalid escapes.
1279+
cases = [
1280+
('\u00e9%ff', '\u00e9\ufffd'),
1281+
('%C3\u00e9', '\ufffd\u00e9'),
1282+
('%F0%9F\U0001F600', '\ufffd\U0001F600'),
1283+
('\u6f22%20\u5b57%E2%82%AC', '\u6f22 \u5b57\u20ac'),
1284+
# Lone surrogates cannot be encoded and are passed through.
1285+
('\ud800%41', '\ud800A'),
1286+
]
1287+
for given, expect in cases:
1288+
with self.subTest(given=given):
1289+
self.assertEqual(urllib.parse.unquote(given), expect)
1290+
self.assertEqual(urllib.parse.unquote(given, 'utf8'), expect)
1291+
self.assertEqual(urllib.parse.unquote_plus('caf\u00e9+%2B'),
1292+
'caf\u00e9 +')
1293+
self.assertRaises(UnicodeDecodeError, urllib.parse.unquote,
1294+
'\u00e9%ff', errors='strict')
1295+
12741296
def test_unquoting_with_bytes_input(self):
12751297
# ASCII characters decoded to a string
12761298
given = b'blueberryjam'

‎Lib/urllib/parse.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,13 @@ def unquote(string, encoding='utf-8', errors='replace'):
855855
errors = 'replace'
856856
if string.isascii():
857857
return _unquote_impl(string).decode(encoding, errors)
858+
if encoding in ('utf-8', 'utf8'):
859+
try:
860+
data = string.encode('utf-8')
861+
except UnicodeEncodeError:
862+
pass # lone surrogates must be passed through verbatim
863+
else:
864+
return _unquote_impl(data).decode(encoding, errors)
858865
return ''.join(_generate_unquoted_parts(string, encoding, errors))
859866

860867

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Speed up :func:`urllib.parse.unquote` and :func:`urllib.parse.unquote_plus`
2-
by up to ~2x for ASCII input, which also makes :func:`urllib.parse.parse_qs`
3-
and :func:`urllib.parse.parse_qsl` faster. Patch by Brendan Fahy.
2+
by up to ~2x for ASCII input and for non-ASCII input decoded as UTF-8 (the
3+
default), which also makes :func:`urllib.parse.parse_qs` and
4+
:func:`urllib.parse.parse_qsl` faster. Patch by Brendan Fahy.

0 commit comments

Comments
 (0)