Skip to content

nested_dict_to_tree breaks for Nodes with required args #338

@mat-adamec

Description

@mat-adamec

Describe the issue

The nested_dict_to_tree function explicitly builds nodes by calling node_type(node_name...) here.

Names are an optional attribute of Nodes as defined within the bigtree documentation. When one subclasses a bigtree node and adds required arguments, then calling nested_dict_to_tree with the subclass as the node_type breaks down, because this line takes the first argument as the name of the node, rather than taking the argument defined by the name_key.

I would classify this as a bug, as while it produces consistent behavior in bigtree with no augmentations, it harms the extensibility of the package without bringing any clear benefit (at least as far as I can see).

I believe this specific issue could be solved, without introducing additional bugs, by rewriting the line to:

root = node_type(name=node_name, parent=parent_node, **child_dict)

Environment

  • Platform: Windows 10
  • Python version: 3.11
  • bigtree version: 0.19.3

To Reproduce

Though the issue is generic, I offer an example to illustrate and make reproducibility simple.

Consider the following subclass node type.

class FooNode(Node):
    def __init__(
        self,
        bar: str,
        name: str = "",
        **kwargs: Any,
    ):
        super().__init__(name, **kwargs)
        self.bar = bar

With the following nested dictionary:

sample = {"name": "a", "foo": 1, "children": [{"name": "b", "foo": 2}, {"name": "c", "foo": 3, "children": [{"name": "d", "foo": 4}]}]}

Such that we have the following tree structure:

a (foo = 1)
--- b (foo=2)
--- c (foo=3)
      --- d (foo=4)

Calling nested_dict_to_tree on this with node_type set to FooNode will result in an error, as the following occurs:

Line 915 pops the value of the name key, say "a":
node_name = child_dict.pop(name_key)

Line 921 initializes a FooNode with "a" as the first argument, but the first argument of FooNode is bar (since bar is a required argument):
root = node_type(node_name, parent=parent_node, **child_dict)

The actual name for FooNode is thus never set, since name has already been popped off of the dictionary and provided to the incorrect argument in the Node's init signature.

Expected behaviour

I would expect the error to be avoided, since a name is provided, it's just not being provided to the appropriate argument in the function signature. At risk of repetition, the produced tree would look like:

a (foo = 1)
--- b (foo=2)
--- c (foo=3)
      --- d (foo=4)

where foo is an attribute of the node.

Additional context

I am not sure whether the same issue arises in other constructors in the library, as I am primarily using nested_dict_to_tree. If it does, then it would be worth fixing for the sake of proper extensibility (and, if this change is made to nested_dict_to_tree, consistency).

Final Check

  • I will watch this issue to stay updated with any comments or requests for additional information. I understand that timely responses will help in resolving the issue more quickly.

  • I have thoroughly searched the documentation, and I have also checked for existing solutions or similar issues before submitting this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions