mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #13866: add *quote_via* argument to urlencode.
Patch by samwyse, completed by Arnon Yaari, and reviewed by Martin Panter.
This commit is contained in:
parent
1dbee9460e
commit
c17686f071
5 changed files with 47 additions and 18 deletions
|
@ -519,7 +519,8 @@ task isn't already covered by the URL parsing functions above.
|
||||||
Example: ``unquote_to_bytes('a%26%EF')`` yields ``b'a&\xef'``.
|
Example: ``unquote_to_bytes('a%26%EF')`` yields ``b'a&\xef'``.
|
||||||
|
|
||||||
|
|
||||||
.. function:: urlencode(query, doseq=False, safe='', encoding=None, errors=None)
|
.. function:: urlencode(query, doseq=False, safe='', encoding=None, \
|
||||||
|
errors=None, quote_via=quote_plus)
|
||||||
|
|
||||||
Convert a mapping object or a sequence of two-element tuples, which may
|
Convert a mapping object or a sequence of two-element tuples, which may
|
||||||
contain :class:`str` or :class:`bytes` objects, to a "percent-encoded"
|
contain :class:`str` or :class:`bytes` objects, to a "percent-encoded"
|
||||||
|
@ -528,8 +529,16 @@ task isn't already covered by the URL parsing functions above.
|
||||||
properly encoded to bytes, otherwise it would result in a :exc:`TypeError`.
|
properly encoded to bytes, otherwise it would result in a :exc:`TypeError`.
|
||||||
|
|
||||||
The resulting string is a series of ``key=value`` pairs separated by ``'&'``
|
The resulting string is a series of ``key=value`` pairs separated by ``'&'``
|
||||||
characters, where both *key* and *value* are quoted using :func:`quote_plus`
|
characters, where both *key* and *value* are quoted using the *quote_via*
|
||||||
above. When a sequence of two-element tuples is used as the *query*
|
function. By default, :func:`quote_plus` is used to quote the values, which
|
||||||
|
means spaces are quoted as a ``'+'`` character and '/' characters are
|
||||||
|
encoded as ``%2F``, which follows the standard for GET requests
|
||||||
|
(``application/x-www-form-urlencoded``). An alternate function that can be
|
||||||
|
passed as *quote_via* is :func:`quote`, which will encode spaces as ``%20``
|
||||||
|
and not encode '/' characters. For maximum control of what is quoted, use
|
||||||
|
``quote`` and specify a value for *safe*.
|
||||||
|
|
||||||
|
When a sequence of two-element tuples is used as the *query*
|
||||||
argument, the first element of each tuple is a key and the second is a
|
argument, the first element of each tuple is a key and the second is a
|
||||||
value. The value element in itself can be a sequence and in that case, if
|
value. The value element in itself can be a sequence and in that case, if
|
||||||
the optional parameter *doseq* is evaluates to *True*, individual
|
the optional parameter *doseq* is evaluates to *True*, individual
|
||||||
|
@ -538,7 +547,7 @@ task isn't already covered by the URL parsing functions above.
|
||||||
string will match the order of parameter tuples in the sequence.
|
string will match the order of parameter tuples in the sequence.
|
||||||
|
|
||||||
The *safe*, *encoding*, and *errors* parameters are passed down to
|
The *safe*, *encoding*, and *errors* parameters are passed down to
|
||||||
:func:`quote_plus` (the *encoding* and *errors* parameters are only passed
|
*quote_via* (the *encoding* and *errors* parameters are only passed
|
||||||
when a query element is a :class:`str`).
|
when a query element is a :class:`str`).
|
||||||
|
|
||||||
To reverse this encoding process, :func:`parse_qs` and :func:`parse_qsl` are
|
To reverse this encoding process, :func:`parse_qs` and :func:`parse_qsl` are
|
||||||
|
@ -550,6 +559,9 @@ task isn't already covered by the URL parsing functions above.
|
||||||
.. versionchanged:: 3.2
|
.. versionchanged:: 3.2
|
||||||
Query parameter supports bytes and string objects.
|
Query parameter supports bytes and string objects.
|
||||||
|
|
||||||
|
.. versionadded:: 3.5
|
||||||
|
*quote_via* parameter.
|
||||||
|
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
|
|
|
@ -622,6 +622,10 @@ urllib
|
||||||
sent. (Contributed by Matej Cepl in :issue:`19494` and Akshit Khurana in
|
sent. (Contributed by Matej Cepl in :issue:`19494` and Akshit Khurana in
|
||||||
:issue:`7159`.)
|
:issue:`7159`.)
|
||||||
|
|
||||||
|
* A new :func:`~urllib.parse.urlencode` parameter *quote_via* provides a way to
|
||||||
|
control the encoding of query parts if needed. (Contributed by Samwyse and
|
||||||
|
Arnon Yaari in :issue:`13866`.)
|
||||||
|
|
||||||
wsgiref
|
wsgiref
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -785,6 +785,16 @@ class UrlParseTestCase(unittest.TestCase):
|
||||||
result = urllib.parse.urlencode({'a': Trivial()}, True)
|
result = urllib.parse.urlencode({'a': Trivial()}, True)
|
||||||
self.assertEqual(result, 'a=trivial')
|
self.assertEqual(result, 'a=trivial')
|
||||||
|
|
||||||
|
def test_urlencode_quote_via(self):
|
||||||
|
result = urllib.parse.urlencode({'a': 'some value'})
|
||||||
|
self.assertEqual(result, "a=some+value")
|
||||||
|
result = urllib.parse.urlencode({'a': 'some value/another'},
|
||||||
|
quote_via=urllib.parse.quote)
|
||||||
|
self.assertEqual(result, "a=some%20value%2Fanother")
|
||||||
|
result = urllib.parse.urlencode({'a': 'some value/another'},
|
||||||
|
safe='/', quote_via=urllib.parse.quote)
|
||||||
|
self.assertEqual(result, "a=some%20value/another")
|
||||||
|
|
||||||
def test_quote_from_bytes(self):
|
def test_quote_from_bytes(self):
|
||||||
self.assertRaises(TypeError, urllib.parse.quote_from_bytes, 'foo')
|
self.assertRaises(TypeError, urllib.parse.quote_from_bytes, 'foo')
|
||||||
result = urllib.parse.quote_from_bytes(b'archaeological arcana')
|
result = urllib.parse.quote_from_bytes(b'archaeological arcana')
|
||||||
|
|
|
@ -750,7 +750,8 @@ def quote_from_bytes(bs, safe='/'):
|
||||||
_safe_quoters[safe] = quoter = Quoter(safe).__getitem__
|
_safe_quoters[safe] = quoter = Quoter(safe).__getitem__
|
||||||
return ''.join([quoter(char) for char in bs])
|
return ''.join([quoter(char) for char in bs])
|
||||||
|
|
||||||
def urlencode(query, doseq=False, safe='', encoding=None, errors=None):
|
def urlencode(query, doseq=False, safe='', encoding=None, errors=None,
|
||||||
|
quote_via=quote_plus):
|
||||||
"""Encode a dict or sequence of two-element tuples into a URL query string.
|
"""Encode a dict or sequence of two-element tuples into a URL query string.
|
||||||
|
|
||||||
If any values in the query arg are sequences and doseq is true, each
|
If any values in the query arg are sequences and doseq is true, each
|
||||||
|
@ -762,8 +763,8 @@ def urlencode(query, doseq=False, safe='', encoding=None, errors=None):
|
||||||
|
|
||||||
The components of a query arg may each be either a string or a bytes type.
|
The components of a query arg may each be either a string or a bytes type.
|
||||||
|
|
||||||
The safe, encoding, and errors parameters are passed down to quote_plus()
|
The safe, encoding, and errors parameters are passed down to the function
|
||||||
(encoding and errors only if a component is a str).
|
specified by quote_via (encoding and errors only if a component is a str).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if hasattr(query, "items"):
|
if hasattr(query, "items"):
|
||||||
|
@ -789,27 +790,27 @@ def urlencode(query, doseq=False, safe='', encoding=None, errors=None):
|
||||||
if not doseq:
|
if not doseq:
|
||||||
for k, v in query:
|
for k, v in query:
|
||||||
if isinstance(k, bytes):
|
if isinstance(k, bytes):
|
||||||
k = quote_plus(k, safe)
|
k = quote_via(k, safe)
|
||||||
else:
|
else:
|
||||||
k = quote_plus(str(k), safe, encoding, errors)
|
k = quote_via(str(k), safe, encoding, errors)
|
||||||
|
|
||||||
if isinstance(v, bytes):
|
if isinstance(v, bytes):
|
||||||
v = quote_plus(v, safe)
|
v = quote_via(v, safe)
|
||||||
else:
|
else:
|
||||||
v = quote_plus(str(v), safe, encoding, errors)
|
v = quote_via(str(v), safe, encoding, errors)
|
||||||
l.append(k + '=' + v)
|
l.append(k + '=' + v)
|
||||||
else:
|
else:
|
||||||
for k, v in query:
|
for k, v in query:
|
||||||
if isinstance(k, bytes):
|
if isinstance(k, bytes):
|
||||||
k = quote_plus(k, safe)
|
k = quote_via(k, safe)
|
||||||
else:
|
else:
|
||||||
k = quote_plus(str(k), safe, encoding, errors)
|
k = quote_via(str(k), safe, encoding, errors)
|
||||||
|
|
||||||
if isinstance(v, bytes):
|
if isinstance(v, bytes):
|
||||||
v = quote_plus(v, safe)
|
v = quote_via(v, safe)
|
||||||
l.append(k + '=' + v)
|
l.append(k + '=' + v)
|
||||||
elif isinstance(v, str):
|
elif isinstance(v, str):
|
||||||
v = quote_plus(v, safe, encoding, errors)
|
v = quote_via(v, safe, encoding, errors)
|
||||||
l.append(k + '=' + v)
|
l.append(k + '=' + v)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -817,15 +818,15 @@ def urlencode(query, doseq=False, safe='', encoding=None, errors=None):
|
||||||
x = len(v)
|
x = len(v)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# not a sequence
|
# not a sequence
|
||||||
v = quote_plus(str(v), safe, encoding, errors)
|
v = quote_via(str(v), safe, encoding, errors)
|
||||||
l.append(k + '=' + v)
|
l.append(k + '=' + v)
|
||||||
else:
|
else:
|
||||||
# loop over the sequence
|
# loop over the sequence
|
||||||
for elt in v:
|
for elt in v:
|
||||||
if isinstance(elt, bytes):
|
if isinstance(elt, bytes):
|
||||||
elt = quote_plus(elt, safe)
|
elt = quote_via(elt, safe)
|
||||||
else:
|
else:
|
||||||
elt = quote_plus(str(elt), safe, encoding, errors)
|
elt = quote_via(str(elt), safe, encoding, errors)
|
||||||
l.append(k + '=' + elt)
|
l.append(k + '=' + elt)
|
||||||
return '&'.join(l)
|
return '&'.join(l)
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #13866: *quote_via* argument added to urllib.parse.urlencode.
|
||||||
|
|
||||||
- Issue #20098: New mangle_from_ policy option for email, default True
|
- Issue #20098: New mangle_from_ policy option for email, default True
|
||||||
for compat32, but False for all other policies.
|
for compat32, but False for all other policies.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue