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
odxtools/tablerow.py CHANGED
@@ -5,7 +5,6 @@ from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
7
7
  from .audience import Audience
8
- from .basicstructure import BasicStructure
9
8
  from .dataobjectproperty import DataObjectProperty
10
9
  from .dtcdop import DtcDop
11
10
  from .element import IdentifiableElement
@@ -14,10 +13,11 @@ from .functionalclass import FunctionalClass
14
13
  from .nameditemlist import NamedItemList
15
14
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
16
15
  from .odxtypes import AtomicOdxType, odxstr_to_bool
16
+ from .preconditionstateref import PreConditionStateRef
17
17
  from .snrefcontext import SnRefContext
18
18
  from .specialdatagroup import SpecialDataGroup
19
- from .state import State
20
- from .statetransition import StateTransition
19
+ from .statetransitionref import StateTransitionRef
20
+ from .structure import Structure
21
21
  from .utils import dataclass_fields_asdict
22
22
 
23
23
  if TYPE_CHECKING:
@@ -27,8 +27,8 @@ if TYPE_CHECKING:
27
27
  @dataclass
28
28
  class TableRow(IdentifiableElement):
29
29
  """This class represents a TABLE-ROW."""
30
- key_raw: str
31
30
  table_ref: OdxLinkRef
31
+ key_raw: str
32
32
 
33
33
  # The spec mandates that either a structure or a non-complex DOP
34
34
  # must be referenced here, i.e., exactly one of the four
@@ -41,8 +41,8 @@ class TableRow(IdentifiableElement):
41
41
  sdgs: List[SpecialDataGroup]
42
42
  audience: Optional[Audience]
43
43
  functional_class_refs: List[OdxLinkRef]
44
- state_transition_refs: List[OdxLinkRef]
45
- pre_condition_state_refs: List[OdxLinkRef]
44
+ state_transition_refs: List[StateTransitionRef]
45
+ pre_condition_state_refs: List[PreConditionStateRef]
46
46
  admin_data: Optional[AdminData]
47
47
 
48
48
  is_executable_raw: Optional[bool]
@@ -51,16 +51,28 @@ class TableRow(IdentifiableElement):
51
51
  is_final_raw: Optional[bool]
52
52
 
53
53
  @property
54
- def functional_classes(self) -> NamedItemList[FunctionalClass]:
55
- return self._functional_classes
54
+ def table(self) -> "Table":
55
+ return self._table
56
+
57
+ # the value of the key expressed in the type represented by the
58
+ # referenced DOP
59
+ @property
60
+ def key(self) -> Optional[AtomicOdxType]:
61
+ return self._key
62
+
63
+ @property
64
+ def dop(self) -> Optional[DataObjectProperty]:
65
+ """The data object property object resolved by dop_ref."""
66
+ return self._dop
56
67
 
57
68
  @property
58
- def state_transitions(self) -> NamedItemList[StateTransition]:
59
- return self._state_transitions
69
+ def structure(self) -> Optional[Structure]:
70
+ """The structure associated with this table row."""
71
+ return self._structure
60
72
 
61
73
  @property
62
- def pre_condition_states(self) -> NamedItemList[State]:
63
- return self._pre_condition_states
74
+ def functional_classes(self) -> NamedItemList[FunctionalClass]:
75
+ return self._functional_classes
64
76
 
65
77
  @property
66
78
  def is_executable(self) -> bool:
@@ -74,21 +86,6 @@ class TableRow(IdentifiableElement):
74
86
  def is_final(self) -> bool:
75
87
  return self.is_final_raw is True
76
88
 
77
- def __post_init__(self) -> None:
78
- self._structure: Optional[BasicStructure] = None
79
- self._dop: Optional[DataObjectProperty] = None
80
-
81
- n = sum([0 if x is None else 1 for x in (self.structure_ref, self.structure_snref)])
82
- odxassert(
83
- n <= 1,
84
- f"Table row {self.short_name}: The structure can either be defined using ODXLINK or SNREF but not both."
85
- )
86
- n = sum([0 if x is None else 1 for x in (self.dop_ref, self.dop_snref)])
87
- odxassert(
88
- n <= 1,
89
- f"Table row {self.short_name}: The dop can either be defined using ODXLINK or SNREF but not both."
90
- )
91
-
92
89
  @staticmethod
93
90
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> Any:
94
91
  raise RuntimeError(
@@ -99,16 +96,19 @@ class TableRow(IdentifiableElement):
99
96
  table_ref: OdxLinkRef) -> "TableRow":
100
97
  """Reads a TABLE-ROW."""
101
98
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
102
- semantic = et_element.get("SEMANTIC")
99
+
103
100
  key_raw = odxrequire(et_element.findtext("KEY"))
104
- structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), doc_frags)
105
- structure_snref: Optional[str] = None
106
- if (structure_snref_elem := et_element.find("STRUCTURE-SNREF")) is not None:
107
- structure_snref = structure_snref_elem.attrib["SHORT-NAME"]
101
+
108
102
  dop_ref = OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), doc_frags)
109
103
  dop_snref: Optional[str] = None
110
104
  if (dop_snref_elem := et_element.find("DATA-OBJECT-PROP-SNREF")) is not None:
111
105
  dop_snref = dop_snref_elem.attrib["SHORT-NAME"]
106
+
107
+ structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), doc_frags)
108
+ structure_snref: Optional[str] = None
109
+ if (structure_snref_elem := et_element.find("STRUCTURE-SNREF")) is not None:
110
+ structure_snref = structure_snref_elem.attrib["SHORT-NAME"]
111
+
112
112
  sdgs = [
113
113
  SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
114
114
  ]
@@ -123,12 +123,12 @@ class TableRow(IdentifiableElement):
123
123
  ]
124
124
 
125
125
  state_transition_refs = [
126
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
126
+ StateTransitionRef.from_et(el, doc_frags)
127
127
  for el in et_element.iterfind("STATE-TRANSITION-REFS/STATE-TRANSITION-REF")
128
128
  ]
129
129
 
130
130
  pre_condition_state_refs = [
131
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
131
+ PreConditionStateRef.from_et(el, doc_frags)
132
132
  for el in et_element.iterfind("PRE-CONDITION-STATE-REFS/PRE-CONDITION-STATE-REF")
133
133
  ]
134
134
 
@@ -142,10 +142,10 @@ class TableRow(IdentifiableElement):
142
142
  return TableRow(
143
143
  table_ref=table_ref,
144
144
  key_raw=key_raw,
145
- structure_ref=structure_ref,
146
- structure_snref=structure_snref,
147
145
  dop_ref=dop_ref,
148
146
  dop_snref=dop_snref,
147
+ structure_ref=structure_ref,
148
+ structure_snref=structure_snref,
149
149
  sdgs=sdgs,
150
150
  audience=audience,
151
151
  functional_class_refs=functional_class_refs,
@@ -158,38 +158,66 @@ class TableRow(IdentifiableElement):
158
158
  is_final_raw=is_final_raw,
159
159
  **kwargs)
160
160
 
161
+ def __post_init__(self) -> None:
162
+ self._dop: Optional[DataObjectProperty] = None
163
+ self._structure: Optional[Structure] = None
164
+
165
+ n = sum([0 if x is None else 1 for x in (self.dop_ref, self.dop_snref)])
166
+ odxassert(
167
+ n <= 1,
168
+ f"Table row {self.short_name}: The dop can either be defined using ODXLINK or SNREF but not both."
169
+ )
170
+
171
+ n = sum([0 if x is None else 1 for x in (self.structure_ref, self.structure_snref)])
172
+ odxassert(
173
+ n <= 1,
174
+ f"Table row {self.short_name}: The structure can either be defined using ODXLINK or SNREF but not both."
175
+ )
176
+
161
177
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
162
178
  result = {self.odx_id: self}
163
179
 
164
180
  for sdg in self.sdgs:
165
181
  result.update(sdg._build_odxlinks())
166
182
 
183
+ if self.audience is not None:
184
+ result.update(self.audience._build_odxlinks())
185
+
186
+ for st_ref in self.state_transition_refs:
187
+ result.update(st_ref._build_odxlinks())
188
+
189
+ for pc_ref in self.pre_condition_state_refs:
190
+ result.update(pc_ref._build_odxlinks())
191
+
167
192
  return result
168
193
 
169
194
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
170
- if self.structure_ref is not None:
171
- self._structure = odxlinks.resolve(self.structure_ref, BasicStructure)
172
- if self.dop_ref is not None:
173
- self._dop = odxlinks.resolve(self.dop_ref)
174
- if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
175
- odxraise("The DOP-REF of TABLE-ROWs must reference a simple DOP!")
176
-
177
195
  if TYPE_CHECKING:
178
196
  self._table = odxlinks.resolve(self.table_ref, Table)
179
197
  else:
180
198
  self._table = odxlinks.resolve(self.table_ref)
181
199
 
200
+ if self.dop_ref is not None:
201
+ self._dop = odxlinks.resolve(self.dop_ref)
202
+ if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
203
+ odxraise("The DOP-REF of TABLE-ROWs must reference a simple DOP!")
204
+ if self.structure_ref is not None:
205
+ self._structure = odxlinks.resolve(self.structure_ref, Structure)
206
+
182
207
  for sdg in self.sdgs:
183
208
  sdg._resolve_odxlinks(odxlinks)
184
209
 
210
+ if self.audience is not None:
211
+ self.audience._resolve_odxlinks(odxlinks)
212
+
185
213
  self._functional_classes = NamedItemList(
186
214
  [odxlinks.resolve(fc_ref, FunctionalClass) for fc_ref in self.functional_class_refs])
187
215
 
188
- self._state_transitions = NamedItemList(
189
- [odxlinks.resolve(st_ref, StateTransition) for st_ref in self.state_transition_refs])
216
+ for st_ref in self.state_transition_refs:
217
+ st_ref._resolve_odxlinks(odxlinks)
190
218
 
191
- self._pre_condition_states = NamedItemList(
192
- [odxlinks.resolve(pcs_ref, State) for pcs_ref in self.pre_condition_state_refs])
219
+ for pc_ref in self.pre_condition_state_refs:
220
+ pc_ref._resolve_odxlinks(odxlinks)
193
221
 
194
222
  def _resolve_snrefs(self, context: SnRefContext) -> None:
195
223
  # convert the raw key into the proper internal
@@ -212,34 +240,23 @@ class TableRow(IdentifiableElement):
212
240
  ddd_spec = odxrequire(context.diag_layer).diag_data_dictionary_spec
213
241
 
214
242
  if self.structure_snref is not None:
215
- self._structure = resolve_snref(self.structure_snref, ddd_spec.structures,
216
- BasicStructure)
243
+ self._structure = resolve_snref(self.structure_snref, ddd_spec.structures, Structure)
217
244
  if self.dop_snref is not None:
218
- self._dop = resolve_snref(self.dop_snref, ddd_spec.data_object_props,
219
- DataObjectProperty)
245
+ self._dop = resolve_snref(self.dop_snref, ddd_spec.data_object_props)
246
+ if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
247
+ odxraise("The DOP-SNREF of TABLE-ROWs must reference a simple DOP!")
248
+
249
+ if self.audience is not None:
250
+ self.audience._resolve_snrefs(context)
220
251
 
221
252
  for sdg in self.sdgs:
222
253
  sdg._resolve_snrefs(context)
223
254
 
224
- @property
225
- def table(self) -> "Table":
226
- return self._table
255
+ for st_ref in self.state_transition_refs:
256
+ st_ref._resolve_snrefs(context)
227
257
 
228
- # the value of the key expressed in the type represented by the
229
- # referenced DOP
230
- @property
231
- def key(self) -> Optional[AtomicOdxType]:
232
- return self._key
233
-
234
- @property
235
- def structure(self) -> Optional[BasicStructure]:
236
- """The structure associated with this table row."""
237
- return self._structure
238
-
239
- @property
240
- def dop(self) -> Optional[DataObjectProperty]:
241
- """The data object property object resolved by dop_ref."""
242
- return self._dop
258
+ for pc_ref in self.pre_condition_state_refs:
259
+ pc_ref._resolve_snrefs(context)
243
260
 
244
261
  def __reduce__(self) -> Tuple[Any, ...]:
245
262
  """This ensures that the object can be correctly reconstructed during unpickling."""
odxtools/teammember.py CHANGED
@@ -15,7 +15,7 @@ class TeamMember(IdentifiableElement):
15
15
  roles: List[str]
16
16
  department: Optional[str]
17
17
  address: Optional[str]
18
- zip: Optional[str]
18
+ zipcode: Optional[str] # the tag for this is "ZIP", but `zip` is a keyword in python
19
19
  city: Optional[str]
20
20
  phone: Optional[str]
21
21
  fax: Optional[str]
@@ -24,11 +24,11 @@ class TeamMember(IdentifiableElement):
24
24
  @staticmethod
25
25
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "TeamMember":
26
26
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
27
- roles = [odxrequire(role_elem.text) for role_elem in et_element.iterfind("ROLES/ROLE")]
28
27
 
28
+ roles = [odxrequire(role_elem.text) for role_elem in et_element.iterfind("ROLES/ROLE")]
29
29
  department = et_element.findtext("DEPARTMENT")
30
30
  address = et_element.findtext("ADDRESS")
31
- zip = et_element.findtext("ZIP")
31
+ zipcode = et_element.findtext("ZIP")
32
32
  city = et_element.findtext("CITY")
33
33
  phone = et_element.findtext("PHONE")
34
34
  fax = et_element.findtext("FAX")
@@ -38,7 +38,7 @@ class TeamMember(IdentifiableElement):
38
38
  roles=roles,
39
39
  department=department,
40
40
  address=address,
41
- zip=zip,
41
+ zipcode=zipcode,
42
42
  city=city,
43
43
  phone=phone,
44
44
  fax=fax,
@@ -35,8 +35,8 @@
35
35
  {%- if team_member.address is not none %}
36
36
  <ADDRESS>{{team_member.address|e}}</ADDRESS>
37
37
  {%- endif %}
38
- {%- if team_member.zip is not none %}
39
- <ZIP>{{team_member.zip|e}}</ZIP>
38
+ {%- if team_member.zipcode is not none %}
39
+ <ZIP>{{team_member.zipcode|e}}</ZIP>
40
40
  {%- endif %}
41
41
  {%- if team_member.city is not none %}
42
42
  <CITY>{{team_member.city|e}}</CITY>
@@ -44,9 +44,7 @@
44
44
  {{make_xml_attrib("DISPLAY-LEVEL", cp.display_level)}}{#- #}
45
45
  CPUSAGE="{{cp.cpusage.value}}">
46
46
  {{ peid.printElementIdSubtags(cp)|indent(1) }}
47
- {%- if cp.physical_default_value is not none %}
48
- <PHYSICAL-DEFAULT-VALUE>{{cp.physical_default_value | e}}</PHYSICAL-DEFAULT-VALUE>
49
- {%- endif %}
47
+ <PHYSICAL-DEFAULT-VALUE>{{cp.physical_default_value_raw}}</PHYSICAL-DEFAULT-VALUE>
50
48
  <DATA-OBJECT-PROP-REF ID-REF="{{cp.dop_ref.ref_id}}" />
51
49
  </COMPARAM>
52
50
  {%- endmacro %}
@@ -55,9 +53,9 @@
55
53
  <COMPLEX-COMPARAM {{-peid.printElementIdAttribs(cp)}}
56
54
  PARAM-CLASS="{{cp.param_class}}"
57
55
  CPTYPE="{{cp.cptype.value}}"
58
- {{make_xml_attrib("DISPLAY-LEVEL", cp.display_level)}}{#- #}
56
+ {{make_xml_attrib("DISPLAY-LEVEL", cp.display_level)}}{#- #}
59
57
  CPUSAGE="{{cp.cpusage.value}}"
60
- {{make_bool_xml_attrib("ALLOW-MULTIPLE-VALUES", cp.allow_multiple_values_raw)}}
58
+ {{make_bool_xml_attrib("ALLOW-MULTIPLE-VALUES", cp.allow_multiple_values_raw)}}
61
59
  {#- #}>
62
60
  {{ peid.printElementIdSubtags(cp)|indent(1) }}
63
61
  {%- for sub_cp in cp.subparams %}
@@ -17,6 +17,9 @@
17
17
  {%- if dct.termination is defined %}
18
18
  {{-make_xml_attrib("TERMINATION", dct.termination.value)}}
19
19
  {%- endif %}
20
+ {%- if dct.is_condensed_raw is defined %}
21
+ {{-make_bool_xml_attrib("CONDENSED", dct.is_condensed_raw)}}
22
+ {%- endif %}
20
23
  {#- #} xsi:type="{{dct.dct_type}}">
21
24
  {%- if dct.dct_type in ("STANDARD-LENGTH-TYPE", "LEADING-LENGTH-INFO-TYPE") %}
22
25
  <BIT-LENGTH>{{dct.bit_length}}</BIT-LENGTH>
@@ -136,7 +139,7 @@
136
139
  {%- if dtc.display_trouble_code is not none %}
137
140
  <DISPLAY-TROUBLE-CODE>{{dtc.display_trouble_code}}</DISPLAY-TROUBLE-CODE>
138
141
  {%- endif %}
139
- <TEXT>{{dtc.text|e}}</TEXT>
142
+ <TEXT {{- make_xml_attrib("TI", dtc.text.text_identifier) }}>{{dtc.text|e}}</TEXT>
140
143
  {%- if not dtc.level is none %}
141
144
  <LEVEL>{{dtc.level}}</LEVEL>
142
145
  {%- endif %}
@@ -7,6 +7,8 @@
7
7
  {%- import('macros/printAdminData.xml.jinja2') as pad %}
8
8
  {%- import('macros/printAudience.xml.jinja2') as paud %}
9
9
  {%- import('macros/printSpecialData.xml.jinja2') as psd %}
10
+ {%- import('macros/printPreConditionStateRef.xml.jinja2') as ppcsr %}
11
+ {%- import('macros/printStateTransitionRef.xml.jinja2') as pstr %}
10
12
 
11
13
  {%- macro printDiagCommAttribs(dc) -%}
12
14
  {{-peid.printElementIdAttribs(dc)}}
@@ -17,7 +19,6 @@
17
19
  {{-make_bool_xml_attrib("IS-FINAL", dc.is_final_raw)}}
18
20
  {%- endmacro -%}
19
21
 
20
-
21
22
  {%- macro printDiagCommSubtags(dc) -%}
22
23
  {{ peid.printElementIdSubtags(dc)|indent(1) }}
23
24
  {%- if dc.admin_data %}
@@ -53,15 +54,15 @@
53
54
  {%- if dc.pre_condition_state_refs %}
54
55
  <PRE-CONDITION-STATE-REFS>
55
56
  {%- for ps_ref in dc.pre_condition_state_refs %}
56
- <PRE-CONDITION-STATE-REF ID-REF="{{ps_ref.ref_id}}" />
57
+ {{ ppcsr.printPreConditionStateRef(ps_ref)|indent(2) }}
57
58
  {%- endfor %}
58
59
  </PRE-CONDITION-STATE-REFS>
59
60
  {%- endif%}
60
61
  {%- if dc.state_transition_refs %}
61
62
  <STATE-TRANSITION-REFS>
62
- {%- for st_ref in dc.state_transition_refs %}
63
- <STATE-TRANSITION-REF ID-REF="{{st_ref.ref_id}}" />
64
- {%- endfor %}
63
+ {%- for st_ref in dc.state_transition_refs %}
64
+ {{ pstr.printStateTransitionRef(st_ref)|indent(2) }}
65
+ {%- endfor %}
65
66
  </STATE-TRANSITION-REFS>
66
67
  {%- endif%}
67
68
  {%- endmacro -%}
@@ -33,12 +33,12 @@
33
33
  {%- if param.byte_length is defined and param.byte_length is not none %}
34
34
  <BYTE-LENGTH>{{param.byte_length}}</BYTE-LENGTH>
35
35
  {%- endif %}
36
- {%- if param.coded_value is defined %}
37
- <CODED-VALUE>{{param.coded_value}}</CODED-VALUE>
38
- {%- elif param.coded_values is defined %}
36
+ {%- if param.coded_value_raw is defined %}
37
+ <CODED-VALUE>{{param.coded_value_raw}}</CODED-VALUE>
38
+ {%- elif param.coded_values_raw is defined %}
39
39
  <CODED-VALUES>
40
- {%- for coded_value in param.coded_values %}
41
- <CODED-VALUE>{{coded_value}}</CODED-VALUE>
40
+ {%- for coded_value_raw in param.coded_values_raw %}
41
+ <CODED-VALUE>{{coded_value_raw}}</CODED-VALUE>
42
42
  {%- endfor %}
43
43
  </CODED-VALUES>
44
44
  {%- endif %}
@@ -0,0 +1,18 @@
1
+ {#- -*- mode: sgml; tab-width: 1; indent-tabs-mode: nil -*-
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ -#}
5
+
6
+ {%- macro printPreConditionStateRef(ps_ref) -%}
7
+ <PRE-CONDITION-STATE-REF ID-REF="{{ps_ref.ref_id}}">
8
+ {%- if ps_ref.value is not none %}
9
+ <VALUE>{{ ps_ref.value }}</VALUE>
10
+ {%- endif %}
11
+ {%- if ps_ref.in_param_if_snref is not none %}
12
+ <IN-PARAM-IF-SNREF SHORT-NAME="{{ ps_ref.in_param_if_snref }}" />
13
+ {%- endif %}
14
+ {%- if ps_ref.in_param_if_snpathref is not none %}
15
+ <IN-PARAM-IF-SNPATHREF SHORT-NAME-PATH="{{ ps_ref.in_param_if_snpathref }}" />
16
+ {%- endif %}
17
+ </PRE-CONDITION-STATE-REF>
18
+ {%- endmacro -%}
@@ -0,0 +1,18 @@
1
+ {#- -*- mode: sgml; tab-width: 1; indent-tabs-mode: nil -*-
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ -#}
5
+
6
+ {%- macro printStateTransitionRef(st_ref) -%}
7
+ <STATE-TRANSITION-REF ID-REF="{{st_ref.ref_id}}">
8
+ {%- if st_ref.value is not none %}
9
+ <VALUE>{{ st_ref.value }}</VALUE>
10
+ {%- endif %}
11
+ {%- if st_ref.in_param_if_snref is not none %}
12
+ <IN-PARAM-IF-SNREF SHORT-NAME="{{ st_ref.in_param_if_snref }}" />
13
+ {%- endif %}
14
+ {%- if st_ref.in_param_if_snpathref is not none %}
15
+ <IN-PARAM-IF-SNPATHREF SHORT-NAME-PATH="{{ st_ref.in_param_if_snpathref }}" />
16
+ {%- endif %}
17
+ </STATE-TRANSITION-REF>
18
+ {%- endmacro -%}
@@ -8,6 +8,8 @@
8
8
  {%- import('macros/printDescription.xml.jinja2') as pd %}
9
9
  {%- import('macros/printAdminData.xml.jinja2') as pad %}
10
10
  {%- import('macros/printAudience.xml.jinja2') as paud %}
11
+ {%- import('macros/printPreConditionStateRef.xml.jinja2') as ppcsr %}
12
+ {%- import('macros/printStateTransitionRef.xml.jinja2') as pstr %}
11
13
 
12
14
  {%- macro printTable(table) %}
13
15
  <TABLE {{-peid.printElementIdAttribs(table)}}
@@ -20,18 +22,20 @@
20
22
  {%- if hasattr(table_row, "key") %}
21
23
  <TABLE-ROW {{-peid.printElementIdAttribs(table_row)}}
22
24
  {{-make_xml_attrib("SEMANTIC", table_row.semantic)}}>
23
- <SHORT-NAME>{{table_row.short_name}}</SHORT-NAME>
24
- {%- if table_row.long_name %}
25
- <LONG-NAME>{{table_row.long_name|e}}</LONG-NAME>
26
- {%- endif %}
27
- {{ pd.printDescription(table_row.description) }}
25
+ {{-peid.printElementIdSubtags(table_row)}}
28
26
  <KEY>{{table_row.key|e}}</KEY>
29
- {%- if table_row.dop_ref %}
27
+ {%- if table_row.dop_ref is not none %}
30
28
  <DATA-OBJECT-PROP-REF ID-REF="{{ table_row.dop_ref.ref_id }}" />
31
29
  {%- endif %}
32
- {%- if table_row.structure_ref %}
30
+ {%- if table_row.dop_snref is not none %}
31
+ <DATA-OBJECT-PROP-SNREF SHORT-NAME="{{ table_row.dop_snref }}" />
32
+ {%- endif %}
33
+ {%- if table_row.structure_ref is not none %}
33
34
  <STRUCTURE-REF ID-REF="{{ table_row.structure_ref.ref_id }}" />
34
35
  {%- endif %}
36
+ {%- if table_row.structure_snref is not none %}
37
+ <STRUCTURE-SNREF SHORT-NAME="{{ table_row.structure_snref }}" />
38
+ {%- endif %}
35
39
  {{- psd.printSpecialDataGroups(table_row.sdgs)|indent(2, first=True) }}
36
40
  {%- if table_row.audience is not none %}
37
41
  {{ paud.printAudience(table_row.audience) | indent(2) }}
@@ -46,14 +50,14 @@
46
50
  {%- if table_row.state_transition_refs %}
47
51
  <STATE-TRANSITION-REFS>
48
52
  {%- for st_ref in table_row.state_transition_refs %}
49
- <STATE-TRANSITION-REF ID-REF="{{ st_ref.ref_id }}" />
53
+ {{ pstr.printStateTransitionRef(st_ref)|indent(4) }}
50
54
  {%- endfor %}
51
55
  </STATE-TRANSITION-REFS>
52
56
  {%- endif %}
53
57
  {%- if table_row.pre_condition_state_refs %}
54
58
  <PRE-CONDITION-STATE-REFS>
55
59
  {%- for pcs_ref in table_row.pre_condition_state_refs %}
56
- <PRE-CONDITION-STATE-REF ID-REF="{{ pcs_ref.ref_id }}" />
60
+ {{ ppcsr.printPreConditionStateRef(ps_ref)|indent(4) }}
57
61
  {%- endfor %}
58
62
  </PRE-CONDITION-STATE-REFS>
59
63
  {%- endif %}
odxtools/text.py ADDED
@@ -0,0 +1,35 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Optional
3
+ from xml.etree import ElementTree
4
+
5
+ from .odxlink import OdxDocFragment
6
+
7
+
8
+ @dataclass
9
+ class Text:
10
+ text: str
11
+ text_identifier: Optional[str]
12
+
13
+ @staticmethod
14
+ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Text":
15
+ # Extract the contents of the tag as a string.
16
+ raw_string = et_element.text or ""
17
+ for e in et_element:
18
+ raw_string += ElementTree.tostring(e, encoding="unicode")
19
+
20
+ # remove white spaces at the beginning and at the end of all
21
+ # extracted lines
22
+ stripped_lines = [x.strip() for x in raw_string.split("\n")]
23
+
24
+ text = "\n".join(stripped_lines).strip()
25
+
26
+ text_identifier = et_element.get("TI")
27
+
28
+ return Text(text=text, text_identifier=text_identifier)
29
+
30
+ @staticmethod
31
+ def from_string(text: str) -> "Text":
32
+ return Text(text=text, text_identifier=None)
33
+
34
+ def __str__(self) -> str:
35
+ return self.text
odxtools/unit.py CHANGED
@@ -61,9 +61,6 @@ class Unit(IdentifiableElement):
61
61
  def physical_dimension(self) -> Optional[PhysicalDimension]:
62
62
  return self._physical_dimension
63
63
 
64
- def __post_init__(self) -> None:
65
- self._physical_dimension: Optional[PhysicalDimension] = None
66
-
67
64
  @staticmethod
68
65
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Unit":
69
66
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
@@ -92,6 +89,7 @@ class Unit(IdentifiableElement):
92
89
  return {self.odx_id: self}
93
90
 
94
91
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
92
+ self._physical_dimension: Optional[PhysicalDimension] = None
95
93
  if self.physical_dimension_ref:
96
94
  self._physical_dimension = odxlinks.resolve(self.physical_dimension_ref,
97
95
  PhysicalDimension)
odxtools/unitgroup.py CHANGED
@@ -28,13 +28,14 @@ class UnitGroup(NamedElement):
28
28
  unit_refs: List[OdxLinkRef]
29
29
  oid: Optional[str]
30
30
 
31
- def __post_init__(self) -> None:
32
- self._units = NamedItemList[Unit]()
31
+ @property
32
+ def units(self) -> NamedItemList[Unit]:
33
+ return self._units
33
34
 
34
35
  @staticmethod
35
36
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "UnitGroup":
36
- oid = et_element.get("OID")
37
37
  kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
38
+
38
39
  category_str = odxrequire(et_element.findtext("CATEGORY"))
39
40
  try:
40
41
  category = UnitGroupCategory(category_str)
@@ -42,10 +43,11 @@ class UnitGroup(NamedElement):
42
43
  category = cast(UnitGroupCategory, None)
43
44
  odxraise(f"Encountered unknown unit group category '{category_str}'")
44
45
 
45
- unit_refs: List[OdxLinkRef] = [
46
+ unit_refs = [
46
47
  odxrequire(OdxLinkRef.from_et(el, doc_frags))
47
48
  for el in et_element.iterfind("UNIT-REFS/UNIT-REF")
48
49
  ]
50
+ oid = et_element.get("OID")
49
51
 
50
52
  return UnitGroup(category=category, unit_refs=unit_refs, oid=oid, **kwargs)
51
53
 
@@ -57,7 +59,3 @@ class UnitGroup(NamedElement):
57
59
 
58
60
  def _resolve_snrefs(self, context: SnRefContext) -> None:
59
61
  pass
60
-
61
- @property
62
- def units(self) -> NamedItemList[Unit]:
63
- return self._units
odxtools/utils.py CHANGED
@@ -3,15 +3,11 @@ import dataclasses
3
3
  import re
4
4
  from typing import TYPE_CHECKING, Any, Dict, Optional
5
5
 
6
- from typing_extensions import SupportsBytes
7
-
8
6
  if TYPE_CHECKING:
9
7
  from .database import Database
10
8
  from .diaglayers.diaglayer import DiagLayer
11
9
  from .snrefcontext import SnRefContext
12
10
 
13
- BytesTypes = (bytearray, bytes, SupportsBytes)
14
-
15
11
 
16
12
  def retarget_snrefs(database: "Database",
17
13
  diag_layer: "DiagLayer",
odxtools/version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '9.5.0'
21
- __version_tuple__ = version_tuple = (9, 5, 0)
20
+ __version__ = version = '9.6.0'
21
+ __version_tuple__ = version_tuple = (9, 6, 0)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: odxtools
3
- Version: 9.5.0
3
+ Version: 9.6.0
4
4
  Summary: Utilities to work with the ODX standard for automotive diagnostics
5
5
  Author-email: Katrin Bauer <katrin.bauer@mbition.io>, Andreas Lauser <andreas.lauser@mbition.io>, Ayoub Kaanich <kayoub5@live.com>
6
6
  Maintainer-email: Andreas Lauser <andreas.lauser@mbition.io>, Ayoub Kaanich <kayoub5@live.com>
@@ -43,6 +43,7 @@ Provides-Extra: examples
43
43
  Requires-Dist: can-isotp>=1.9; extra == "examples"
44
44
  Provides-Extra: all
45
45
  Requires-Dist: odxtools[browse-tool,examples,test]; extra == "all"
46
+ Dynamic: license-file
46
47
 
47
48
  <!-- SPDX-License-Identifier: MIT -->
48
49
  [![PyPi - Version](https://img.shields.io/pypi/v/odxtools)](https://pypi.org/project/odxtools)