1111 "add_dict_to_tree_by_name" ,
1212 "dict_to_tree" ,
1313 "nested_dict_to_tree" ,
14+ "nested_dict_key_to_tree" ,
1415]
1516
1617T = TypeVar ("T" , bound = node .Node )
@@ -238,7 +239,7 @@ def nested_dict_to_tree(
238239
239240 Examples:
240241 >>> from bigtree import nested_dict_to_tree
241- >>> path_dict = {
242+ >>> nested_dict = {
242243 ... "name": "a",
243244 ... "age": 90,
244245 ... "children": [
@@ -252,7 +253,7 @@ def nested_dict_to_tree(
252253 ... ]},
253254 ... ],
254255 ... }
255- >>> root = nested_dict_to_tree(path_dict )
256+ >>> root = nested_dict_to_tree(nested_dict )
256257 >>> root.show(attr_list=["age"])
257258 a [age=90]
258259 └── b [age=65]
@@ -300,3 +301,88 @@ def _recursive_add_child(
300301
301302 root_node = _recursive_add_child (node_attrs )
302303 return root_node
304+
305+
306+ def nested_dict_key_to_tree (
307+ node_attrs : Mapping [str , Mapping [str , Any ]],
308+ child_key : str = "children" ,
309+ node_type : Type [T ] = node .Node , # type: ignore[assignment]
310+ ) -> T :
311+ """Construct tree from nested recursive dictionary, where the keys are node names.
312+
313+ - ``key``: node name
314+ - ``value``: dict of node attributes and node children (recursive)
315+
316+ Value dictionary
317+
318+ - ``key`` that is not ``child_key`` has node attribute as value
319+ - ``key`` that is ``child_key`` has dictionary of node children as value (recursive)
320+
321+ Examples:
322+ >>> from bigtree import nested_dict_key_to_tree
323+ >>> nested_dict = {
324+ ... "a": {
325+ ... "age": 90,
326+ ... "children": {
327+ ... "b": {
328+ ... "age": 65,
329+ ... "children": {
330+ ... "d": {"age": 40},
331+ ... "e": {
332+ ... "age": 35,
333+ ... "children": {"g": {"age": 10}},
334+ ... },
335+ ... },
336+ ... },
337+ ... },
338+ ... }
339+ ... }
340+ >>> root = nested_dict_key_to_tree(nested_dict)
341+ >>> root.show(attr_list=["age"])
342+ a [age=90]
343+ └── b [age=65]
344+ ├── d [age=40]
345+ └── e [age=35]
346+ └── g [age=10]
347+
348+ Args:
349+ node_attrs: node, children, and node attribute information,
350+ key: node name
351+ value: dictionary of node attributes and node children
352+ child_key: key of child dict, value is type dict
353+ node_type: node type of tree to be created
354+
355+ Returns:
356+ Node
357+ """
358+ assertions .assert_length (node_attrs , 1 , "Dictionary" , "node_attrs" )
359+
360+ def _recursive_add_child (
361+ child_name : str , child_dict : Mapping [str , Any ], parent_node : Optional [T ] = None
362+ ) -> T :
363+ """Recursively add child to tree, given child attributes and parent node.
364+
365+ Args:
366+ child_name: child name to be added to tree
367+ child_dict: child to be added to tree, from dictionary
368+ parent_node: parent node to be assigned to child node
369+
370+ Returns:
371+ Node
372+ """
373+ child_dict = dict (child_dict )
374+ node_children = child_dict .pop (child_key , {})
375+ if not isinstance (node_children , Mapping ):
376+ raise TypeError (
377+ f"child_key { child_key } should be Dict type, received { node_children } "
378+ )
379+ root = node_type (child_name , parent = parent_node , ** child_dict )
380+ for _child_name in node_children :
381+ _recursive_add_child (
382+ _child_name , node_children [_child_name ], parent_node = root
383+ )
384+ return root
385+
386+ root_node_name = list (node_attrs .keys ())[0 ]
387+ root_node = _recursive_add_child (root_node_name , node_attrs [root_node_name ])
388+ return root_node
0 commit comments