multidimensional_urlencode/urlencoder.py (32 lines of code) (raw):

try: from urllib.parse import urlencode as urllib_urlencode except ImportError: from urllib import urlencode as urllib_urlencode from collections import OrderedDict def flatten(d): """Return a dict as a list of lists. >>> flatten({"a": "b"}) [['a', 'b']] >>> flatten({"a": [1, 2, 3]}) [['a', [1, 2, 3]]] >>> flatten({"a": {"b": "c"}}) [['a', 'b', 'c']] >>> flatten({"a": {"b": {"c": "e"}}}) [['a', 'b', 'c', 'e']] >>> flatten({"a": {"b": "c", "d": "e"}}) [['a', 'b', 'c'], ['a', 'd', 'e']] >>> flatten({"a": {"b": "c", "d": "e"}, "b": {"c": "d"}}) [['a', 'b', 'c'], ['a', 'd', 'e'], ['b', 'c', 'd']] """ if not isinstance(d, dict): return [[d]] returned = [] for key, value in sorted(d.items()): # Each key, value is treated as a row. nested = flatten(value) for nest in nested: current_row = [key] current_row.extend(nest) returned.append(current_row) return returned def parametrize(params): """Return list of params as params. >>> parametrize(['a']) 'a' >>> parametrize(['a', 'b']) 'a[b]' >>> parametrize(['a', 'b', 'c']) 'a[b][c]' """ returned = str(params[0]) returned += "".join("[" + str(p) + "]" for p in params[1:]) return returned def urlencode(params): """Urlencode a multidimensional dict.""" # Not doing duck typing here. Will make debugging easier. if not isinstance(params, dict): raise TypeError("Only dicts are supported.") params = flatten(params) url_params = OrderedDict() for param in params: value = param.pop() name = parametrize(param) if isinstance(value, (list, tuple)): name += "[]" url_params[name] = value return urllib_urlencode(url_params, doseq=True)