From 1f541e4467701431687dc1053028712ad74d0c21 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 21:09:12 +0100 Subject: [PATCH 1/2] Add crunch utility --- graphene/utils/crunch.py | 37 ++++++++++++++++++++++++++ graphene/utils/tests/test_crunch.py | 40 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 graphene/utils/crunch.py create mode 100644 graphene/utils/tests/test_crunch.py diff --git a/graphene/utils/crunch.py b/graphene/utils/crunch.py new file mode 100644 index 00000000..16902e2b --- /dev/null +++ b/graphene/utils/crunch.py @@ -0,0 +1,37 @@ +import json +from collections import Mapping + + +def to_key(value): + return json.dumps(value) + + +def insert(value, index, values): + key = to_key(value) + + if key not in index: + index[key] = len(values) + values.append(value) + return len(values) - 1 + + return index.get(key) + + +def flatten(data, index, values): + if isinstance(data, (list, tuple)): + flattened = [flatten(child, index, values) for child in data] + elif isinstance(data, Mapping): + flattened = { + key: flatten(child, index, values) for key, child in data.items() + } + else: + flattened = data + return insert(flattened, index, values) + + +def crunch(data): + index = {} + values = [] + + flatten(data, index, values) + return values diff --git a/graphene/utils/tests/test_crunch.py b/graphene/utils/tests/test_crunch.py new file mode 100644 index 00000000..086d0d0f --- /dev/null +++ b/graphene/utils/tests/test_crunch.py @@ -0,0 +1,40 @@ +import pytest + +from ..crunch import crunch + + +@pytest.mark.parametrize("description,uncrunched,crunched", [ + ['number primitive', 0, [0]], + ['boolean primitive', True, [True]], + ['string primitive', "string", ["string"]], + ['empty array', [], [[]]], + ['single-item array', [None], [None, [0]]], + ['multi-primitive all distinct array', [None, 0, True, "string"], [None, 0, True, "string", [0, 1, 2, 3]]], + ['multi-primitive repeated array', [True, True, True, True], [True, [0, 0, 0, 0]]], + ['one-level nested array', [[1, 2, 3]], [1, 2, 3, [0, 1, 2], [3]]], + ['two-level nested array', [[[1, 2, 3]]], [1, 2, 3, [0, 1, 2], [3], [4]]], + ['empty object', {}, [{}]], + ['single-item object', {'a': None}, [None, {'a': 0}]], + [ + 'multi-item all distinct object', + {'a': None, 'b': 0, 'c': True, 'd': "string"}, + [None, 0, True, "string", {'a': 0, 'b': 1, 'c': 2, 'd': 3}] + ], + [ + 'multi-item repeated object', + {'a': True, 'b': True, 'c': True, 'd': True}, + [True, {'a': 0, 'b': 0, 'c': 0, 'd': 0}] + ], + [ + 'complex array', + [{'a': True, 'b': [1, 2, 3]}, [1, 2, 3]], + [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, [5, 4]] + ], + [ + 'complex object', + {'a': True, 'b': [1, 2, 3], 'c': {'a': True, 'b': [1, 2, 3]}}, + [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, {'a': 0, 'b': 4, 'c': 5}] + ], +]) +def test_crunch(description, uncrunched, crunched): + assert crunch(uncrunched) == crunched From 1e40eceab3b88bb283e6ce7a5a67c0f836f669eb Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 21:19:19 +0100 Subject: [PATCH 2/2] Convert inputs to OrderedDicts --- graphene/utils/tests/test_crunch.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/graphene/utils/tests/test_crunch.py b/graphene/utils/tests/test_crunch.py index 086d0d0f..6dd396c6 100644 --- a/graphene/utils/tests/test_crunch.py +++ b/graphene/utils/tests/test_crunch.py @@ -1,4 +1,5 @@ import pytest +from collections import OrderedDict from ..crunch import crunch @@ -17,22 +18,29 @@ from ..crunch import crunch ['single-item object', {'a': None}, [None, {'a': 0}]], [ 'multi-item all distinct object', - {'a': None, 'b': 0, 'c': True, 'd': "string"}, + OrderedDict([('a', None), ('b', 0), ('c', True), ('d', 'string')]), [None, 0, True, "string", {'a': 0, 'b': 1, 'c': 2, 'd': 3}] ], [ 'multi-item repeated object', - {'a': True, 'b': True, 'c': True, 'd': True}, + OrderedDict([('a', True), ('b', True), ('c', True), ('d', True)]), [True, {'a': 0, 'b': 0, 'c': 0, 'd': 0}] ], [ 'complex array', - [{'a': True, 'b': [1, 2, 3]}, [1, 2, 3]], + [ + OrderedDict([('a', True), ('b', [1, 2, 3])]), + [1, 2, 3] + ], [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, [5, 4]] ], [ 'complex object', - {'a': True, 'b': [1, 2, 3], 'c': {'a': True, 'b': [1, 2, 3]}}, + OrderedDict([ + ('a', True), + ('b', [1, 2, 3]), + ('c', OrderedDict([('a', True), ('b', [1, 2, 3])])) + ]), [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, {'a': 0, 'b': 4, 'c': 5}] ], ])