codekingpro/portable-devtools
114k
1# -*- coding: utf-8 -*-2"""Implementation of nested form-data encoding function(s)."""3from .._compat import basestring4from .._compat import urlencode as _urlencode5 6 7__all__ = ('urlencode',)8 9 10def urlencode(query, *args, **kwargs):11 """Handle nested form-data queries and serialize them appropriately.12 13 There are times when a website expects a nested form data query to be sent14 but, the standard library's urlencode function does not appropriately15 handle the nested structures. In that case, you need this function which16 will flatten the structure first and then properly encode it for you.17 18 When using this to send data in the body of a request, make sure you19 specify the appropriate Content-Type header for the request.20 21 .. code-block:: python22 23 import requests24 from requests_toolbelt.utils import formdata25 26 query = {27 'my_dict': {28 'foo': 'bar',29 'biz': 'baz",30 },31 'a': 'b',32 }33 34 resp = requests.get(url, params=formdata.urlencode(query))35 # or36 resp = requests.post(37 url,38 data=formdata.urlencode(query),39 headers={40 'Content-Type': 'application/x-www-form-urlencoded'41 },42 )43 44 Similarly, you can specify a list of nested tuples, e.g.,45 46 .. code-block:: python47 48 import requests49 from requests_toolbelt.utils import formdata50 51 query = [52 ('my_list', [53 ('foo', 'bar'),54 ('biz', 'baz'),55 ]),56 ('a', 'b'),57 ]58 59 resp = requests.get(url, params=formdata.urlencode(query))60 # or61 resp = requests.post(62 url,63 data=formdata.urlencode(query),64 headers={65 'Content-Type': 'application/x-www-form-urlencoded'66 },67 )68 69 For additional parameter and return information, see the official70 `urlencode`_ documentation.71 72 .. _urlencode:73 https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode74 """75 expand_classes = (dict, list, tuple)76 original_query_list = _to_kv_list(query)77 78 if not all(_is_two_tuple(i) for i in original_query_list):79 raise ValueError("Expected query to be able to be converted to a "80 "list comprised of length 2 tuples.")81 82 query_list = original_query_list83 while any(isinstance(v, expand_classes) for _, v in query_list):84 query_list = _expand_query_values(query_list)85 86 return _urlencode(query_list, *args, **kwargs)87 88 89def _to_kv_list(dict_or_list):90 if hasattr(dict_or_list, 'items'):91 return list(dict_or_list.items())92 return dict_or_list93 94 95def _is_two_tuple(item):96 return isinstance(item, (list, tuple)) and len(item) == 297 98 99def _expand_query_values(original_query_list):100 query_list = []101 for key, value in original_query_list:102 if isinstance(value, basestring):103 query_list.append((key, value))104 else:105 key_fmt = key + '[%s]'106 value_list = _to_kv_list(value)107 query_list.extend((key_fmt % k, v) for k, v in value_list)108 return query_list109 