Added nest utility method.

This commit is contained in:
Fabio Caccamo 2020-02-06 15:16:11 +01:00
parent 78c20ca2ce
commit 46e55cf1c9
4 changed files with 101 additions and 0 deletions

View File

@ -13,6 +13,7 @@ from benedict.core.keylists import keylists
from benedict.core.keypaths import keypaths
from benedict.core.merge import merge
from benedict.core.move import move
from benedict.core.nest import nest
from benedict.core.remove import remove
from benedict.core.rename import rename
from benedict.core.search import search

22
benedict/core/nest.py Normal file
View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from benedict.core.groupby import groupby
def _nest_items(nested_items, item, id_key, children_key):
children_items = nested_items.pop(item[id_key], [])
item[children_key] = children_items
for child_item in children_items:
_nest_items(nested_items, child_item, id_key, children_key)
def nest(items, id_key, parent_id_key, children_key):
if any([id_key == parent_id_key,
id_key == children_key,
parent_id_key == children_key]):
raise ValueError('keys should be different.')
nested_items = groupby(items, parent_id_key)
root_items = nested_items.get(None, [])
for item in root_items:
_nest_items(nested_items, item, id_key, children_key)
return nested_items.get(None)

View File

@ -12,6 +12,7 @@ from benedict.core import items_sorted_by_values as _items_sorted_by_values
from benedict.core import keypaths as _keypaths
from benedict.core import merge as _merge
from benedict.core import move as _move
from benedict.core import nest as _nest
from benedict.core import remove as _remove
from benedict.core import rename as _rename
from benedict.core import search as _search
@ -141,6 +142,13 @@ class benedict(IODict, KeypathDict, ParseDict):
"""
_move(self, key_src, key_dest)
def nest(self, key, id_key='id', parent_id_key='parent_id', children_key='children'):
"""
Nest a list of dicts at the given key and return a new nested list
using the specified keys to establish the correct items hierarchy.
"""
return _nest(self[key], id_key, parent_id_key, children_key)
def remove(self, keys, *args):
"""
Remove multiple keys from the current dict instance.

70
tests/core/test_nest.py Normal file
View File

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
from benedict.core import clone as _clone
from benedict.core import nest as _nest
import unittest
class nest_test_case(unittest.TestCase):
def test_nest(self):
l = [
{'id':1, 'parent_id':None, 'name':'John'},
{'id':2, 'parent_id':1, 'name':'Frank'},
{'id':3, 'parent_id':2, 'name':'Tony'},
{'id':4, 'parent_id':3, 'name':'Jimmy'},
{'id':5, 'parent_id':1, 'name':'Sam'},
{'id':6, 'parent_id':3, 'name':'Charles'},
{'id':7, 'parent_id':2, 'name':'Bob'},
{'id':8, 'parent_id':3, 'name':'Paul'},
{'id':9, 'parent_id':None, 'name':'Michael'},
]
l_clone = _clone(l)
n = _nest(l, 'id', 'parent_id', 'children')
r = [
{'id':1, 'parent_id':None, 'name':'John', 'children':[
{'id':2, 'parent_id':1, 'name':'Frank', 'children':[
{'id':3, 'parent_id':2, 'name':'Tony', 'children':[
{'id':4, 'parent_id':3, 'name':'Jimmy', 'children':[], },
{'id':6, 'parent_id':3, 'name':'Charles', 'children':[], },
{'id':8, 'parent_id':3, 'name':'Paul', 'children':[], },
], },
{'id':7, 'parent_id':2, 'name':'Bob', 'children':[], },
], },
{'id':5, 'parent_id':1, 'name':'Sam', 'children':[], },
]},
{'id':9, 'parent_id':None, 'name':'Michael', 'children':[], },
]
self.assertEqual(l, l_clone)
self.assertEqual(n, r)
def test_nest_with_wrong_keys(self):
l = [
{'id':1, 'parent_id':None, 'name':'John'},
{'id':2, 'parent_id':1, 'name':'Frank'},
{'id':3, 'parent_id':2, 'name':'Tony'},
{'id':4, 'parent_id':3, 'name':'Jimmy'},
{'id':5, 'parent_id':1, 'name':'Sam'},
{'id':6, 'parent_id':3, 'name':'Charles'},
{'id':7, 'parent_id':2, 'name':'Bob'},
{'id':8, 'parent_id':3, 'name':'Paul'},
{'id':9, 'parent_id':None, 'name':'Michael'},
]
with self.assertRaises(ValueError):
n = _nest(l, 'id', 'id', 'children')
with self.assertRaises(ValueError):
n = _nest(l, 'id', 'parent_id', 'id')
with self.assertRaises(ValueError):
n = _nest(l, 'id', 'parent_id', 'parent_id')
def test_nest_with_wrong_input(self):
l = {'id':1, 'parent_id':None, 'name':'John'}
with self.assertRaises(ValueError):
d = _nest(l, 'id', 'parent_id', 'children')
l = [
[{'id':1, 'parent_id':None, 'name':'John'},],
[{'id':2, 'parent_id':1, 'name':'Frank'},],
]
with self.assertRaises(ValueError):
d = _nest(l, 'id', 'parent_id', 'children')