odxtools 9.5.0__py3-none-any.whl → 9.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. odxtools/additionalaudience.py +2 -2
  2. odxtools/admindata.py +3 -0
  3. odxtools/audience.py +9 -13
  4. odxtools/basecomparam.py +1 -2
  5. odxtools/basevariantpattern.py +5 -5
  6. odxtools/basicstructure.py +34 -35
  7. odxtools/commrelation.py +2 -1
  8. odxtools/companydata.py +1 -2
  9. odxtools/companyspecificinfo.py +3 -0
  10. odxtools/comparam.py +16 -8
  11. odxtools/comparaminstance.py +12 -12
  12. odxtools/comparamspec.py +4 -3
  13. odxtools/comparamsubset.py +26 -24
  14. odxtools/compumethods/compuconst.py +4 -4
  15. odxtools/compumethods/limit.py +9 -9
  16. odxtools/compumethods/linearsegment.py +8 -8
  17. odxtools/dataobjectproperty.py +16 -18
  18. odxtools/description.py +4 -2
  19. odxtools/determinenumberofitems.py +4 -4
  20. odxtools/diagcodedtype.py +20 -20
  21. odxtools/diagcomm.py +61 -41
  22. odxtools/diagdatadictionaryspec.py +51 -55
  23. odxtools/diaglayercontainer.py +25 -25
  24. odxtools/diaglayers/diaglayerraw.py +26 -27
  25. odxtools/diagnostictroublecode.py +13 -10
  26. odxtools/diagservice.py +48 -50
  27. odxtools/diagvariable.py +10 -8
  28. odxtools/docrevision.py +5 -5
  29. odxtools/dtcdop.py +17 -17
  30. odxtools/dynamicendmarkerfield.py +8 -8
  31. odxtools/dynamiclengthfield.py +2 -0
  32. odxtools/dyndefinedspec.py +21 -8
  33. odxtools/encodestate.py +1 -2
  34. odxtools/endofpdufield.py +7 -9
  35. odxtools/environmentdatadescription.py +9 -20
  36. odxtools/field.py +21 -21
  37. odxtools/inputparam.py +15 -14
  38. odxtools/leadinglengthinfotype.py +4 -4
  39. odxtools/matchingparameter.py +2 -3
  40. odxtools/minmaxlengthtype.py +7 -7
  41. odxtools/multiplexer.py +38 -39
  42. odxtools/multiplexercase.py +3 -6
  43. odxtools/multiplexerdefaultcase.py +3 -6
  44. odxtools/multiplexerswitchkey.py +4 -4
  45. odxtools/negoutputparam.py +6 -9
  46. odxtools/odxlink.py +21 -5
  47. odxtools/odxtypes.py +4 -4
  48. odxtools/outputparam.py +9 -8
  49. odxtools/parameterinfo.py +1 -1
  50. odxtools/parameters/codedconstparameter.py +28 -27
  51. odxtools/parameters/dynamicparameter.py +9 -9
  52. odxtools/parameters/lengthkeyparameter.py +18 -18
  53. odxtools/parameters/matchingrequestparameter.py +15 -15
  54. odxtools/parameters/nrcconstparameter.py +32 -24
  55. odxtools/parameters/parameter.py +35 -37
  56. odxtools/parameters/parameterwithdop.py +6 -6
  57. odxtools/parameters/physicalconstantparameter.py +19 -20
  58. odxtools/parameters/reservedparameter.py +10 -11
  59. odxtools/parameters/systemparameter.py +10 -11
  60. odxtools/parameters/tableentryparameter.py +19 -20
  61. odxtools/parameters/tablekeyparameter.py +0 -2
  62. odxtools/parameters/tablestructparameter.py +27 -21
  63. odxtools/parameters/valueparameter.py +20 -20
  64. odxtools/parentref.py +6 -7
  65. odxtools/physicaldimension.py +11 -11
  66. odxtools/physicaltype.py +9 -14
  67. odxtools/preconditionstateref.py +85 -0
  68. odxtools/progcode.py +1 -2
  69. odxtools/protstack.py +4 -4
  70. odxtools/relateddoc.py +3 -4
  71. odxtools/scaleconstr.py +0 -1
  72. odxtools/singleecujob.py +8 -4
  73. odxtools/specialdata.py +10 -9
  74. odxtools/specialdatagroup.py +1 -0
  75. odxtools/standardlengthtype.py +10 -10
  76. odxtools/statechart.py +10 -6
  77. odxtools/statemachine.py +186 -0
  78. odxtools/statetransitionref.py +231 -0
  79. odxtools/structure.py +4 -4
  80. odxtools/subcomponent.py +72 -8
  81. odxtools/table.py +23 -13
  82. odxtools/tablerow.py +86 -69
  83. odxtools/teammember.py +4 -4
  84. odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -2
  85. odxtools/templates/macros/printComparam.xml.jinja2 +3 -5
  86. odxtools/templates/macros/printDOP.xml.jinja2 +4 -1
  87. odxtools/templates/macros/printDiagComm.xml.jinja2 +6 -5
  88. odxtools/templates/macros/printParam.xml.jinja2 +5 -5
  89. odxtools/templates/macros/printPreConditionStateRef.xml.jinja2 +18 -0
  90. odxtools/templates/macros/printStateTransitionRef.xml.jinja2 +18 -0
  91. odxtools/templates/macros/printTable.xml.jinja2 +13 -9
  92. odxtools/text.py +35 -0
  93. odxtools/unit.py +1 -3
  94. odxtools/unitgroup.py +6 -8
  95. odxtools/utils.py +0 -4
  96. odxtools/version.py +2 -2
  97. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/METADATA +3 -2
  98. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/RECORD +102 -96
  99. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/WHEEL +1 -1
  100. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/entry_points.txt +0 -0
  101. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info/licenses}/LICENSE +0 -0
  102. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/top_level.txt +0 -0
@@ -13,11 +13,11 @@ from .encodestate import EncodeState
13
13
  from .exceptions import EncodeError, odxraise, odxrequire
14
14
  from .internalconstr import InternalConstr
15
15
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
16
- from .odxtypes import AtomicOdxType, ParameterValue
16
+ from .odxtypes import AtomicOdxType, BytesTypes, ParameterValue
17
17
  from .physicaltype import PhysicalType
18
18
  from .snrefcontext import SnRefContext
19
19
  from .unit import Unit
20
- from .utils import BytesTypes, dataclass_fields_asdict
20
+ from .utils import dataclass_fields_asdict
21
21
 
22
22
 
23
23
  @dataclass
@@ -28,21 +28,26 @@ class DataObjectProperty(DopBase):
28
28
  name would thus be SimpleDataObjectProp...
29
29
  """
30
30
 
31
+ #: Conversion from the physical to the internal representation and vice-versa.
32
+ compu_method: CompuMethod
33
+
31
34
  #: The type used to represent a value internally
32
35
  diag_coded_type: DiagCodedType
33
36
 
34
37
  #: The type of the value in the physical world
35
38
  physical_type: PhysicalType
36
39
 
37
- #: Conversion from the physical to the internal representation and vice-versa.
38
- compu_method: CompuMethod
40
+ internal_constr: Optional[InternalConstr]
39
41
 
40
42
  #: The unit associated with physical values (e.g. 'm/s^2')
41
43
  unit_ref: Optional[OdxLinkRef]
42
44
 
43
- internal_constr: Optional[InternalConstr]
44
45
  physical_constr: Optional[InternalConstr]
45
46
 
47
+ @property
48
+ def unit(self) -> Optional[Unit]:
49
+ return self._unit
50
+
46
51
  @staticmethod
47
52
  def from_et(et_element: ElementTree.Element,
48
53
  doc_frags: List[OdxDocFragment]) -> "DataObjectProperty":
@@ -51,7 +56,6 @@ class DataObjectProperty(DopBase):
51
56
 
52
57
  diag_coded_type = create_any_diag_coded_type_from_et(
53
58
  odxrequire(et_element.find("DIAG-CODED-TYPE")), doc_frags)
54
-
55
59
  physical_type = PhysicalType.from_et(
56
60
  odxrequire(et_element.find("PHYSICAL-TYPE")), doc_frags)
57
61
  compu_method = create_any_compu_method_from_et(
@@ -60,39 +64,37 @@ class DataObjectProperty(DopBase):
60
64
  internal_type=diag_coded_type.base_data_type,
61
65
  physical_type=physical_type.base_data_type,
62
66
  )
63
- unit_ref = OdxLinkRef.from_et(et_element.find("UNIT-REF"), doc_frags)
64
-
65
67
  internal_constr = None
66
68
  if (internal_constr_elem := et_element.find("INTERNAL-CONSTR")) is not None:
67
69
  internal_constr = InternalConstr.constr_from_et(
68
70
  internal_constr_elem, doc_frags, value_type=diag_coded_type.base_data_type)
69
-
71
+ unit_ref = OdxLinkRef.from_et(et_element.find("UNIT-REF"), doc_frags)
70
72
  physical_constr = None
71
73
  if (physical_constr_elem := et_element.find("PHYS-CONSTR")) is not None:
72
74
  physical_constr = InternalConstr.constr_from_et(
73
75
  physical_constr_elem, doc_frags, value_type=physical_type.base_data_type)
74
76
 
75
77
  return DataObjectProperty(
78
+ compu_method=compu_method,
76
79
  diag_coded_type=diag_coded_type,
77
80
  physical_type=physical_type,
78
- compu_method=compu_method,
79
- unit_ref=unit_ref,
80
81
  internal_constr=internal_constr,
82
+ unit_ref=unit_ref,
81
83
  physical_constr=physical_constr,
82
84
  **kwargs)
83
85
 
84
86
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
85
87
  result = super()._build_odxlinks()
86
- result.update(self.diag_coded_type._build_odxlinks())
87
88
  result.update(self.compu_method._build_odxlinks())
89
+ result.update(self.diag_coded_type._build_odxlinks())
88
90
  return result
89
91
 
90
92
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
91
93
  """Resolves the reference to the unit"""
92
94
  super()._resolve_odxlinks(odxlinks)
93
95
 
94
- self.diag_coded_type._resolve_odxlinks(odxlinks)
95
96
  self.compu_method._resolve_odxlinks(odxlinks)
97
+ self.diag_coded_type._resolve_odxlinks(odxlinks)
96
98
 
97
99
  self._unit: Optional[Unit] = None
98
100
  if self.unit_ref:
@@ -101,12 +103,8 @@ class DataObjectProperty(DopBase):
101
103
  def _resolve_snrefs(self, context: SnRefContext) -> None:
102
104
  super()._resolve_snrefs(context)
103
105
 
104
- self.diag_coded_type._resolve_snrefs(context)
105
106
  self.compu_method._resolve_snrefs(context)
106
-
107
- @property
108
- def unit(self) -> Optional[Unit]:
109
- return self._unit
107
+ self.diag_coded_type._resolve_snrefs(context)
110
108
 
111
109
  def get_static_bit_length(self) -> Optional[int]:
112
110
  return self.diag_coded_type.get_static_bit_length()
odxtools/description.py CHANGED
@@ -27,6 +27,7 @@ class ExternalDoc:
27
27
  class Description:
28
28
  text: str
29
29
  external_docs: List[ExternalDoc]
30
+
30
31
  text_identifier: Optional[str]
31
32
 
32
33
  @staticmethod
@@ -48,12 +49,13 @@ class Description:
48
49
 
49
50
  text = "\n".join(stripped_lines).strip()
50
51
 
51
- text_identifier = et_element.get("TI")
52
-
53
52
  external_docs = \
54
53
  [
55
54
  odxrequire(ExternalDoc.from_et(ed, doc_frags)) for ed in et_element.iterfind("EXTERNAL-DOCS/EXTERNAL-DOC")
56
55
  ]
56
+
57
+ text_identifier = et_element.attrib.get("TI")
58
+
57
59
  return Description(text=text, text_identifier=text_identifier, external_docs=external_docs)
58
60
 
59
61
  @staticmethod
@@ -18,6 +18,10 @@ class DetermineNumberOfItems:
18
18
  bit_position: Optional[int]
19
19
  dop_ref: OdxLinkRef
20
20
 
21
+ @property
22
+ def dop(self) -> DataObjectProperty:
23
+ return self._dop
24
+
21
25
  @staticmethod
22
26
  def from_et(et_element: ElementTree.Element,
23
27
  doc_frags: List[OdxDocFragment]) -> "DetermineNumberOfItems":
@@ -40,7 +44,3 @@ class DetermineNumberOfItems:
40
44
 
41
45
  def _resolve_snrefs(self, context: SnRefContext) -> None:
42
46
  pass
43
-
44
- @property
45
- def dop(self) -> DataObjectProperty:
46
- return self._dop
odxtools/diagcodedtype.py CHANGED
@@ -22,21 +22,24 @@ DctType = Literal[
22
22
 
23
23
  @dataclass
24
24
  class DiagCodedType:
25
-
26
- base_data_type: DataType
27
25
  base_type_encoding: Optional[Encoding]
26
+ base_data_type: DataType
27
+
28
28
  is_highlow_byte_order_raw: Optional[bool]
29
29
 
30
+ @property
31
+ def dct_type(self) -> DctType:
32
+ odxraise(f"Class {type(self).__name__} does not override required method "
33
+ f"dct_type()", NotImplementedError)
34
+ return cast(DctType, None)
35
+
36
+ @property
37
+ def is_highlow_byte_order(self) -> bool:
38
+ return self.is_highlow_byte_order_raw in [None, True]
39
+
30
40
  @staticmethod
31
41
  def from_et(et_element: ElementTree.Element,
32
42
  doc_frags: List[OdxDocFragment]) -> "DiagCodedType":
33
- base_data_type_str = odxrequire(et_element.get("BASE-DATA-TYPE"))
34
- try:
35
- base_data_type = DataType(base_data_type_str)
36
- except ValueError:
37
- odxraise(f"Unknown base data type {base_data_type_str}")
38
- base_data_type = cast(DataType, None)
39
-
40
43
  base_type_encoding = None
41
44
  if (base_type_encoding_str := et_element.get("BASE-TYPE-ENCODING")) is not None:
42
45
  try:
@@ -44,11 +47,18 @@ class DiagCodedType:
44
47
  except ValueError:
45
48
  odxraise(f"Encountered unknown BASE-TYPE-ENCODING '{base_type_encoding_str}'")
46
49
 
50
+ base_data_type_str = odxrequire(et_element.get("BASE-DATA-TYPE"))
51
+ try:
52
+ base_data_type = DataType(base_data_type_str)
53
+ except ValueError:
54
+ odxraise(f"Unknown base data type {base_data_type_str}")
55
+ base_data_type = cast(DataType, None)
56
+
47
57
  is_highlow_byte_order_raw = odxstr_to_bool(et_element.get("IS-HIGHLOW-BYTE-ORDER"))
48
58
 
49
59
  return DiagCodedType(
50
- base_data_type=base_data_type,
51
60
  base_type_encoding=base_type_encoding,
61
+ base_data_type=base_data_type,
52
62
  is_highlow_byte_order_raw=is_highlow_byte_order_raw)
53
63
 
54
64
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: # noqa: B027
@@ -65,16 +75,6 @@ class DiagCodedType:
65
75
  def get_static_bit_length(self) -> Optional[int]:
66
76
  return None
67
77
 
68
- @property
69
- def dct_type(self) -> DctType:
70
- odxraise(f"Class {type(self).__name__} does not override required method "
71
- f"dct_type()", NotImplementedError)
72
- return cast(DctType, None)
73
-
74
- @property
75
- def is_highlow_byte_order(self) -> bool:
76
- return self.is_highlow_byte_order_raw in [None, True]
77
-
78
78
  def _minimal_byte_length_of(self, internal_value: Union[bytes, str]) -> int:
79
79
  """Helper method to get the minimal byte length.
80
80
  (needed for LeadingLength- and MinMaxLengthType)
odxtools/diagcomm.py CHANGED
@@ -12,10 +12,12 @@ from .functionalclass import FunctionalClass
12
12
  from .nameditemlist import NamedItemList
13
13
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
14
14
  from .odxtypes import odxstr_to_bool
15
+ from .preconditionstateref import PreConditionStateRef
15
16
  from .snrefcontext import SnRefContext
16
17
  from .specialdatagroup import SpecialDataGroup
17
18
  from .state import State
18
19
  from .statetransition import StateTransition
20
+ from .statetransitionref import StateTransitionRef
19
21
  from .utils import dataclass_fields_asdict
20
22
 
21
23
  if TYPE_CHECKING:
@@ -61,8 +63,8 @@ class DiagComm(IdentifiableElement):
61
63
  audience: Optional[Audience]
62
64
  protocol_snrefs: List[str]
63
65
  related_diag_comm_refs: List[RelatedDiagCommRef]
64
- pre_condition_state_refs: List[OdxLinkRef]
65
- state_transition_refs: List[OdxLinkRef]
66
+ pre_condition_state_refs: List[PreConditionStateRef]
67
+ state_transition_refs: List[StateTransitionRef]
66
68
 
67
69
  # attributes
68
70
  semantic: Optional[str]
@@ -71,6 +73,38 @@ class DiagComm(IdentifiableElement):
71
73
  is_executable_raw: Optional[bool]
72
74
  is_final_raw: Optional[bool]
73
75
 
76
+ @property
77
+ def functional_classes(self) -> NamedItemList[FunctionalClass]:
78
+ return self._functional_classes
79
+
80
+ @property
81
+ def protocols(self) -> NamedItemList["Protocol"]:
82
+ return self._protocols
83
+
84
+ @property
85
+ def related_diag_comms(self) -> NamedItemList["DiagComm"]:
86
+ return self._related_diag_comms
87
+
88
+ @property
89
+ def pre_condition_states(self) -> NamedItemList[State]:
90
+ return self._pre_condition_states
91
+
92
+ @property
93
+ def state_transitions(self) -> NamedItemList[StateTransition]:
94
+ return self._state_transitions
95
+
96
+ @property
97
+ def is_mandatory(self) -> bool:
98
+ return self.is_mandatory_raw is True
99
+
100
+ @property
101
+ def is_executable(self) -> bool:
102
+ return self.is_executable_raw in (None, True)
103
+
104
+ @property
105
+ def is_final(self) -> bool:
106
+ return self.is_final_raw is True
107
+
74
108
  @staticmethod
75
109
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagComm":
76
110
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
@@ -100,27 +134,27 @@ class DiagComm(IdentifiableElement):
100
134
  ]
101
135
 
102
136
  pre_condition_state_refs = [
103
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
137
+ PreConditionStateRef.from_et(el, doc_frags)
104
138
  for el in et_element.iterfind("PRE-CONDITION-STATE-REFS/PRE-CONDITION-STATE-REF")
105
139
  ]
106
140
 
107
141
  state_transition_refs = [
108
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
142
+ StateTransitionRef.from_et(el, doc_frags)
109
143
  for el in et_element.iterfind("STATE-TRANSITION-REFS/STATE-TRANSITION-REF")
110
144
  ]
111
145
 
112
- semantic = et_element.get("SEMANTIC")
146
+ semantic = et_element.attrib.get("SEMANTIC")
113
147
 
114
148
  diagnostic_class: Optional[DiagClassType] = None
115
- if (diagnostic_class_str := et_element.get("DIAGNOSTIC-CLASS")) is not None:
149
+ if (diagnostic_class_str := et_element.attrib.get("DIAGNOSTIC-CLASS")) is not None:
116
150
  try:
117
151
  diagnostic_class = DiagClassType(diagnostic_class_str)
118
152
  except ValueError:
119
153
  odxraise(f"Encountered unknown diagnostic class type '{diagnostic_class_str}'")
120
154
 
121
- is_mandatory_raw = odxstr_to_bool(et_element.get("IS-MANDATORY"))
122
- is_executable_raw = odxstr_to_bool(et_element.get("IS-EXECUTABLE"))
123
- is_final_raw = odxstr_to_bool(et_element.get("IS-FINAL"))
155
+ is_mandatory_raw = odxstr_to_bool(et_element.attrib.get("IS-MANDATORY"))
156
+ is_executable_raw = odxstr_to_bool(et_element.attrib.get("IS-EXECUTABLE"))
157
+ is_final_raw = odxstr_to_bool(et_element.attrib.get("IS-FINAL"))
124
158
 
125
159
  return DiagComm(
126
160
  admin_data=admin_data,
@@ -138,38 +172,6 @@ class DiagComm(IdentifiableElement):
138
172
  is_final_raw=is_final_raw,
139
173
  **kwargs)
140
174
 
141
- @property
142
- def functional_classes(self) -> NamedItemList[FunctionalClass]:
143
- return self._functional_classes
144
-
145
- @property
146
- def protocols(self) -> NamedItemList["Protocol"]:
147
- return self._protocols
148
-
149
- @property
150
- def related_diag_comms(self) -> NamedItemList["DiagComm"]:
151
- return self._related_diag_comms
152
-
153
- @property
154
- def pre_condition_states(self) -> NamedItemList[State]:
155
- return self._pre_condition_states
156
-
157
- @property
158
- def state_transitions(self) -> NamedItemList[StateTransition]:
159
- return self._state_transitions
160
-
161
- @property
162
- def is_mandatory(self) -> bool:
163
- return self.is_mandatory_raw is True
164
-
165
- @property
166
- def is_executable(self) -> bool:
167
- return self.is_executable_raw in (None, True)
168
-
169
- @property
170
- def is_final(self) -> bool:
171
- return self.is_final_raw is True
172
-
173
175
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
174
176
  result = {self.odx_id: self}
175
177
 
@@ -182,6 +184,12 @@ class DiagComm(IdentifiableElement):
182
184
  if self.audience is not None:
183
185
  result.update(self.audience._build_odxlinks())
184
186
 
187
+ for pc_ref in self.pre_condition_state_refs:
188
+ result.update(pc_ref._build_odxlinks())
189
+
190
+ for st_ref in self.state_transition_refs:
191
+ result.update(st_ref._build_odxlinks())
192
+
185
193
  return result
186
194
 
187
195
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
@@ -194,6 +202,12 @@ class DiagComm(IdentifiableElement):
194
202
  for sdg in self.sdgs:
195
203
  sdg._resolve_odxlinks(odxlinks)
196
204
 
205
+ for pc_ref in self.pre_condition_state_refs:
206
+ pc_ref._resolve_odxlinks(odxlinks)
207
+
208
+ for st_ref in self.state_transition_refs:
209
+ st_ref._resolve_odxlinks(odxlinks)
210
+
197
211
  self._related_diag_comms = NamedItemList(
198
212
  [odxlinks.resolve(dc_ref, DiagComm) for dc_ref in self.related_diag_comm_refs])
199
213
  self._functional_classes = NamedItemList(
@@ -213,6 +227,12 @@ class DiagComm(IdentifiableElement):
213
227
  for sdg in self.sdgs:
214
228
  sdg._resolve_snrefs(context)
215
229
 
230
+ for pc_ref in self.pre_condition_state_refs:
231
+ pc_ref._resolve_snrefs(context)
232
+
233
+ for st_ref in self.state_transition_refs:
234
+ st_ref._resolve_snrefs(context)
235
+
216
236
  if TYPE_CHECKING:
217
237
  diag_layer = odxrequire(context.diag_layer)
218
238
  self._protocols = NamedItemList([
@@ -5,7 +5,6 @@ from typing import Any, Dict, List, Optional
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .admindata import AdminData
8
- from .basicstructure import BasicStructure
9
8
  from .dataobjectproperty import DataObjectProperty
10
9
  from .dopbase import DopBase
11
10
  from .dtcdop import DtcDop
@@ -14,7 +13,6 @@ from .dynamiclengthfield import DynamicLengthField
14
13
  from .endofpdufield import EndOfPduField
15
14
  from .environmentdata import EnvironmentData
16
15
  from .environmentdatadescription import EnvironmentDataDescription
17
- from .exceptions import odxraise
18
16
  from .multiplexer import Multiplexer
19
17
  from .nameditemlist import NamedItemList
20
18
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
@@ -32,7 +30,7 @@ class DiagDataDictionarySpec:
32
30
  dtc_dops: NamedItemList[DtcDop]
33
31
  env_data_descs: NamedItemList[EnvironmentDataDescription]
34
32
  data_object_props: NamedItemList[DataObjectProperty]
35
- structures: NamedItemList[BasicStructure]
33
+ structures: NamedItemList[Structure]
36
34
  static_fields: NamedItemList[StaticField]
37
35
  dynamic_length_fields: NamedItemList[DynamicLengthField]
38
36
  dynamic_endmarker_fields: NamedItemList[DynamicEndmarkerField]
@@ -43,21 +41,6 @@ class DiagDataDictionarySpec:
43
41
  tables: NamedItemList[Table]
44
42
  sdgs: List[SpecialDataGroup]
45
43
 
46
- def __post_init__(self) -> None:
47
- self._all_data_object_properties: NamedItemList[DopBase] = NamedItemList(
48
- chain(
49
- self.dtc_dops,
50
- self.env_data_descs,
51
- self.data_object_props,
52
- self.structures,
53
- self.static_fields,
54
- self.dynamic_length_fields,
55
- self.dynamic_endmarker_fields,
56
- self.end_of_pdu_fields,
57
- self.muxs,
58
- self.env_datas,
59
- ))
60
-
61
44
  @staticmethod
62
45
  def from_et(et_element: ElementTree.Element,
63
46
  doc_frags: List[OdxDocFragment]) -> "DiagDataDictionarySpec":
@@ -65,72 +48,70 @@ class DiagDataDictionarySpec:
65
48
  if (admin_data_elem := et_element.find("ADMIN-DATA")) is not None:
66
49
  admin_data = AdminData.from_et(admin_data_elem, doc_frags)
67
50
 
68
- dtc_dops = []
69
- for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP"):
70
- dtc_dop = DtcDop.from_et(dtc_dop_elem, doc_frags)
71
- if not isinstance(dtc_dop, DtcDop):
72
- odxraise()
73
- dtc_dops.append(dtc_dop)
51
+ dtc_dops = NamedItemList([
52
+ DtcDop.from_et(dtc_dop_elem, doc_frags)
53
+ for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP")
54
+ ])
74
55
 
75
- env_data_descs = [
56
+ env_data_descs = NamedItemList([
76
57
  EnvironmentDataDescription.from_et(env_data_desc_element, doc_frags)
77
58
  for env_data_desc_element in et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC")
78
- ]
59
+ ])
79
60
 
80
- data_object_props = [
61
+ data_object_props = NamedItemList([
81
62
  DataObjectProperty.from_et(dop_element, doc_frags)
82
63
  for dop_element in et_element.iterfind("DATA-OBJECT-PROPS/DATA-OBJECT-PROP")
83
- ]
64
+ ])
84
65
 
85
- structures = [
66
+ structures = NamedItemList([
86
67
  Structure.from_et(structure_element, doc_frags)
87
68
  for structure_element in et_element.iterfind("STRUCTURES/STRUCTURE")
88
- ]
69
+ ])
89
70
 
90
- static_fields = [
71
+ static_fields = NamedItemList([
91
72
  StaticField.from_et(dl_element, doc_frags)
92
73
  for dl_element in et_element.iterfind("STATIC-FIELDS/STATIC-FIELD")
93
- ]
74
+ ])
94
75
 
95
- dynamic_length_fields = [
76
+ dynamic_length_fields = NamedItemList([
96
77
  DynamicLengthField.from_et(dl_element, doc_frags)
97
78
  for dl_element in et_element.iterfind("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD")
98
- ]
79
+ ])
99
80
 
100
- dynamic_endmarker_fields = [
81
+ dynamic_endmarker_fields = NamedItemList([
101
82
  DynamicEndmarkerField.from_et(dl_element, doc_frags) for dl_element in
102
83
  et_element.iterfind("DYNAMIC-ENDMARKER-FIELDS/DYNAMIC-ENDMARKER-FIELD")
103
- ]
84
+ ])
104
85
 
105
- end_of_pdu_fields = [
86
+ end_of_pdu_fields = NamedItemList([
106
87
  EndOfPduField.from_et(eofp_element, doc_frags)
107
88
  for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD")
108
- ]
89
+ ])
109
90
 
110
- muxs = [
91
+ muxs = NamedItemList([
111
92
  Multiplexer.from_et(mux_element, doc_frags)
112
93
  for mux_element in et_element.iterfind("MUXS/MUX")
113
- ]
94
+ ])
114
95
 
115
96
  env_data_elements = chain(
116
97
  et_element.iterfind("ENV-DATAS/ENV-DATA"),
117
98
  # ODX 2.0.0 says ENV-DATA-DESC could contain a list of ENV-DATAS
118
99
  et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC/ENV-DATAS/ENV-DATA"),
119
100
  )
120
- env_datas = [
101
+ env_datas = NamedItemList([
121
102
  EnvironmentData.from_et(env_data_element, doc_frags)
122
103
  for env_data_element in env_data_elements
123
- ]
104
+ ])
124
105
 
125
106
  if (spec_elem := et_element.find("UNIT-SPEC")) is not None:
126
107
  unit_spec = UnitSpec.from_et(spec_elem, doc_frags)
127
108
  else:
128
109
  unit_spec = None
129
110
 
130
- tables = [
111
+ tables = NamedItemList([
131
112
  Table.from_et(table_element, doc_frags)
132
113
  for table_element in et_element.iterfind("TABLES/TABLE")
133
- ]
114
+ ])
134
115
 
135
116
  sdgs = [
136
117
  SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
@@ -138,21 +119,36 @@ class DiagDataDictionarySpec:
138
119
 
139
120
  return DiagDataDictionarySpec(
140
121
  admin_data=admin_data,
141
- dtc_dops=NamedItemList(dtc_dops),
142
- env_data_descs=NamedItemList(env_data_descs),
143
- data_object_props=NamedItemList(data_object_props),
144
- structures=NamedItemList(structures),
145
- static_fields=NamedItemList(static_fields),
146
- dynamic_length_fields=NamedItemList(dynamic_length_fields),
147
- dynamic_endmarker_fields=NamedItemList(dynamic_endmarker_fields),
148
- end_of_pdu_fields=NamedItemList(end_of_pdu_fields),
149
- muxs=NamedItemList(muxs),
150
- env_datas=NamedItemList(env_datas),
122
+ dtc_dops=dtc_dops,
123
+ env_data_descs=env_data_descs,
124
+ data_object_props=data_object_props,
125
+ structures=structures,
126
+ static_fields=static_fields,
127
+ dynamic_length_fields=dynamic_length_fields,
128
+ dynamic_endmarker_fields=dynamic_endmarker_fields,
129
+ end_of_pdu_fields=end_of_pdu_fields,
130
+ muxs=muxs,
131
+ env_datas=env_datas,
151
132
  unit_spec=unit_spec,
152
- tables=NamedItemList(tables),
133
+ tables=tables,
153
134
  sdgs=sdgs,
154
135
  )
155
136
 
137
+ def __post_init__(self) -> None:
138
+ self._all_data_object_properties: NamedItemList[DopBase] = NamedItemList(
139
+ chain(
140
+ self.dtc_dops,
141
+ self.env_data_descs,
142
+ self.data_object_props,
143
+ self.structures,
144
+ self.static_fields,
145
+ self.dynamic_length_fields,
146
+ self.dynamic_endmarker_fields,
147
+ self.end_of_pdu_fields,
148
+ self.muxs,
149
+ self.env_datas,
150
+ ))
151
+
156
152
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
157
153
  # note that DataDictionarySpec objects do not exhibit an ODXLINK id.
158
154
  odxlinks = {}