From bfcfd12373eff7a5434dd7ca6ffb9f18b2761fce Mon Sep 17 00:00:00 2001 From: Andreas Lauser Date: Fri, 1 Mar 2024 09:30:59 +0100 Subject: [PATCH] DiagDataDictionarySpec: some janitorial work - add the missing `admin_data` attribute - use the same order for all member attributes as the XSD uses for the corresponding subtags. Signed-off-by: Andreas Lauser Signed-off-by: Michael Hahn --- examples/somersaultecu.py | 2 + odxtools/diagdatadictionaryspec.py | 168 ++++++++++++++---------- odxtools/diaglayer.py | 1 + tests/test_decoding.py | 5 + tests/test_diag_coded_types.py | 3 + tests/test_diag_data_dictionary_spec.py | 1 + tests/test_unit_spec.py | 1 + 7 files changed, 109 insertions(+), 72 deletions(-) diff --git a/examples/somersaultecu.py b/examples/somersaultecu.py index b0b13a87..1991b971 100755 --- a/examples/somersaultecu.py +++ b/examples/somersaultecu.py @@ -2054,6 +2054,7 @@ class SomersaultSID(IntEnum): ] somersault_diag_data_dictionary_spec = DiagDataDictionarySpec( + admin_data=None, data_object_props=NamedItemList(somersault_dops.values()), unit_spec=UnitSpec( unit_groups=list(somersault_unit_groups.values()), @@ -2326,6 +2327,7 @@ class SomersaultSID(IntEnum): company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, dtc_dops=NamedItemList(), data_object_props=NamedItemList(), static_fields=NamedItemList(), diff --git a/odxtools/diagdatadictionaryspec.py b/odxtools/diagdatadictionaryspec.py index e1a1ede5..ab26e8ba 100644 --- a/odxtools/diagdatadictionaryspec.py +++ b/odxtools/diagdatadictionaryspec.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional from xml.etree import ElementTree +from .admindata import AdminData from .basicstructure import BasicStructure from .createsdgs import create_sdgs_from_et from .dataobjectproperty import DataObjectProperty @@ -29,37 +30,55 @@ @dataclass class DiagDataDictionarySpec: + admin_data: Optional[AdminData] dtc_dops: NamedItemList[DtcDop] + env_data_descs: NamedItemList[EnvironmentDataDescription] data_object_props: NamedItemList[DataObjectProperty] structures: NamedItemList[BasicStructure] - end_of_pdu_fields: NamedItemList[EndOfPduField] static_fields: NamedItemList[StaticField] dynamic_length_fields: NamedItemList[DynamicLengthField] - tables: NamedItemList[Table] - env_data_descs: NamedItemList[EnvironmentDataDescription] - env_datas: NamedItemList[EnvironmentData] + #dynamic_endmarker_fields: NamedItemList[DynamicEndmarkerField] + end_of_pdu_fields: NamedItemList[EndOfPduField] muxs: NamedItemList[Multiplexer] + env_datas: NamedItemList[EnvironmentData] unit_spec: Optional[UnitSpec] + tables: NamedItemList[Table] sdgs: List[SpecialDataGroup] def __post_init__(self) -> None: self._all_data_object_properties: NamedItemList[DopBase] = NamedItemList( chain( self.dtc_dops, + self.env_data_descs, self.data_object_props, self.structures, - self.end_of_pdu_fields, self.static_fields, self.dynamic_length_fields, - self.env_data_descs, - self.env_datas, + #self.dynamic_endmarker_fields, + self.end_of_pdu_fields, self.muxs, + self.env_datas, )) @staticmethod def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagDataDictionarySpec": - # Parse DOP-BASEs + admin_data = None + if (admin_data_elem := et_element.find("ADMIN-DATA")) is not None: + admin_data = AdminData.from_et(admin_data_elem, doc_frags) + + dtc_dops = [] + for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP"): + dtc_dop = DtcDop.from_et(dtc_dop_elem, doc_frags) + if not isinstance(dtc_dop, DtcDop): + odxraise() + dtc_dops.append(dtc_dop) + + env_data_descs = [ + EnvironmentDataDescription.from_et(env_data_desc_element, doc_frags) + for env_data_desc_element in et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC") + ] + data_object_props = [ DataObjectProperty.from_et(dop_element, doc_frags) for dop_element in et_element.iterfind("DATA-OBJECT-PROPS/DATA-OBJECT-PROP") @@ -70,11 +89,6 @@ def from_et(et_element: ElementTree.Element, for structure_element in et_element.iterfind("STRUCTURES/STRUCTURE") ] - end_of_pdu_fields = [ - EndOfPduField.from_et(eofp_element, doc_frags) - for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD") - ] - static_fields = [ StaticField.from_et(dl_element, doc_frags) for dl_element in et_element.iterfind("STATIC-FIELDS/STATIC-FIELD") @@ -85,21 +99,20 @@ def from_et(et_element: ElementTree.Element, for dl_element in et_element.iterfind("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD") ] - dtc_dops = [] - for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP"): - dtc_dop = DtcDop.from_et(dtc_dop_elem, doc_frags) - if not isinstance(dtc_dop, DtcDop): - odxraise() - dtc_dops.append(dtc_dop) + # TODO: dynamic endmarker fields + #dynamic_endmarker_fields = [ + # DynamicEndmarkerField.from_et(dl_element, doc_frags) + # for dl_element in et_element.iterfind("DYNAMIC-ENDMARKER-FIELDS/DYNAMIC-ENDMARKER-FIELD") + #] - tables = [ - Table.from_et(table_element, doc_frags) - for table_element in et_element.iterfind("TABLES/TABLE") + end_of_pdu_fields = [ + EndOfPduField.from_et(eofp_element, doc_frags) + for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD") ] - env_data_descs = [ - EnvironmentDataDescription.from_et(env_data_desc_element, doc_frags) - for env_data_desc_element in et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC") + muxs = [ + Multiplexer.from_et(mux_element, doc_frags) + for mux_element in et_element.iterfind("MUXS/MUX") ] env_data_elements = chain( @@ -112,30 +125,32 @@ def from_et(et_element: ElementTree.Element, for env_data_element in env_data_elements ] - muxs = [ - Multiplexer.from_et(mux_element, doc_frags) - for mux_element in et_element.iterfind("MUXS/MUX") - ] - if (spec_elem := et_element.find("UNIT-SPEC")) is not None: unit_spec = UnitSpec.from_et(spec_elem, doc_frags) else: unit_spec = None + tables = [ + Table.from_et(table_element, doc_frags) + for table_element in et_element.iterfind("TABLES/TABLE") + ] + sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags) return DiagDataDictionarySpec( + admin_data=admin_data, + dtc_dops=NamedItemList(dtc_dops), + env_data_descs=NamedItemList(env_data_descs), data_object_props=NamedItemList(data_object_props), structures=NamedItemList(structures), - end_of_pdu_fields=NamedItemList(end_of_pdu_fields), static_fields=NamedItemList(static_fields), dynamic_length_fields=NamedItemList(dynamic_length_fields), - dtc_dops=NamedItemList(dtc_dops), + #dynamic_endmarker_fields=NamedItemList(dynamic_endmarker_fields), + end_of_pdu_fields=NamedItemList(end_of_pdu_fields), + muxs=NamedItemList(muxs), + env_datas=NamedItemList(env_datas), unit_spec=unit_spec, tables=NamedItemList(tables), - env_data_descs=NamedItemList(env_data_descs), - env_datas=NamedItemList(env_datas), - muxs=NamedItemList(muxs), sdgs=sdgs, ) @@ -143,87 +158,96 @@ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: # note that DataDictionarySpec objects do not exhibit an ODXLINK id. odxlinks = {} - for data_object_prop in self.data_object_props: - odxlinks.update(data_object_prop._build_odxlinks()) + if self.admin_data is not None: + odxlinks.update(self.admin_data._build_odxlinks()) for dtc_dop in self.dtc_dops: odxlinks.update(dtc_dop._build_odxlinks()) for env_data_desc in self.env_data_descs: odxlinks.update(env_data_desc._build_odxlinks()) - for env_data in self.env_datas: - odxlinks.update(env_data._build_odxlinks()) - for mux in self.muxs: - odxlinks.update(mux._build_odxlinks()) - for sdg in self.sdgs: - odxlinks.update(sdg._build_odxlinks()) + for data_object_prop in self.data_object_props: + odxlinks.update(data_object_prop._build_odxlinks()) for structure in self.structures: odxlinks.update(structure._build_odxlinks()) for static_field in self.static_fields: odxlinks.update(static_field._build_odxlinks()) for dynamic_length_field in self.dynamic_length_fields: odxlinks.update(dynamic_length_field._build_odxlinks()) + #for dynamic_endmarker_field in self.dynamic_endmarker_fields: + # odxlinks.update(dynamic_endmarker_field._build_odxlinks()) for end_of_pdu_field in self.end_of_pdu_fields: odxlinks.update(end_of_pdu_field._build_odxlinks()) - for table in self.tables: - odxlinks.update(table._build_odxlinks()) - + for mux in self.muxs: + odxlinks.update(mux._build_odxlinks()) + for env_data in self.env_datas: + odxlinks.update(env_data._build_odxlinks()) if self.unit_spec is not None: odxlinks.update(self.unit_spec._build_odxlinks()) + for table in self.tables: + odxlinks.update(table._build_odxlinks()) + for sdg in self.sdgs: + odxlinks.update(sdg._build_odxlinks()) return odxlinks def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: - for data_object_prop in self.data_object_props: - data_object_prop._resolve_odxlinks(odxlinks) + if self.admin_data is not None: + self.admin_data._resolve_odxlinks(odxlinks) for dtc_dop in self.dtc_dops: dtc_dop._resolve_odxlinks(odxlinks) + for env_data_desc in self.env_data_descs: + env_data_desc._resolve_odxlinks(odxlinks) + for data_object_prop in self.data_object_props: + data_object_prop._resolve_odxlinks(odxlinks) + for structure in self.structures: + structure._resolve_odxlinks(odxlinks) for static_field in self.static_fields: static_field._resolve_odxlinks(odxlinks) for dynamic_length_field in self.dynamic_length_fields: dynamic_length_field._resolve_odxlinks(odxlinks) + #for dynamic_endmarker_field in self.dynamic_endmarker_fields: + # dynamic_endmarker_field._resolve_odxlinks(odxlinks) for end_of_pdu_field in self.end_of_pdu_fields: end_of_pdu_field._resolve_odxlinks(odxlinks) - for env_data_desc in self.env_data_descs: - env_data_desc._resolve_odxlinks(odxlinks) - for env_data in self.env_datas: - env_data._resolve_odxlinks(odxlinks) for mux in self.muxs: mux._resolve_odxlinks(odxlinks) - for sdg in self.sdgs: - sdg._resolve_odxlinks(odxlinks) - for structure in self.structures: - structure._resolve_odxlinks(odxlinks) - for table in self.tables: - table._resolve_odxlinks(odxlinks) - + for env_data in self.env_datas: + env_data._resolve_odxlinks(odxlinks) if self.unit_spec is not None: self.unit_spec._resolve_odxlinks(odxlinks) + for table in self.tables: + table._resolve_odxlinks(odxlinks) + for sdg in self.sdgs: + sdg._resolve_odxlinks(odxlinks) def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None: - for data_object_prop in self.data_object_props: - data_object_prop._resolve_snrefs(diag_layer) + if self.admin_data is not None: + self.admin_data._resolve_snrefs(diag_layer) for dtc_dop in self.dtc_dops: dtc_dop._resolve_snrefs(diag_layer) + for env_data_desc in self.env_data_descs: + env_data_desc._resolve_snrefs(diag_layer) + for data_object_prop in self.data_object_props: + data_object_prop._resolve_snrefs(diag_layer) + for structure in self.structures: + structure._resolve_snrefs(diag_layer) for static_field in self.static_fields: static_field._resolve_snrefs(diag_layer) for dynamic_length_field in self.dynamic_length_fields: dynamic_length_field._resolve_snrefs(diag_layer) + #for dynamic_endmarker_field in self.dynamic_endmarker_fields: + # dynamic_endmarker_field._resolve_snrefs(diag_layer) for end_of_pdu_field in self.end_of_pdu_fields: end_of_pdu_field._resolve_snrefs(diag_layer) - for env_data_desc in self.env_data_descs: - env_data_desc._resolve_snrefs(diag_layer) - for env_data in self.env_datas: - env_data._resolve_snrefs(diag_layer) for mux in self.muxs: mux._resolve_snrefs(diag_layer) - for sdg in self.sdgs: - sdg._resolve_snrefs(diag_layer) - for structure in self.structures: - structure._resolve_snrefs(diag_layer) - for table in self.tables: - table._resolve_snrefs(diag_layer) - + for env_data in self.env_datas: + env_data._resolve_snrefs(diag_layer) if self.unit_spec is not None: self.unit_spec._resolve_snrefs(diag_layer) + for table in self.tables: + table._resolve_snrefs(diag_layer) + for sdg in self.sdgs: + sdg._resolve_snrefs(diag_layer) @property def all_data_object_properties(self) -> NamedItemList[DopBase]: diff --git a/odxtools/diaglayer.py b/odxtools/diaglayer.py index aaef5791..14136c05 100644 --- a/odxtools/diaglayer.py +++ b/odxtools/diaglayer.py @@ -192,6 +192,7 @@ def _finalize_init(self, odxlinks: OdxLinkDatabase) -> None: # inherited objects. To me, this seems rather inelegant, but # hey, it's described like this in the standard. self._diag_data_dictionary_spec = DiagDataDictionarySpec( + admin_data=None, data_object_props=dops, dtc_dops=dtc_dops, structures=structures, diff --git a/tests/test_decoding.py b/tests/test_decoding.py index 922ca312..bd9df8be 100644 --- a/tests/test_decoding.py +++ b/tests/test_decoding.py @@ -652,6 +652,7 @@ def test_decode_request_structure(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, dtc_dops=NamedItemList(), data_object_props=NamedItemList([dop]), structures=NamedItemList([struct]), @@ -853,6 +854,7 @@ def test_static_field_coding(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, dtc_dops=NamedItemList(), data_object_props=NamedItemList([dop]), structures=NamedItemList([struct]), @@ -1075,6 +1077,7 @@ def test_dynamic_length_field_coding(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, dtc_dops=NamedItemList(), data_object_props=NamedItemList([dop]), structures=NamedItemList([struct]), @@ -1299,6 +1302,7 @@ def test_decode_request_end_of_pdu_field(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, dtc_dops=NamedItemList(), data_object_props=NamedItemList([dop]), structures=NamedItemList([struct]), @@ -1461,6 +1465,7 @@ def test_decode_request_linear_compu_method(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, dtc_dops=NamedItemList(), data_object_props=NamedItemList([dop]), structures=NamedItemList(), diff --git a/tests/test_diag_coded_types.py b/tests/test_diag_coded_types.py index 6ff0de34..061f72da 100644 --- a/tests/test_diag_coded_types.py +++ b/tests/test_diag_coded_types.py @@ -246,6 +246,7 @@ def test_end_to_end(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, data_object_props=NamedItemList(dops.values()), dtc_dops=NamedItemList(), structures=NamedItemList(), @@ -546,6 +547,7 @@ def test_end_to_end(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, data_object_props=NamedItemList(dops.values()), dtc_dops=NamedItemList(), structures=NamedItemList(), @@ -853,6 +855,7 @@ def test_end_to_end(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, data_object_props=NamedItemList(dops.values()), dtc_dops=NamedItemList(), structures=NamedItemList(), diff --git a/tests/test_diag_data_dictionary_spec.py b/tests/test_diag_data_dictionary_spec.py index f9d06542..6181cc4a 100644 --- a/tests/test_diag_data_dictionary_spec.py +++ b/tests/test_diag_data_dictionary_spec.py @@ -268,6 +268,7 @@ def test_initialization(self) -> None: ) ddds = DiagDataDictionarySpec( + admin_data=None, dtc_dops=NamedItemList([dtc_dop]), data_object_props=NamedItemList([dop_1, dop_2]), tables=NamedItemList([table]), diff --git a/tests/test_unit_spec.py b/tests/test_unit_spec.py index 67772529..1b2e13eb 100644 --- a/tests/test_unit_spec.py +++ b/tests/test_unit_spec.py @@ -132,6 +132,7 @@ def test_resolve_odxlinks(self) -> None: company_datas=NamedItemList(), functional_classes=NamedItemList(), diag_data_dictionary_spec=DiagDataDictionarySpec( + admin_data=None, data_object_props=NamedItemList([dop]), unit_spec=UnitSpec( units=[unit],