diff --git a/odxtools/basicstructure.py b/odxtools/basicstructure.py index 335ddbb7..b3bc7d7e 100644 --- a/odxtools/basicstructure.py +++ b/odxtools/basicstructure.py @@ -23,7 +23,6 @@ from .parameters.parameterwithdop import ParameterWithDOP from .parameters.physicalconstantparameter import PhysicalConstantParameter from .parameters.tablekeyparameter import TableKeyParameter -from .parameters.tablestructparameter import TableStructParameter from .utils import dataclass_fields_asdict if TYPE_CHECKING: @@ -307,7 +306,4 @@ def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: super()._resolve_snrefs(diag_layer) for param in self.parameters: - if isinstance(param, TableStructParameter): - param._table_struct_resolve_snrefs(diag_layer, param_list=self.parameters) - else: - param._resolve_snrefs(diag_layer) + param._parameter_resolve_snrefs(diag_layer, param_list=self.parameters) diff --git a/odxtools/diagcomm.py b/odxtools/diagcomm.py index d6e92515..b190b400 100644 --- a/odxtools/diagcomm.py +++ b/odxtools/diagcomm.py @@ -11,7 +11,7 @@ from .exceptions import odxraise, odxrequire from .functionalclass import FunctionalClass from .nameditemlist import NamedItemList -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from .odxtypes import odxstr_to_bool from .specialdatagroup import SpecialDataGroup from .state import State @@ -211,5 +211,13 @@ def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: for sdg in self.sdgs: sdg._resolve_snrefs(diag_layer) - self._protocols = NamedItemList( - [diag_layer.protocols[prot_snref] for prot_snref in self.protocol_snrefs]) + if TYPE_CHECKING: + self._protocols = NamedItemList([ + resolve_snref(prot_snref, diag_layer.protocols, DiagLayer) + for prot_snref in self.protocol_snrefs + ]) + else: + self._protocols = NamedItemList([ + resolve_snref(prot_snref, diag_layer.protocols) + for prot_snref in self.protocol_snrefs + ]) diff --git a/odxtools/diaglayerraw.py b/odxtools/diaglayerraw.py index 42d931e4..cdc5dca7 100644 --- a/odxtools/diaglayerraw.py +++ b/odxtools/diaglayerraw.py @@ -19,7 +19,7 @@ from .exceptions import odxassert, odxraise, odxrequire from .functionalclass import FunctionalClass from .nameditemlist import NamedItemList -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from .parentref import ParentRef from .protstack import ProtStack from .request import Request @@ -281,8 +281,8 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: self._prot_stack: Optional[ProtStack] = None if self.prot_stack_snref is not None: - self._prot_stack = odxrequire( - odxrequire(self.comparam_spec).prot_stacks.get(self.prot_stack_snref)) + self._prot_stack = resolve_snref(self.prot_stack_snref, + odxrequire(self.comparam_spec).prot_stacks, ProtStack) # do short-name reference resolution if self.admin_data is not None: @@ -292,8 +292,8 @@ def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: for company_data in self.company_datas: company_data._resolve_snrefs(diag_layer) - for functional_classe in self.functional_classes: - functional_classe._resolve_snrefs(diag_layer) + for functional_class in self.functional_classes: + functional_class._resolve_snrefs(diag_layer) for diag_comm in self.diag_comms: if isinstance(diag_comm, OdxLinkRef): continue diff --git a/odxtools/field.py b/odxtools/field.py index 50589892..89ac409e 100644 --- a/odxtools/field.py +++ b/odxtools/field.py @@ -6,7 +6,7 @@ from .complexdop import ComplexDop from .environmentdatadescription import EnvironmentDataDescription from .exceptions import odxassert, odxrequire -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef, resolve_snref from .odxtypes import odxstr_to_bool from .utils import dataclass_fields_asdict @@ -84,8 +84,9 @@ def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: """Recursively resolve any short-name references""" if self.structure_snref is not None: structures = diag_layer.diag_data_dictionary_spec.structures - self._structure = odxrequire(structures.get(self.structure_snref)) + self._structure = resolve_snref(self.structure_snref, structures, BasicStructure) if self.env_data_desc_snref is not None: env_data_descs = diag_layer.diag_data_dictionary_spec.env_data_descs - self._env_data_desc = odxrequire(env_data_descs.get(self.env_data_desc_snref)) + self._env_data_desc = resolve_snref(self.env_data_desc_snref, env_data_descs, + EnvironmentDataDescription) diff --git a/odxtools/matchingparameter.py b/odxtools/matchingparameter.py index bb9288d9..25ff1add 100644 --- a/odxtools/matchingparameter.py +++ b/odxtools/matchingparameter.py @@ -32,8 +32,8 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "MatchingParameter": expected_value = odxrequire(et_element.findtext("EXPECTED-VALUE")) - diag_com_snref_el = odxrequire(et_element.find("DIAG-COMM-SNREF")) - diag_comm_snref = odxrequire(diag_com_snref_el.get("SHORT-NAME")) + diag_comm_snref_el = odxrequire(et_element.find("DIAG-COMM-SNREF")) + diag_comm_snref = odxrequire(diag_comm_snref_el.get("SHORT-NAME")) out_param_snref_el = et_element.find("OUT-PARAM-IF-SNREF") out_param_snpathref_el = et_element.find("OUT-PARAM-IF-SNPATHREF") out_param_if = None diff --git a/odxtools/multiplexercase.py b/odxtools/multiplexercase.py index d7b16c53..2e8d0eeb 100644 --- a/odxtools/multiplexercase.py +++ b/odxtools/multiplexercase.py @@ -7,7 +7,7 @@ from .compumethods.limit import Limit from .element import NamedElement from .exceptions import odxrequire -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from .odxtypes import AtomicOdxType, DataType from .utils import dataclass_fields_asdict @@ -73,7 +73,7 @@ def _mux_case_resolve_odxlinks(self, odxlinks: OdxLinkDatabase, *, def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: if self.structure_snref: ddds = diag_layer.diag_data_dictionary_spec - self._structure = odxrequire(ddds.structures.get(self.structure_snref)) + self._structure = resolve_snref(self.structure_snref, ddds.structures, BasicStructure) def applies(self, value: AtomicOdxType) -> bool: return self.lower_limit.complies_to_lower(value) \ diff --git a/odxtools/multiplexerdefaultcase.py b/odxtools/multiplexerdefaultcase.py index 9b77e732..45f289ce 100644 --- a/odxtools/multiplexerdefaultcase.py +++ b/odxtools/multiplexerdefaultcase.py @@ -6,7 +6,7 @@ from .basicstructure import BasicStructure from .element import NamedElement from .exceptions import odxrequire -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from .utils import dataclass_fields_asdict if TYPE_CHECKING: @@ -20,7 +20,7 @@ class MultiplexerDefaultCase(NamedElement): structure_snref: Optional[str] def __post_init__(self) -> None: - self._structure: Optional[BasicStructure] = None + self._structure: BasicStructure @staticmethod def from_et(et_element: ElementTree.Element, @@ -46,4 +46,8 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: if self.structure_snref: ddds = diag_layer.diag_data_dictionary_spec - self._structure = odxrequire(ddds.structures.get(self.structure_snref)) + self._structure = resolve_snref(self.structure_snref, ddds.structures, BasicStructure) + + @property + def structure(self) -> BasicStructure: + return self._structure diff --git a/odxtools/odxlink.py b/odxtools/odxlink.py index 76a9a239..b6ba55cf 100644 --- a/odxtools/odxlink.py +++ b/odxtools/odxlink.py @@ -1,10 +1,11 @@ # SPDX-License-Identifier: MIT import warnings from dataclasses import dataclass -from typing import Any, Dict, List, Optional, Type, TypeVar, overload +from typing import Any, Dict, Iterable, List, Optional, Type, TypeVar, overload from xml.etree import ElementTree -from .exceptions import OdxWarning, odxassert +from .exceptions import OdxWarning, odxassert, odxraise +from .nameditemlist import OdxNamed, TNamed @dataclass(frozen=True) @@ -270,3 +271,34 @@ def update(self, new_entries: Dict[OdxLinkId, Any]) -> None: self._db[doc_frag] = {} self._db[doc_frag][odx_id] = obj + + +@overload +def resolve_snref(target_short_name: str, + items: Iterable[OdxNamed], + expected_type: None = None) -> Any: + """Resolve a short name reference given a sequence of candidate objects""" + ... + + +@overload +def resolve_snref(target_short_name: str, items: Iterable[OdxNamed], + expected_type: Type[TNamed]) -> TNamed: + ... + + +def resolve_snref(target_short_name: str, + items: Iterable[OdxNamed], + expected_type: Any = None) -> Any: + candidates = [x for x in items if x.short_name == target_short_name] + + if not candidates: + odxraise(f"Cannot resolve short name reference to '{target_short_name}'") + return None + elif len(candidates) > 1: + odxraise(f"Cannot uniquely resolve short name reference to '{target_short_name}'") + elif expected_type is not None and not isinstance(candidates[0], expected_type): + odxraise(f"Reference '{target_short_name}' points to a {type(candidates[0]).__name__}" + f"object while expecting {expected_type.__name__}") + + return candidates[0] diff --git a/odxtools/parameters/codedconstparameter.py b/odxtools/parameters/codedconstparameter.py index e2ae4c84..e6f2c5d3 100644 --- a/odxtools/parameters/codedconstparameter.py +++ b/odxtools/parameters/codedconstparameter.py @@ -59,8 +59,9 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: super()._resolve_odxlinks(odxlinks) @override - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) @override def get_static_bit_length(self) -> Optional[int]: diff --git a/odxtools/parameters/lengthkeyparameter.py b/odxtools/parameters/lengthkeyparameter.py index 9410f6a9..6a705be6 100644 --- a/odxtools/parameters/lengthkeyparameter.py +++ b/odxtools/parameters/lengthkeyparameter.py @@ -11,7 +11,7 @@ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId from ..odxtypes import ParameterValue from ..utils import dataclass_fields_asdict -from .parameter import ParameterType +from .parameter import Parameter, ParameterType from .parameterwithdop import ParameterWithDOP if TYPE_CHECKING: @@ -60,8 +60,9 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: super()._resolve_odxlinks(odxlinks) @override - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) @property @override diff --git a/odxtools/parameters/nrcconstparameter.py b/odxtools/parameters/nrcconstparameter.py index 3419dbd3..6cbd1a5b 100644 --- a/odxtools/parameters/nrcconstparameter.py +++ b/odxtools/parameters/nrcconstparameter.py @@ -75,8 +75,9 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: super()._resolve_odxlinks(odxlinks) @override - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) @override def get_static_bit_length(self) -> Optional[int]: diff --git a/odxtools/parameters/parameter.py b/odxtools/parameters/parameter.py index 7705802c..7ade96ed 100644 --- a/odxtools/parameters/parameter.py +++ b/odxtools/parameters/parameter.py @@ -82,7 +82,13 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: for sdg in self.sdgs: sdg._resolve_odxlinks(odxlinks) + @final def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: + raise RuntimeError("Calling _resolve_snrefs() is not allowed for parameters. " + "Use _parameter_resolve_snrefs() instead.") + + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List["Parameter"]) -> None: for sdg in self.sdgs: sdg._resolve_snrefs(diag_layer) diff --git a/odxtools/parameters/parameterwithdop.py b/odxtools/parameters/parameterwithdop.py index 06aec3f6..b5ab03aa 100644 --- a/odxtools/parameters/parameterwithdop.py +++ b/odxtools/parameters/parameterwithdop.py @@ -11,7 +11,7 @@ from ..dtcdop import DtcDop from ..encodestate import EncodeState from ..exceptions import odxassert, odxrequire -from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from ..odxtypes import AtomicOdxType, ParameterValue from ..physicaltype import PhysicalType from ..utils import dataclass_fields_asdict @@ -61,12 +61,13 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: self._dop = odxlinks.resolve_lenient(self.dop_ref) @override - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) if self.dop_snref: - ddds = diag_layer.diag_data_dictionary_spec - self._dop = odxrequire(ddds.all_data_object_properties.get(self.dop_snref)) + all_dops = diag_layer.diag_data_dictionary_spec.all_data_object_properties + self._dop = resolve_snref(self.dop_snref, all_dops, DopBase) @property def dop(self) -> DopBase: diff --git a/odxtools/parameters/physicalconstantparameter.py b/odxtools/parameters/physicalconstantparameter.py index df58c8bc..f34dbf65 100644 --- a/odxtools/parameters/physicalconstantparameter.py +++ b/odxtools/parameters/physicalconstantparameter.py @@ -12,7 +12,7 @@ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId from ..odxtypes import ParameterValue from ..utils import dataclass_fields_asdict -from .parameter import ParameterType +from .parameter import Parameter, ParameterType from .parameterwithdop import ParameterWithDOP if TYPE_CHECKING: @@ -50,8 +50,9 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: super()._resolve_odxlinks(odxlinks) @override - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) dop = odxrequire(self.dop) if not isinstance(dop, DataObjectProperty): diff --git a/odxtools/parameters/tablekeyparameter.py b/odxtools/parameters/tablekeyparameter.py index 564bdc33..ca2b0175 100644 --- a/odxtools/parameters/tablekeyparameter.py +++ b/odxtools/parameters/tablekeyparameter.py @@ -8,7 +8,7 @@ from ..decodestate import DecodeState from ..encodestate import EncodeState from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire -from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from ..odxtypes import ParameterValue from ..utils import dataclass_fields_asdict from .parameter import Parameter, ParameterType @@ -94,19 +94,19 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: self._table = self._table_row.table @override - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) if self.table_snref is not None: - ddd_spec = diag_layer.diag_data_dictionary_spec - self._table = ddd_spec.tables[self.table_snref] + tables = diag_layer.diag_data_dictionary_spec.tables + self._table = resolve_snref(self.table_snref, tables, Table) if self.table_row_snref is not None: # make sure that we know the table to which the table row # SNREF is relative to. - table = odxrequire( - self._table, "If a table-row short name reference is defined, a " - "table must also be specified.") - self._table_row = table.table_rows[self.table_row_snref] + table = odxrequire(self._table, + "If a table-row is referenced, a table must also be referenced.") + self._table_row = resolve_snref(self.table_row_snref, table.table_rows, TableRow) @property def table(self) -> "Table": diff --git a/odxtools/parameters/tablestructparameter.py b/odxtools/parameters/tablestructparameter.py index adfe0d55..083da933 100644 --- a/odxtools/parameters/tablestructparameter.py +++ b/odxtools/parameters/tablestructparameter.py @@ -3,12 +3,12 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast from xml.etree import ElementTree -from typing_extensions import final, override +from typing_extensions import override from ..decodestate import DecodeState from ..encodestate import EncodeState from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire -from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from ..odxtypes import ParameterValue from ..utils import dataclass_fields_asdict from .parameter import Parameter, ParameterType @@ -60,31 +60,12 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: self._table_key = odxlinks.resolve(self.table_key_ref, TableKeyParameter) @override - @final - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - raise RuntimeError(f"Calling TableStructParameter._resolve_snref() is not allowed. " - f"Use ._table_struct_resolve_snrefs() instead.") - - def _table_struct_resolve_snrefs(self, diag_layer: "DiagLayer", *, - param_list: List[Parameter]) -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) if self.table_key_snref is not None: - tk_candidates = [p for p in param_list if p.short_name == self.table_key_snref] - if len(tk_candidates) > 1: - odxraise(f"Short name reference '{self.table_key_snref}' could " - f"not be uniquely resolved.") - elif len(tk_candidates) == 0: - odxraise(f"Short name reference '{self.table_key_snref}' could " - f"not be resolved.") - return - - tk = tk_candidates[0] - if not isinstance(tk, TableKeyParameter): - odxraise(f"Table struct '{self.short_name}' references non-TableKey parameter " - f"`{self.table_key_snref}' as its table key.") - - self._table_key = tk + self._table_key = resolve_snref(self.table_key_snref, param_list, TableKeyParameter) @property def table_key(self) -> TableKeyParameter: diff --git a/odxtools/parameters/valueparameter.py b/odxtools/parameters/valueparameter.py index b8737d91..1ef22d60 100644 --- a/odxtools/parameters/valueparameter.py +++ b/odxtools/parameters/valueparameter.py @@ -11,7 +11,7 @@ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId from ..odxtypes import AtomicOdxType, ParameterValue from ..utils import dataclass_fields_asdict -from .parameter import ParameterType +from .parameter import Parameter, ParameterType from .parameterwithdop import ParameterWithDOP if TYPE_CHECKING: @@ -50,8 +50,9 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: super()._resolve_odxlinks(odxlinks) @override - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - super()._resolve_snrefs(diag_layer) + def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *, + param_list: List[Parameter]) -> None: + super()._parameter_resolve_snrefs(diag_layer, param_list=param_list) if self.physical_default_value_raw is not None: dop = odxrequire(self.dop) diff --git a/odxtools/statechart.py b/odxtools/statechart.py index 24bdf42e..bd8bc9cd 100644 --- a/odxtools/statechart.py +++ b/odxtools/statechart.py @@ -6,7 +6,7 @@ from .element import IdentifiableElement from .exceptions import odxrequire from .nameditemlist import NamedItemList -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref from .state import State from .statetransition import StateTransition from .utils import dataclass_fields_asdict @@ -68,19 +68,15 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: for st in self.states: st._resolve_odxlinks(odxlinks) - # For now, we assume that the start state short name ref - # points to a state local to the state chart. TODO: The XML + def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: + # For now, we assume that the start state short name reference + # points to a local state of the state chart. TODO: The XSD # allows to define state charts without any states, yet the # start state SNREF is mandatory. Is this a gap in the spec or # does it allow "foreign" start states? If the latter, what # does that mean? - self._start_state: State - for st in self.states: - if st.short_name == self.start_state_snref: - self._start_state = st - break + self._start_state = resolve_snref(self.start_state_snref, self.states, State) - def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: for st in self.states: st._resolve_snrefs(diag_layer) diff --git a/odxtools/statetransition.py b/odxtools/statetransition.py index 5b40e131..bcc6930f 100644 --- a/odxtools/statetransition.py +++ b/odxtools/statetransition.py @@ -5,7 +5,7 @@ from .element import IdentifiableElement from .exceptions import odxrequire -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref from .state import State from .utils import dataclass_fields_asdict @@ -55,10 +55,5 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: # chart. To mitigate this a bit, the non-standard parameters are # keyword-only... def _resolve_snrefs(self, diag_layer: "DiagLayer", *, states: Iterable[State]) -> None: - self._source_state: State - self._target_state: State - for st in states: - if st.short_name == self.source_snref: - self._source_state = st - if st.short_name == self.target_snref: - self._target_state = st + self._source_state = resolve_snref(self.source_snref, states, State) + self._target_state = resolve_snref(self.target_snref, states, State) diff --git a/odxtools/tablerow.py b/odxtools/tablerow.py index 776f0e2c..242a6614 100644 --- a/odxtools/tablerow.py +++ b/odxtools/tablerow.py @@ -9,7 +9,7 @@ from .dtcdop import DtcDop from .element import IdentifiableElement from .exceptions import odxassert, odxraise, odxrequire -from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef +from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref from .odxtypes import AtomicOdxType from .specialdatagroup import SpecialDataGroup from .utils import dataclass_fields_asdict @@ -128,9 +128,11 @@ def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: ddd_spec = diag_layer.diag_data_dictionary_spec if self.structure_snref is not None: - self._structure = odxrequire(ddd_spec.structures.get(self.structure_snref)) + self._structure = resolve_snref(self.structure_snref, ddd_spec.structures, + BasicStructure) if self.dop_snref is not None: - self._dop = odxrequire(ddd_spec.data_object_props.get(self.dop_snref)) + self._dop = resolve_snref(self.dop_snref, ddd_spec.data_object_props, + DataObjectProperty) for sdg in self.sdgs: sdg._resolve_snrefs(diag_layer) diff --git a/tests/test_decoding.py b/tests/test_decoding.py index 9bea19e6..991228d5 100644 --- a/tests/test_decoding.py +++ b/tests/test_decoding.py @@ -2235,8 +2235,9 @@ def setUp(self) -> None: self.parameter_termination_end_of_pdu._resolve_odxlinks(odxlinks) self.parameter_sid._resolve_odxlinks(odxlinks) - self.parameter_termination_end_of_pdu._resolve_snrefs(None) # type: ignore[arg-type] - self.parameter_sid._resolve_snrefs(None) # type: ignore[arg-type] + self.parameter_termination_end_of_pdu._parameter_resolve_snrefs( + cast(DiagLayer, None), param_list=[]) + self.parameter_sid._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=[]) def test_min_max_length_type_end_of_pdu(self) -> None: req_param1 = self.parameter_sid @@ -2304,8 +2305,8 @@ def test_min_max_length_type_end_of_pdu_in_structure(self) -> None: req_param1._resolve_odxlinks(odxlinks) req_param2._resolve_odxlinks(odxlinks) - req_param1._resolve_snrefs(cast(DiagLayer, None)) - req_param2._resolve_snrefs(cast(DiagLayer, None)) + req_param1._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=[]) + req_param2._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=[]) expected_coded_message = bytes([0x12, 0x34]) expected_param_dict = { @@ -2398,8 +2399,8 @@ def test_physical_constant_parameter(self) -> None: req_param1._resolve_odxlinks(odxlinks) req_param2._resolve_odxlinks(odxlinks) - req_param1._resolve_snrefs(cast(DiagLayer, None)) - req_param2._resolve_snrefs(cast(DiagLayer, None)) + req_param1._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=[]) + req_param2._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=[]) expected_coded_message = bytes([0x12, 0x0]) expected_param_dict = {"SID": 0x12, "physical_constant_parameter": offset} diff --git a/tests/test_encoding.py b/tests/test_encoding.py index 6a4c217e..a882342a 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -170,7 +170,7 @@ def test_encode_linear(self) -> None: ) param1._resolve_odxlinks(odxlinks) - param1._resolve_snrefs(cast(DiagLayer, None)) + param1._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=req.parameters) # Missing mandatory parameter. with self.assertRaises(EncodeError): @@ -402,7 +402,7 @@ def test_bit_mask(self) -> None: sdgs=[], physical_default_value_raw=None) inner_param._resolve_odxlinks(odxlinks) - inner_param._resolve_snrefs(cast(DiagLayer, None)) + inner_param._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=[]) # Outer outer_param = ValueParameter( @@ -417,7 +417,7 @@ def test_bit_mask(self) -> None: sdgs=[], physical_default_value_raw=None) outer_param._resolve_odxlinks(odxlinks) - outer_param._resolve_snrefs(cast(DiagLayer, None)) + outer_param._parameter_resolve_snrefs(cast(DiagLayer, None), param_list=[]) req = self._create_request([inner_param, outer_param])