Fixed #28679 -- Fixed urlencode()'s handling of bytes.

Regression in fee42fd99e.

Thanks Claude Paroz, Jon Dufresne, and Tim Graham for the guidance.
This commit is contained in:
François Freitag 2017-10-09 13:20:01 -07:00 committed by Tim Graham
parent 4d60261b2a
commit 41be85862d
2 changed files with 35 additions and 5 deletions

View File

@ -88,11 +88,24 @@ def urlencode(query, doseq=False):
query = query.lists() query = query.lists()
elif hasattr(query, 'items'): elif hasattr(query, 'items'):
query = query.items() query = query.items()
return original_urlencode( query_params = []
[(k, [str(i) for i in v] if isinstance(v, (list, tuple)) else str(v)) for key, value in query:
for k, v in query], if isinstance(value, (str, bytes)):
doseq query_val = value
) else:
try:
iter(value)
except TypeError:
query_val = value
else:
# Consume generators and iterators, even when doseq=True, to
# work around https://bugs.python.org/issue31706.
query_val = [
item if isinstance(item, bytes) else str(item)
for item in value
]
query_params.append((key, query_val))
return original_urlencode(query_params, doseq)
def cookie_date(epoch_seconds=None): def cookie_date(epoch_seconds=None):

View File

@ -47,6 +47,23 @@ class URLEncodeTests(unittest.TestCase):
'position=Developer&name=Adrian&name=Simon', 'position=Developer&name=Adrian&name=Simon',
]) ])
def test_dict_with_bytes_values(self):
self.assertEqual(urlencode({'a': b'abc'}, doseq=True), 'a=abc')
def test_dict_with_sequence_of_bytes(self):
self.assertEqual(urlencode({'a': [b'spam', b'eggs', b'bacon']}, doseq=True), 'a=spam&a=eggs&a=bacon')
def test_dict_with_bytearray(self):
self.assertEqual(urlencode({'a': bytearray(range(2))}, doseq=True), 'a=0&a=1')
self.assertEqual(urlencode({'a': bytearray(range(2))}, doseq=False), 'a=%5B%270%27%2C+%271%27%5D')
def test_generator(self):
def gen():
yield from range(2)
self.assertEqual(urlencode({'a': gen()}, doseq=True), 'a=0&a=1')
self.assertEqual(urlencode({'a': gen()}, doseq=False), 'a=%5B%270%27%2C+%271%27%5D')
class Base36IntTests(SimpleTestCase): class Base36IntTests(SimpleTestCase):
def test_roundtrip(self): def test_roundtrip(self):