From 572319033180f081eedd711630fe082ad80c5143 Mon Sep 17 00:00:00 2001 From: Andreas Lauser Date: Fri, 13 Dec 2024 11:40:18 +0100 Subject: [PATCH] Add a `retarget_snrefs()` utility function The problem is that accessing object specified via short name reference always requires a context that is specific to the path via the object is accessed to; IOW, strictly speaking, resolving SNREFs cannot be done ahead of time (without copying everything for each possible context). Since odxtools is build on the assumption that all references can be resolved when a database is loaded and copying everything for each possible context would be quickly running into RAM limitations, we provide `retarget_snrefs()`, a utility function that re-resolves the SNREFs reachable by a specified diagnostic layer using that diagnostic layer. While this is not a "100% solution" because sometimes contexts of SNREFs are more fine-grained than the diagnostic layer that contains them, it should be a workable solution for about 95% of people who run into this issue. Usage: ```python import odxtools from odxtools.utils import retarget_snrefs db = odxtools.load_file("MyEcu.pdx") retarget_snrefs(db, db.ecu_variants.Variant2) ``` After this, all objects specified via SNREFs reachable by the diagnostic layer "Variant2" will be resolved using the point of view of Variant2. Be aware that only a single variant can be "active" for a given database, i.e., in the example above, accessing a resolved object via a diagnostic layer other than "Variant2" will still yield the same result as for Variant2... Signed-off-by: Andreas Lauser Signed-off-by: Gerrit Ecke --- odxtools/utils.py | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/odxtools/utils.py b/odxtools/utils.py index 3cf4f0ec..2989db00 100644 --- a/odxtools/utils.py +++ b/odxtools/utils.py @@ -1,7 +1,48 @@ # SPDX-License-Identifier: MIT import dataclasses import re -from typing import Any, Dict +from typing import TYPE_CHECKING, Any, Dict, Optional + +if TYPE_CHECKING: + from .database import Database + from .diaglayers.diaglayer import DiagLayer + from .snrefcontext import SnRefContext + + +def retarget_snrefs(database: "Database", + diag_layer: "DiagLayer", + context: Optional["SnRefContext"] = None) -> None: + """Re-resolve the short name references reachable by a + DiagLayer to this DiagLayer + + This implies that after the SNREFs have been retargeted, accessing + the resolved objects via a different diagnostic layer might not be + correct. E.g.: If the ECU variants "V1" and "V2" are derived from + the base variant "BV", BV defines a short name reference to a data + object property called "Foo" and V1 and V2 both define a "Foo" + DOP, the reference in the base variant to Foo ought to be resolved + differently depending on whether it is accessed via V1 or + V2. Since odxtools resolves all references ahead of time, a fixed + variant has to be chosen. This method allows to switch the variant + to another one. + + """ + from .snrefcontext import SnRefContext + + if context is None: + context = SnRefContext() + + if context.diag_layer is None: + context.database = database + context.diag_layer = diag_layer + + # retarget the objects "owned" by the layer itself + diag_layer._resolve_snrefs(context) + + # retarget all parents of the current layer (if any) + if (parent_refs := getattr(diag_layer, "parent_refs", None)) is not None: + for pr in parent_refs: + retarget_snrefs(database, pr.layer, context) def dataclass_fields_asdict(obj: Any) -> Dict[str, Any]: