Exemple #1
0
    def test_7(self):
        """4-level tree"""
        x1_nodes = LengthNode(2)
        x2_nodes = LengthNode(1), LengthNode(3)
        x3_0_nodes = [LengthNode(2)]
        x3_1_nodes = LengthNode(1), LengthNode(2), LengthNode(4)
        x4_0_0_nodes = LengthNode(1), LengthNode(3)
        x4_1_0_nodes = [LengthNode(1)]
        x4_1_1_nodes = LengthNode(2), LengthNode(2)
        x4_1_2_nodes = (
            LengthNode(1),
            LengthNode(1),
            LengthNode(1),
            LengthNode(2),
        )

        x1_nodes.set_children(x2_nodes)
        x2_nodes[0].set_children(x3_0_nodes)
        x2_nodes[1].set_children(x3_1_nodes)
        x3_0_nodes[0].set_children(x4_0_0_nodes)
        x3_1_nodes[0].set_children(x4_1_0_nodes)
        x3_1_nodes[1].set_children(x4_1_1_nodes)
        x3_1_nodes[2].set_children(x4_1_2_nodes)

        nodes = [x1_nodes]
        nodes.extend(x2_nodes)
        nodes.extend(x3_0_nodes)
        nodes.extend(x3_1_nodes)
        nodes.extend(x4_0_0_nodes)
        nodes.extend(x4_1_0_nodes)
        nodes.extend(x4_1_1_nodes)
        nodes.extend(x4_1_2_nodes)
        level_names = (
            "IDX_X1",
            "IDX_X2",
            "IDX_X3",
            "IDX_X4",
        )
        tree = LengthTree(nodes, level_names)
        expected_lengths = [
            2,
            [1, 3],
            [[2], [1, 2, 4]],
            [[[1, 3]], [[1], [2, 2], [1, 1, 1, 2]]],
        ]
        self.assertListEqual(tree.to_list(), expected_lengths)
Exemple #2
0
class TestTree(unittest.TestCase):
    def setUp(self):
        # lengths = [['IDX_SEG', 2],
        #            ['IDX_LAY', [3, 4]],
        #            ['IDX_POS', [[1, 3, 2], [5, 1, 2, 4]]]]

        seg_nodes = LengthNode(2)
        lay_nodes = LengthNode(3), LengthNode(4)
        pos_lay0_nodes = (
            LengthNode(1),
            LengthNode(3),
            LengthNode(2),
        )
        pos_lay1_nodes = (
            LengthNode(5),
            LengthNode(1),
            LengthNode(2),
            LengthNode(4),
        )

        seg_nodes.set_children(lay_nodes)
        lay_nodes[0].set_children(pos_lay0_nodes)
        lay_nodes[1].set_children(pos_lay1_nodes)

        nodes = [seg_nodes]
        nodes.extend(lay_nodes)
        nodes.extend(pos_lay0_nodes)
        nodes.extend(pos_lay1_nodes)
        level_names = "IDX_SEG", "IDX_LAY", "IDX_POS"
        self.tree = LengthTree(nodes, level_names)
        self.template_path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")

    def test_from_data1(self):
        """Extract lengths from input for path"""
        yml_input = """
                        segments:
                            - layers:
                                - thickness: 0.1 # [m]
                                  material: brick
                                  test:
                                    positions: [1, ]
                                - thickness: 0.02
                                  material: air
                                  test:
                                    positions: [1, 2, 3]
                                - thickness: 0.1
                                  material: brick
                                  test:
                                    positions: [1, 3]
                              inside:
                                temperature: 320. 
                              outside:
                                temperature: 273.
                            - layers:
                                - thickness: 0.15
                                  material: concrete
                                  test:
                                    positions: [1, 2, 3, 4, 5]
                                - thickness: 0.025
                                  material: EPS
                                  test:
                                    positions: [1,]
                                - thickness: 0.1
                                  material: concrete
                                  test:
                                    positions: [1, 2,]
                                - thickness: 0.001
                                  material: paint
                                  test:
                                    positions: [1, 2, 3, 4]
                              inside:
                                temperature: 300.
                              outside:
                                temperature: 273.
                    """
        input_data = yaml.load(yml_input, Loader=yaml.FullLoader)
        # path = "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]"
        path = HubitModelPath(
            "segments[IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")

        tree = LengthTree.from_data(path, input_data)
        tree_as_list = tree.to_list()
        # print(tree_as_list)
        # TODO test paths in this case
        # path = "segments[:@IDX_SEG].layers[:@IDX_LAY].test"
        expected_lengths = [2, [3, 4], [[1, 3, 2], [5, 1, 2, 4]]]
        self.assertSequenceEqual(expected_lengths, tree_as_list)

    def test_from_data2(self):
        """No lengths since there are no index IDs in path"""
        path = HubitModelPath("segments.layers.positions")
        calculated_tree = LengthTree.from_data(path, {})
        self.assertIsInstance(calculated_tree, DummyLengthTree)

    def test_0(self):
        """path is identical to template_path so the tree remains unchanged"""
        path = self.template_path
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertTrue(self.tree.to_list() == pruned_tree.to_list())

    def test_1(self):
        """Top level index fixed to 0
        [['IDX_SEG', 2],
        ['IDX_LAY', [3, 4]],
        ['IDX_POS', [[1, 3, 2], [5, 1, 2, 4]]]]
        """
        expected_lengths = [1, 3, [1, 3, 2]]
        path = HubitModelPath(
            "segments[0@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

        path = HubitQueryPath("segments[0].layers[:].test.positions[:]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

    def test_2(self):
        """Top level index fixed to 1"""
        expected_lengths = [1, 4, [5, 1, 2, 4]]

        path = HubitModelPath(
            "segments[1@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

        path = HubitQueryPath("segments[1].layers[:].test.positions[:]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

    def test_2a(self):
        """Outside bounds top level index"""
        path = HubitModelPath(
            "segments[2@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        with self.assertRaises(HubitIndexError) as context:
            self.tree.prune_from_path(path)

        path = HubitQueryPath("segments[2].layers[:].test.positions[:]")
        with self.assertRaises(HubitIndexError) as context:
            self.tree.prune_from_path(path)

    def test_3(self):
        """Middle index fixed"""
        expected_lengths = [2, [1, 1], [[3], [1]]]

        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[1@IDX_LAY].test.positions[:@IDX_POS]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

        path = HubitQueryPath("segments[:].layers[1].test.positions[:]")
        pruned_tree = self.tree.prune_from_path(path)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

    def test_4(self):
        """In bounds for all bottom-most paths."""
        expected_lengths = [2, [3, 4], [[1, 1, 1], [1, 1, 1, 1]]]

        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[0@IDX_POS]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

        path = HubitQueryPath("segments[:].layers[:].test.positions[0]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

    def test_5(self):
        """Two indices fixed"""
        expected_lengths = [1, 4, [1, 1, 1, 1]]

        path = HubitModelPath(
            "segments[1@IDX_SEG].layers[:@IDX_LAY].test.positions[0@IDX_POS]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

        path = HubitQueryPath("segments[1].layers[:].test.positions[0]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

    def test_5a(self):
        """Out of bounds for all but two paths

        [['IDX_SEG', 2*], -> 1
        ['IDX_LAY', [3, 4*]], -> 2
        ['IDX_POS', [[1, 3, 2], [5*, 1, 2, 4*]]]] -> [1, 1]
        """
        expected_lengths = [1, 2, [1, 1]]

        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[3@IDX_POS]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

        path = HubitQueryPath("segments[:].layers[:].test.positions[3]")
        pruned_tree = self.tree.prune_from_path(path, inplace=False)
        self.assertListEqual(pruned_tree.to_list(), expected_lengths)

    def test_6(self):
        """Out of bounds for all paths

        The tree is modified even when an error is raised if inplace=True
        Thats is OK since Hubit will raise an error and stop execution
        """
        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions1[7@IDX_POS]")
        with self.assertRaises(HubitIndexError) as context:
            self.tree.prune_from_path(path, inplace=False)

        path = HubitQueryPath("segments[:].layers[:].test.positions1[7]")
        with self.assertRaises(HubitIndexError) as context:
            self.tree.prune_from_path(path, inplace=False)

    def test_prune(self):
        def print_test(tree):
            nodes = tree.nodes_for_level[0]
            for node in nodes:
                print("node", node)
                for child in node.children:
                    print("child", child)

        idx_car_node = LengthNode(2)
        idx_parts_nodes = LengthNode(5), LengthNode(4)
        idx_car_node.set_children(idx_parts_nodes)
        nodes = [idx_car_node]
        nodes.extend(idx_parts_nodes)
        level_names = "IDX_CAR", "IDX_CAR"
        tree = LengthTree(nodes, level_names)
        clipped_tree = tree.clip_at_level("IDX_CAR", inplace=False)

        # nodes or bottom level
        nodes = clipped_tree.nodes_for_level[-1]

        # all children should be None at bottom level
        children_are_leaves = [
            all([isinstance(child, LeafNode) for child in node.children])
            for node in nodes
        ]

        with self.subTest():
            self.assertTrue(all(children_are_leaves))

        with self.subTest():
            self.assertTrue(len(clipped_tree.level_names) == 1)

        with self.subTest():
            self.assertTrue(len(clipped_tree.nodes_for_level) == 1)

    def test_7(self):
        """4-level tree"""
        x1_nodes = LengthNode(2)
        x2_nodes = LengthNode(1), LengthNode(3)
        x3_0_nodes = [LengthNode(2)]
        x3_1_nodes = LengthNode(1), LengthNode(2), LengthNode(4)
        x4_0_0_nodes = LengthNode(1), LengthNode(3)
        x4_1_0_nodes = [LengthNode(1)]
        x4_1_1_nodes = LengthNode(2), LengthNode(2)
        x4_1_2_nodes = (
            LengthNode(1),
            LengthNode(1),
            LengthNode(1),
            LengthNode(2),
        )

        x1_nodes.set_children(x2_nodes)
        x2_nodes[0].set_children(x3_0_nodes)
        x2_nodes[1].set_children(x3_1_nodes)
        x3_0_nodes[0].set_children(x4_0_0_nodes)
        x3_1_nodes[0].set_children(x4_1_0_nodes)
        x3_1_nodes[1].set_children(x4_1_1_nodes)
        x3_1_nodes[2].set_children(x4_1_2_nodes)

        nodes = [x1_nodes]
        nodes.extend(x2_nodes)
        nodes.extend(x3_0_nodes)
        nodes.extend(x3_1_nodes)
        nodes.extend(x4_0_0_nodes)
        nodes.extend(x4_1_0_nodes)
        nodes.extend(x4_1_1_nodes)
        nodes.extend(x4_1_2_nodes)
        level_names = (
            "IDX_X1",
            "IDX_X2",
            "IDX_X3",
            "IDX_X4",
        )
        tree = LengthTree(nodes, level_names)
        expected_lengths = [
            2,
            [1, 3],
            [[2], [1, 2, 4]],
            [[[1, 3]], [[1], [2, 2], [1, 1, 1, 2]]],
        ]
        self.assertListEqual(tree.to_list(), expected_lengths)

    def test_expand_mpath1(self):
        """Expand to full template path"""
        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")

        # 1 + 3 + 2 values for segment 0 and 5 + 1 + 2 + 4 values for segment 1
        # All all 18 elements
        expected_paths = [
            [  # IDX_SEG element 0 has 3 IDX_LAY elements
                [  # IDX_LAY element 0 has 1 IDX_POS elements
                    "segments[0].layers[0].test.positions[0]"
                ],
                [  # IDX_LAY element 1 has 3 IDX_POS elements
                    "segments[0].layers[1].test.positions[0]",
                    "segments[0].layers[1].test.positions[1]",
                    "segments[0].layers[1].test.positions[2]",
                ],
                [  # IDX_LAY element 2 has 2 IDX_POS elements
                    "segments[0].layers[2].test.positions[0]",
                    "segments[0].layers[2].test.positions[1]",
                ],
            ],
            [  # IDX_SEG element 1 has 4 IDX_LAY elements
                [  # IDX_LAY element 0 has 5 IDX_POS elements
                    "segments[1].layers[0].test.positions[0]",
                    "segments[1].layers[0].test.positions[1]",
                    "segments[1].layers[0].test.positions[2]",
                    "segments[1].layers[0].test.positions[3]",
                    "segments[1].layers[0].test.positions[4]",
                ],
                [  # IDX_LAY element 0 has 1 IDX_POS elements
                    "segments[1].layers[1].test.positions[0]",
                ],
                [  # IDX_LAY element 0 has 2 IDX_POS elements
                    "segments[1].layers[2].test.positions[0]",
                    "segments[1].layers[2].test.positions[1]",
                ],
                [  # IDX_LAY element 0 has 4 IDX_POS elements
                    "segments[1].layers[3].test.positions[0]",
                    "segments[1].layers[3].test.positions[1]",
                    "segments[1].layers[3].test.positions[2]",
                    "segments[1].layers[3].test.positions[3]",
                ],
            ],
        ]

        paths = self.tree.prune_from_path(path,
                                          inplace=False).expand_path(path)
        self.assertSequenceEqual(paths, expected_paths)

        # Cannot expand without pruning
        with self.assertRaises(HubitError) as context:
            paths = self.tree.expand_path(path)

    def test_expand_path2(self):
        """Expand path"""
        paths = (
            HubitModelPath("segments[:@IDX_SEG].layers[:@IDX_LAY].test"),
            HubitQueryPath("segments[:].layers[:].test"),
        )

        # path = "segments.:@IDX_SEG.layers.:@IDX_LAY.test"
        seg_node = LengthNode(2)
        lay_nodes = LengthNode(2), LengthNode(2)
        seg_node.set_children(lay_nodes)

        nodes = [seg_node]
        nodes.extend(lay_nodes)
        level_names = "IDX_SEG", "IDX_LAY"
        tree = LengthTree(nodes, level_names)
        # 2  values for segment 0 and 2 values for segment 1
        expected_paths = [
            [
                "segments[0].layers[0].test",
                "segments[0].layers[1].test",
            ],
            [
                "segments[1].layers[0].test",
                "segments[1].layers[1].test",
            ],
        ]

        for path in paths:
            with self.subTest(path=path):
                expanded_paths = tree.prune_from_path(path).expand_path(path)
                self.assertSequenceEqual(expanded_paths, expected_paths)

    def test_expand_path_count_from_back(self):
        """Expand path with fixed index set to negative number"""
        path = HubitQueryPath("segments[:].layers[-2].test")

        seg_node = LengthNode(3)
        lay_nodes = LengthNode(2), LengthNode(4), LengthNode(3)
        seg_node.set_children(lay_nodes)

        nodes = [seg_node]
        nodes.extend(lay_nodes)
        level_names = "IDX_SEG", "IDX_LAY"
        tree = LengthTree(nodes, level_names)

        expected_paths = [
            "segments[0].layers[0].test",
            "segments[1].layers[2].test",
            "segments[2].layers[1].test",
        ]

        # Since the tree is not pruned we must use flat=True
        expanded_paths = tree.prune_from_path(path, inplace=False).expand_path(
            path, flat=True)
        self.assertSequenceEqual(expanded_paths, expected_paths)

        # Index error. There are 2 layers on segment at index 0.
        path = HubitQueryPath("segments[:].layers[-3].test")
        with self.assertRaises(HubitIndexError) as context:
            expanded_paths = tree.prune_from_path(
                path, inplace=False).expand_path(path, flat=True)

        tree, _ = _get_data()
        qpath = HubitQueryPath("sites[1].lines[0].tanks[-1].Q_yield")
        expanded_paths = tree.prune_from_path(
            qpath, inplace=False).expand_path(qpath, flat=True)
        assert expanded_paths == ["sites[1].lines[0].tanks[3].Q_yield"]

        qpath = HubitQueryPath("sites[0].lines[-1].tanks[-1].Q_yield")
        expanded_paths = tree.prune_from_path(
            qpath, inplace=False).expand_path(qpath, flat=True)
        assert expanded_paths == ["sites[0].lines[0].tanks[2].Q_yield"]

        qpath = HubitQueryPath("sites[:].lines[-1].tanks[-1].Q_yield")
        expanded_paths = tree.prune_from_path(
            qpath, inplace=False).expand_path(qpath, flat=True)
        assert expanded_paths == [
            "sites[0].lines[0].tanks[2].Q_yield",
            "sites[1].lines[0].tanks[3].Q_yield",
        ]

        qpath = HubitQueryPath("sites[:].lines[:].tanks[:].Q_yield")
        expanded_paths = tree.prune_from_path(
            qpath, inplace=False).expand_path(qpath, flat=True)

    def test_expand_mpath3(self):
        """Prune tree before expanding. Two indices vary so
        expanded paths is 2D
        """
        # 1 + 3 + 2 values for segment 0
        expected_paths = [
            [
                "segments[0].layers[0].test.positions[0]",
            ],
            [
                "segments[0].layers[1].test.positions[0]",
                "segments[0].layers[1].test.positions[1]",
                "segments[0].layers[1].test.positions[2]",
            ],
            [
                "segments[0].layers[2].test.positions[0]",
                "segments[0].layers[2].test.positions[1]",
            ],
        ]

        mpath = HubitModelPath(
            "segments[0@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        pruned_tree = self.tree.prune_from_path(mpath, inplace=False)
        paths = pruned_tree.expand_path(mpath)
        self.assertSequenceEqual(paths, expected_paths)

    def test_expand_mpath4(self):
        """Prune tree before expanding. One index varies so
        expanded paths is 1D
        """
        print(self.tree)
        path = HubitModelPath(
            "segments[0@IDX_SEG].layers[:@IDX_LAY].test.positions[1@IDX_POS]")
        # path = HubitModelPath("segments[0].layers[:@IDX_LAY].test.positions[1]")
        template_path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        self.tree.prune_from_path(path)
        # 1 + 3 + 2 values for segment 0
        expected_paths = [
            "segments[0].layers[1].test.positions[1]",
            "segments[0].layers[2].test.positions[1]",
        ]
        paths = self.tree.expand_path(path)
        self.assertSequenceEqual(paths, expected_paths)

    def test_expand_mpath5(self):
        """Expand subscription path with two wildcards gives a nested list"""
        input_data = {
            "items": [
                {
                    "attr": {
                        "items": [{
                            "path": 2
                        }, {
                            "path": 1
                        }]
                    }
                },
                {
                    "attr": {
                        "items": [{
                            "path": 3
                        }, {
                            "path": 4
                        }]
                    }
                },
            ],
            "some_number":
            33,
        }
        path_consumed_for_name = {
            "attrs": HubitModelPath("items[:@IDX1].attr.items[:@IDX2].path"),
            "number": HubitModelPath("some_number"),
        }
        expected_result = {
            "attrs": [
                ["items[0].attr.items[0].path", "items[0].attr.items[1].path"],
                ["items[1].attr.items[0].path", "items[1].attr.items[1].path"],
            ],
            "number": ["some_number"],
        }
        tree_for_name = {
            name: LengthTree.from_data(path, input_data)
            for name, path in path_consumed_for_name.items()
        }

        result = {
            name:
            tree.prune_from_path(path_consumed_for_name[name]).expand_path(
                path_consumed_for_name[name])
            for name, tree in tree_for_name.items()
        }

        self.assertDictEqual(expected_result, result)

    def test_expand_mpath6(self):
        """As test 8 but the consumed path only subscribes to element 1
        of the (leftmost) items. Thus, the expansion leads to a flat list
        corresponding to the (rightmost) items
        """
        input_data = {
            "items_a": [
                {
                    "attr": {
                        "items": [{
                            "path": 2
                        }, {
                            "path": 1
                        }]
                    }
                },
                {
                    "attr": {
                        "items": [{
                            "path": 3
                        }, {
                            "path": 4
                        }]
                    }
                },
            ],
            "some_number":
            33,
        }

        path_consumed_for_name = {
            "attrs": HubitModelPath("items_a[1@IDX1].attr.items[:@IDX2].path"),
            "number": HubitModelPath("some_number"),
        }

        expected_result = {
            "attrs":
            ["items_a[1].attr.items[0].path", "items_a[1].attr.items[1].path"],
            "number": ["some_number"],
        }

        tree_for_name = {
            name: LengthTree.from_data(path, input_data, prune=True)
            for name, path in path_consumed_for_name.items()
        }

        tree_for_name["attrs"].prune_from_path(path_consumed_for_name["attrs"])

        result = {
            name: tree.expand_path(path_consumed_for_name[name])
            for name, tree in tree_for_name.items()
        }
        self.assertDictEqual(expected_result, result)

    def test_none_like_1(self):
        """
        Get a nested list corresponding to the tree
        """
        print(self.tree)
        result = self.tree.none_like()
        expected_result = [
            [[None], [None, None, None], [None, None]],
            [
                [None, None, None, None, None],
                [None],
                [None, None],
                [None, None, None, None],
            ],
        ]
        print(expected_result)
        self.assertListEqual(result, expected_result)

    def test_none_like_2(self):
        """
        Get a nested list corresponding to a tree with
        only node element per nested list
        """
        #
        yml_input = """
                        segments:
                            - layers:
                                - dummy1: 0.1 
                                  dummy2: dummy_value
                                  test:
                                    positions: 
                                        - 1
                    """
        input_data = yaml.load(yml_input, Loader=yaml.FullLoader)

        # Point to all elements
        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        tree = LengthTree.from_data(path, input_data)
        # print(tree)
        # print(tree.to_list())
        result = tree.none_like()
        print(result)
        # expected_result = [None]
        # self.assertListEqual(result, expected_result)

        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[IDX_POS]")
        tree = LengthTree.from_data(path, input_data)
        # print(tree)
        # print(tree.to_list())
        result = tree.none_like()
        print(result)
        # self.assertListEqual(result, expected_result)

    def test_none_like_2(self):
        """
        Get a nested list corresponding to a tree with
        only node element per nested list
        """
        #
        yml_input = """
                        segments:
                            - layers:
                                - dummy1: 0.1 
                                  dummy2: dummy_value
                                  test:
                                    positions: 
                                        - 1
                                        - 2
                    """
        input_data = yaml.load(yml_input, Loader=yaml.FullLoader)

        # Point to all elements
        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        tree = LengthTree.from_data(path, input_data)
        # print(tree)
        # print(tree.to_list())
        result = tree.none_like()
        print(result)
        # expected_result = [None]
        # self.assertListEqual(result, expected_result)

        path = HubitModelPath(
            "segments[:@IDX_SEG].layers[:@IDX_LAY].test.positions[IDX_POS]")
        tree = LengthTree.from_data(path, input_data)
        # print(tree)
        # print(tree.to_list())
        result = tree.none_like()
        print(result)
        # self.assertListEqual(result, expected_result)

    def test_none_like_3(self):
        """
        Get a nested list corresponding to a tree with
        only node element per nested list
        """
        #
        yml_input = """
                    layers:
                      - dummy1: 0.1 
                        dummy2: dummy_value
                        test:
                          positions: 
                            - 1
                            - 2
                      - dummy1: 0.1 
                        dummy2: dummy_value
                        test:
                          positions: 
                            - 1
                    """
        input_data = yaml.load(yml_input, Loader=yaml.FullLoader)

        # Point to all elements
        path = HubitModelPath("layers[:@IDX_LAY].test.positions[:@IDX_POS]")
        tree = LengthTree.from_data(path, input_data)
        # print(tree)
        # print(tree.to_list())
        result = tree.none_like()
        print(result)
        # expected_result = [None]
        # self.assertListEqual(result, expected_result)

        path = HubitModelPath("layers[:@IDX_LAY].test.positions[IDX_POS]")
        tree = LengthTree.from_data(path, input_data)
        # print(tree)
        # print(tree.to_list())
        result = tree.none_like()
        print(result)
        # self.assertListEqual(result, expected_result)

    def test_none_like_4(self):
        """
        Get a nested list corresponding to a tree with
        only node element per nested list
        """
        # Two nested lists of length 1
        yml_inputs = {
            "1d":
            """
                    layers:
                      - dummy1: 0.1 
                        dummy2: dummy_value
                        test:
                          positions: 
                            - 1
                    """,
            "2d":
            """
                    layers:
                      - dummy1: 0.1 
                        dummy2: dummy_value
                        test:
                          positions: 
                            - 1
                            - 2
                      - dummy1: 0.1 
                        dummy2: dummy_value
                        test:
                          positions: 
                            - 3
                            - 4
                    """,
        }

        test_items = [
            (
                HubitModelPath("layers[:@IDX_LAY].test.positions[:@IDX_POS]"),
                None,
                {
                    "1d": [[None]],
                    "2d": [[None, None], [None, None]]
                },
            ),
            (
                HubitModelPath("layers[0@IDX_LAY].test.positions[0@IDX_POS]"),
                None,
                {
                    "1d": None,
                    "2d": None
                },
            ),
            (
                HubitModelPath("layers[0@IDX_LAY].test.positions[:@IDX_POS]"),
                None,
                {
                    "1d": [None],
                    "2d": [None, None]
                },
            ),
            (
                HubitModelPath("layers[:@IDX_LAY].test.positions[0@IDX_POS]"),
                None,
                {
                    "1d": [None],
                    "2d": [None, None]
                },
            ),
            (
                HubitModelPath("layers[:@IDX_LAY].test.positions[:@IDX_POS]"),
                HubitQueryPath("layers[:].test.positions[:]"),
                {
                    "1d": [[None]],
                    "2d": [[None, None], [None, None]]
                },
            ),
            (
                HubitModelPath("layers[:@IDX_LAY].test.positions[:@IDX_POS]"),
                HubitQueryPath("layers[0].test.positions[0]"),
                {
                    "1d": None,
                    "2d": None
                },
            ),
            (
                HubitModelPath("layers[:@IDX_LAY].test.positions[:@IDX_POS]"),
                HubitQueryPath("layers[:].test.positions[0]"),
                {
                    "1d": [None],
                    "2d": [None, None]
                },
            ),
            (
                HubitModelPath("layers[:@IDX_LAY].test.positions[:@IDX_POS]"),
                HubitQueryPath("layers[0].test.positions[:]"),
                {
                    "1d": [None],
                    "2d": [None, None]
                },
            ),
        ]

        for input_id, yml_input in yml_inputs.items():
            input_data = yaml.load(yml_input, Loader=yaml.FullLoader)

            for test_item in test_items:
                mpath, qpath, expected_result = test_item
                expected_result = expected_result[input_id]
                tree = LengthTree.from_data(mpath, input_data, prune=True)
                if qpath is not None:
                    tree.prune_from_path(qpath)
                print("Test:", input_id, mpath, qpath)
                result = tree.none_like()
                with self.subTest(
                        result=result,
                        expected_result=expected_result,
                        mapth=mpath,
                        qpath=qpath,
                        input_id=input_id,
                ):
                    if expected_result is None:
                        self.assertEqual(result, expected_result)
                    else:
                        self.assertListEqual(result, expected_result)

    def test_is_path_described_query_paths(self):
        print(self.tree)

        # Path with no ranges is not described by a LengthTree
        assert not self.tree.is_path_described(HubitQueryPath("i.dont.exist"))

        assert self.tree.is_path_described(
            HubitQueryPath("segments[0].layers[0].test.positions[0]"))

        assert not self.tree.is_path_described(
            HubitQueryPath("segments[0].layers[0].test.positions[1]"))

        assert not self.tree.is_path_described(
            HubitQueryPath("segments[7].layers[0].test.positions[1]"))

        assert self.tree.is_path_described(
            HubitQueryPath("segments[1].layers[0].test.positions[4]"))

        assert not self.tree.is_path_described(
            HubitQueryPath("segments[1].layers[0].test.positions[5]"))

        # At least one segment has 4 positions on layer 0
        assert self.tree.is_path_described(
            HubitQueryPath("segments[:].layers[0].test.positions[4]"))

        # No segment has 5 positions on layer 0
        assert not self.tree.is_path_described(
            HubitQueryPath("segments[:].layers[0].test.positions[5]"))

    def test_is_path_described_model_paths(self):
        print(self.tree)

        # Path with no ranges is not described by a LengthTree
        assert not self.tree.is_path_described(HubitModelPath("i.dont.exist"))

        assert self.tree.is_path_described(
            HubitModelPath(
                "segments[0@IDX_SEG].layers[0@IDX_LAY].test.positions[0@IDX_POS]"
            ))

        assert not self.tree.is_path_described(
            HubitModelPath(
                "segments[0@IDX_SEG].layers[0@IDX_LAY].test.positions[1@IDX_POS]"
            ))

        # Wrong index context
        assert not self.tree.is_path_described(
            HubitModelPath(
                "segments[0@IDX_WRONG].layers[0@IDX_LAY].test.positions[0@IDX_POS]"
            ))