From 491624bc37fe82787798a37655a0c2e584fee4e2 Mon Sep 17 00:00:00 2001 From: Chris McCormick Date: Mon, 25 Jun 2018 17:08:27 +0800 Subject: [PATCH 1/6] Option to leave off empty array braces. --- multidimensional_urlencode/tests/test_urlencode.py | 6 ++++++ multidimensional_urlencode/urlencoder.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/multidimensional_urlencode/tests/test_urlencode.py b/multidimensional_urlencode/tests/test_urlencode.py index 58e56c7..d097774 100644 --- a/multidimensional_urlencode/tests/test_urlencode.py +++ b/multidimensional_urlencode/tests/test_urlencode.py @@ -41,3 +41,9 @@ def test_with_non_dict(): """Verify that we raise an exception when passing a non-dict.""" with pytest.raises(TypeError): urlencode("e") + +def test_no_array_braces(): + """Verify that array braces can be left off.""" + d = {'a': {"b": [1, 2, 3]}} + expected = "a[b]=1&a[b]=2&a[b]=3" + assert unquote(urlencode(d)) == expected diff --git a/multidimensional_urlencode/urlencoder.py b/multidimensional_urlencode/urlencoder.py index a003451..4110cc4 100644 --- a/multidimensional_urlencode/urlencoder.py +++ b/multidimensional_urlencode/urlencoder.py @@ -54,7 +54,7 @@ def parametrize(params): return returned -def urlencode(params): +def urlencode(params, array_braces=True): """Urlencode a multidimensional dict.""" # Not doing duck typing here. Will make debugging easier. @@ -68,7 +68,7 @@ def urlencode(params): value = param.pop() name = parametrize(param) - if isinstance(value, (list, tuple)): + if isinstance(value, (list, tuple)) and array_braces: name += "[]" url_params[name] = value From 5ebfbe0b29a618d6ebc3aa45ed4118fc17b0d6dd Mon Sep 17 00:00:00 2001 From: Chris McCormick Date: Tue, 26 Jun 2018 14:44:42 +0800 Subject: [PATCH 2/6] Allow encoding of list keys. --- multidimensional_urlencode/urlencoder.py | 34 ++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/multidimensional_urlencode/urlencoder.py b/multidimensional_urlencode/urlencoder.py index 4110cc4..d18610d 100644 --- a/multidimensional_urlencode/urlencoder.py +++ b/multidimensional_urlencode/urlencoder.py @@ -6,7 +6,7 @@ from collections import OrderedDict -def flatten(d): +def flatten(d, encode_list_key=False): """Return a dict as a list of lists. >>> flatten({"a": "b"}) @@ -23,19 +23,25 @@ def flatten(d): [['a', 'b', 'c'], ['a', 'd', 'e'], ['b', 'c', 'd']] """ - if not isinstance(d, dict): - return [[d]] + if isinstance(d, dict) or (encode_list_key and isinstance(d, list)): + returned = [] - 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) + if isinstance(d, list) and encode_list_key: + inner = [(x, d[x]) for x in range(len(d))] + else: + inner = sorted(d.items()) - return returned + for key, value in inner: + # Each key, value is treated as a row. + nested = flatten(value, encode_list_key) + for nest in nested: + current_row = [key] + current_row.extend(nest) + returned.append(current_row) + + return returned + else: + return [[d]] def parametrize(params): @@ -54,14 +60,14 @@ def parametrize(params): return returned -def urlencode(params, array_braces=True): +def urlencode(params, encode_list_key=False, array_braces=True): """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) + params = flatten(params, encode_list_key) url_params = OrderedDict() for param in params: From 3aa6638e7eceeedc5e96989c242b32c99870e9b7 Mon Sep 17 00:00:00 2001 From: Chris McCormick Date: Thu, 16 May 2019 11:43:34 +0800 Subject: [PATCH 3/6] Fixed lint nit. --- multidimensional_urlencode/tests/test_urlencode.py | 1 + 1 file changed, 1 insertion(+) diff --git a/multidimensional_urlencode/tests/test_urlencode.py b/multidimensional_urlencode/tests/test_urlencode.py index d097774..471c58a 100644 --- a/multidimensional_urlencode/tests/test_urlencode.py +++ b/multidimensional_urlencode/tests/test_urlencode.py @@ -42,6 +42,7 @@ def test_with_non_dict(): with pytest.raises(TypeError): urlencode("e") + def test_no_array_braces(): """Verify that array braces can be left off.""" d = {'a': {"b": [1, 2, 3]}} From 1179d2a19ce18677d6da636a3bd28e9286db4066 Mon Sep 17 00:00:00 2001 From: Chris McCormick Date: Thu, 16 May 2019 11:58:31 +0800 Subject: [PATCH 4/6] Update doc with parameters. --- multidimensional_urlencode/urlencoder.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/multidimensional_urlencode/urlencoder.py b/multidimensional_urlencode/urlencoder.py index d18610d..e0bab5b 100644 --- a/multidimensional_urlencode/urlencoder.py +++ b/multidimensional_urlencode/urlencoder.py @@ -61,7 +61,16 @@ def parametrize(params): def urlencode(params, encode_list_key=False, array_braces=True): - """Urlencode a multidimensional dict.""" + """Urlencode a multidimensional dict. + + >>> urlencode({'a': {"b": [1, 2, 3]}}) + 'a[b][]=1&a[b][]=2&a[b][]=3' + >>> urlencode({'a': {"b": [1, 2, 3]}}, array_braces=False) + 'a[b]=1&a[b]=2&a[b]=3' + >>> urlencode({'a': {"b": [1, 2, 3]}}, encode_list_key=True) + 'a[b][0]=1&a[b][1]=2&a[b][2]=3' + + """ # Not doing duck typing here. Will make debugging easier. if not isinstance(params, dict): From a3d48d9bbb40e1032d67024cadfbd03dd16cbec3 Mon Sep 17 00:00:00 2001 From: Chris McCormick Date: Thu, 16 May 2019 11:59:18 +0800 Subject: [PATCH 5/6] Fix tests for new params. --- multidimensional_urlencode/tests/test_urlencode.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/multidimensional_urlencode/tests/test_urlencode.py b/multidimensional_urlencode/tests/test_urlencode.py index 471c58a..d73f9c2 100644 --- a/multidimensional_urlencode/tests/test_urlencode.py +++ b/multidimensional_urlencode/tests/test_urlencode.py @@ -47,4 +47,11 @@ def test_no_array_braces(): """Verify that array braces can be left off.""" d = {'a': {"b": [1, 2, 3]}} expected = "a[b]=1&a[b]=2&a[b]=3" - assert unquote(urlencode(d)) == expected + assert unquote(urlencode(d, array_braces=False)) == expected + + +def test_encode_list_key(): + """Verify that list indexes are explicitly added.""" + d = {'a': {"b": [1, 2, 3]}} + expected = "a[b][0]=1&a[b][1]=2&a[b][2]=3" + assert unquote(urlencode(d, encode_list_key=True)) == expected From 818ac617994fb238fc8d9487bedb3de914e8dd90 Mon Sep 17 00:00:00 2001 From: Chris McCormick Date: Thu, 16 May 2019 12:01:44 +0800 Subject: [PATCH 6/6] Fix doc tests with unquote. --- multidimensional_urlencode/urlencoder.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/multidimensional_urlencode/urlencoder.py b/multidimensional_urlencode/urlencoder.py index e0bab5b..5d61f2e 100644 --- a/multidimensional_urlencode/urlencoder.py +++ b/multidimensional_urlencode/urlencoder.py @@ -63,11 +63,16 @@ def parametrize(params): def urlencode(params, encode_list_key=False, array_braces=True): """Urlencode a multidimensional dict. - >>> urlencode({'a': {"b": [1, 2, 3]}}) + >>> try: + ... from urllib.parse import quote, unquote + ... except ImportError: + ... from urllib import quote, unquote + ... + >>> unquote(urlencode({'a': {"b": [1, 2, 3]}})) 'a[b][]=1&a[b][]=2&a[b][]=3' - >>> urlencode({'a': {"b": [1, 2, 3]}}, array_braces=False) + >>> unquote(urlencode({'a': {"b": [1, 2, 3]}}, array_braces=False)) 'a[b]=1&a[b]=2&a[b]=3' - >>> urlencode({'a': {"b": [1, 2, 3]}}, encode_list_key=True) + >>> unquote(urlencode({'a': {"b": [1, 2, 3]}}, encode_list_key=True)) 'a[b][0]=1&a[b][1]=2&a[b][2]=3' """