Michael Merickel
2018-10-15 2b024920847481592b1a13d4006d2a9fa8881d72
commit | author | age
0c1c39 1 from pyramid.compat import (
CM 2     text_type,
3     binary_type,
4     is_nonstr_iter,
5     url_quote as _url_quote,
e967a9 6     url_quote_plus as _quote_plus,
0c1c39 7     )
8e606d 8
22f0eb 9 def url_quote(val, safe=''): # bw compat api
MM 10     cls = val.__class__
11     if cls is text_type:
12         val = val.encode('utf-8')
13     elif cls is not binary_type:
14         val = str(val).encode('utf-8')
15     return _url_quote(val, safe=safe)
eb9fbf 16
804232 17 # bw compat api (dnr)
D 18 def quote_plus(val, safe=''):
19     cls = val.__class__
20     if cls is text_type:
21         val = val.encode('utf-8')
22     elif cls is not binary_type:
23         val = str(val).encode('utf-8')
24     return _quote_plus(val, safe=safe)
25
26 def urlencode(query, doseq=True, quote_via=quote_plus):
eb9fbf 27     """
6f43b6 28     An alternate implementation of Python's stdlib
MM 29     :func:`urllib.parse.urlencode` function which accepts unicode keys and
30     values within the ``query`` dict/sequence; all Unicode keys and values are
31     first converted to UTF-8 before being used to compose the query string.
eb9fbf 32
CM 33     The value of ``query`` must be a sequence of two-tuples
34     representing key/value pairs *or* an object (often a dictionary)
35     with an ``.items()`` method that returns a sequence of two-tuples
36     representing key/value pairs.
37
38     For minimal calling convention backwards compatibility, this
39     version of urlencode accepts *but ignores* a second argument
40     conventionally named ``doseq``.  The Python stdlib version behaves
41     differently when ``doseq`` is False and when a sequence is
42     presented as one of the values.  This version always behaves in
43     the ``doseq=True`` mode, no matter what the value of the second
44     argument.
45
6f43b6 46     Both the key and value are encoded using the ``quote_via`` function which
MM 47     by default is using a similar algorithm to :func:`urllib.parse.quote_plus`
48     which converts spaces into '+' characters and '/' into '%2F'.
af5fa0 49
MM 50     .. versionchanged:: 1.5
51        In a key/value pair, if the value is ``None`` then it will be
52        dropped from the resulting output.
6f43b6 53
MM 54     .. versionchanged:: 1.9
55        Added the ``quote_via`` argument to allow alternate quoting algorithms
56        to be used.
57
eb9fbf 58     """
CM 59     try:
60         # presumed to be a dictionary
61         query = query.items()
62     except AttributeError:
63         pass
64
65     result = ''
66     prefix = ''
67
68     for (k, v) in query:
804232 69         k = quote_via(k)
a84e17 70
8e606d 71         if is_nonstr_iter(v):
eb9fbf 72             for x in v:
804232 73                 x = quote_via(x)
eb9fbf 74                 result += '%s%s=%s' % (prefix, k, x)
CM 75                 prefix = '&'
af5fa0 76         elif v is None:
15afe5 77             result += '%s%s=' % (prefix, k)
eb9fbf 78         else:
804232 79             v = quote_via(v)
eb9fbf 80             result += '%s%s=%s' % (prefix, k, v)
a84e17 81
eb9fbf 82         prefix = '&'
CM 83
84     return result