From 80e54c062625f53025c1105d7b86b75cdb415c9b Mon Sep 17 00:00:00 2001 From: Erik Jaegervall Date: Tue, 7 Nov 2023 14:42:06 +0100 Subject: [PATCH] Use deepcopy to copy data during expansion Needed so that exporters can change data on individula nodes, if needed Signed-off-by: Erik Jaegervall --- .../instance_extended_attribute.vspec | 17 +++++++++++ tests/instances/test_instances.py | 30 +++++++++++++++++++ .../vspec/test_overlay_on_instance/test.vspec | 4 +-- vspec/model/vsstree.py | 4 ++- 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/instances/resources/instance_extended_attribute.vspec diff --git a/tests/instances/resources/instance_extended_attribute.vspec b/tests/instances/resources/instance_extended_attribute.vspec new file mode 100644 index 00000000..5f763e4c --- /dev/null +++ b/tests/instances/resources/instance_extended_attribute.vspec @@ -0,0 +1,17 @@ +Vehicle: + type: branch + instances: Test[1,3] + description: High-level vehicle data. + +Vehicle.SomeThing: + type: sensor + description: "test" + datatype: string + dbc: + signal: bababa + transform: + mapping: + - from: 0 + to: false + - from: 1 + to: true diff --git a/tests/instances/test_instances.py b/tests/instances/test_instances.py index afd5be86..ad6544cd 100644 --- a/tests/instances/test_instances.py +++ b/tests/instances/test_instances.py @@ -7,6 +7,7 @@ # provisions of the license provided by the LICENSE file in this repository. # +from typing import Dict from vspec.model.vsstree import VSSNode from vspec.model.constants import VSSType, VSSTreeType import vspec @@ -170,3 +171,32 @@ def test_exclusion_from_instance(request): assert "Vehicle.ExcludeSomeThing" in name_list assert "Vehicle.ExcludeNode" in name_list + + +def test_extended_attribute(request): + test_path = os.path.dirname(request.fspath) + # load the file + tree = vspec.load_tree(os.path.join(test_path, "resources/instance_extended_attribute.vspec"), [os.path.join( + test_path, "resources/")], VSSTreeType.SIGNAL_TREE) + + # check if root node has 3 children + assert len(tree.children) == 3 + + # Programmatically change value of dbc/signal for instance in Test2 + + for child in tree.children: + if child.qualified_name() == "Vehicle.Test2": + assert len(child.children) == 1 + assert child.children[0].name == "SomeThing" # <... SomeThing + assert len(child.children[0].extended_attributes.items()) == 1 + assert isinstance(child.children[0].extended_attributes["dbc"], Dict) + assert isinstance(child.children[0].extended_attributes["dbc"]["signal"], str) + assert child.children[0].extended_attributes["dbc"]["signal"] == "bababa" + child.children[0].extended_attributes["dbc"]["signal"] = "lalala" + + for child in tree.children: + if child.qualified_name() == "Vehicle.Test2": + assert child.children[0].extended_attributes["dbc"]["signal"] == "lalala" + else: + # Make sure that all other instances keeps same name + assert child.children[0].extended_attributes["dbc"]["signal"] == "bababa" diff --git a/tests/vspec/test_overlay_on_instance/test.vspec b/tests/vspec/test_overlay_on_instance/test.vspec index c6ceb9f4..702fc755 100644 --- a/tests/vspec/test_overlay_on_instance/test.vspec +++ b/tests/vspec/test_overlay_on_instance/test.vspec @@ -4,7 +4,7 @@ A: description: Branch A. -# Instances defined a slist +# Instances defined as list A.B: type: branch @@ -32,4 +32,4 @@ A.S.T: type: sensor unit: km description: Signal A.S.T - comment: Orig comment. \ No newline at end of file + comment: Orig comment. diff --git a/vspec/model/vsstree.py b/vspec/model/vsstree.py index 1937eaa9..86780de6 100644 --- a/vspec/model/vsstree.py +++ b/vspec/model/vsstree.py @@ -62,7 +62,9 @@ class VSSNode(Node): deprecation = "" def __deepcopy__(self, memo): - return VSSNode(self.name, self.source_dict.copy(), self.available_types.copy(), + # Deep copy of source_dict and children needed as overlay or programmatic changes + # in exporters otherwise risk changing values not only for current instances but also for others + return VSSNode(self.name, copy.deepcopy(self.source_dict), self.available_types.copy(), parent=None, children=copy.deepcopy(self.children, memo)) def __init__(self, name, source_dict: dict, available_types: Set[str], parent=None,