odxtools 9.7.0__py3-none-any.whl → 10.1.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 (193) hide show
  1. odxtools/additionalaudience.py +7 -7
  2. odxtools/admindata.py +14 -13
  3. odxtools/audience.py +17 -17
  4. odxtools/basecomparam.py +9 -8
  5. odxtools/basevariantpattern.py +9 -10
  6. odxtools/basicstructure.py +15 -15
  7. odxtools/cli/_print_utils.py +34 -22
  8. odxtools/cli/browse.py +8 -8
  9. odxtools/cli/compare.py +24 -24
  10. odxtools/cli/decode.py +3 -4
  11. odxtools/cli/find.py +4 -5
  12. odxtools/cli/list.py +6 -6
  13. odxtools/cli/main.py +2 -2
  14. odxtools/cli/snoop.py +3 -3
  15. odxtools/codec.py +3 -3
  16. odxtools/commrelation.py +18 -17
  17. odxtools/companydata.py +13 -13
  18. odxtools/companydocinfo.py +15 -17
  19. odxtools/companyrevisioninfo.py +9 -9
  20. odxtools/companyspecificinfo.py +11 -13
  21. odxtools/comparam.py +8 -7
  22. odxtools/comparaminstance.py +14 -14
  23. odxtools/comparamspec.py +10 -11
  24. odxtools/comparamsubset.py +17 -25
  25. odxtools/complexcomparam.py +14 -14
  26. odxtools/complexdop.py +1 -1
  27. odxtools/compositecodec.py +8 -8
  28. odxtools/compumethods/compucodecompumethod.py +7 -7
  29. odxtools/compumethods/compuconst.py +5 -6
  30. odxtools/compumethods/compudefaultvalue.py +2 -3
  31. odxtools/compumethods/compuinternaltophys.py +13 -12
  32. odxtools/compumethods/compumethod.py +10 -9
  33. odxtools/compumethods/compuphystointernal.py +13 -12
  34. odxtools/compumethods/compurationalcoeffs.py +7 -7
  35. odxtools/compumethods/compuscale.py +15 -16
  36. odxtools/compumethods/createanycompumethod.py +12 -13
  37. odxtools/compumethods/identicalcompumethod.py +4 -5
  38. odxtools/compumethods/limit.py +14 -14
  39. odxtools/compumethods/linearcompumethod.py +5 -5
  40. odxtools/compumethods/linearsegment.py +10 -11
  41. odxtools/compumethods/ratfunccompumethod.py +6 -6
  42. odxtools/compumethods/ratfuncsegment.py +7 -8
  43. odxtools/compumethods/scalelinearcompumethod.py +9 -9
  44. odxtools/compumethods/scaleratfunccompumethod.py +7 -7
  45. odxtools/compumethods/tabintpcompumethod.py +10 -13
  46. odxtools/compumethods/texttablecompumethod.py +6 -6
  47. odxtools/createanycomparam.py +5 -7
  48. odxtools/createanydiagcodedtype.py +7 -8
  49. odxtools/database.py +34 -31
  50. odxtools/dataobjectproperty.py +19 -20
  51. odxtools/decodestate.py +5 -5
  52. odxtools/description.py +9 -9
  53. odxtools/determinenumberofitems.py +8 -7
  54. odxtools/diagcodedtype.py +10 -10
  55. odxtools/diagcomm.py +29 -30
  56. odxtools/diagdatadictionaryspec.py +36 -36
  57. odxtools/diaglayercontainer.py +35 -34
  58. odxtools/diaglayers/basevariant.py +14 -12
  59. odxtools/diaglayers/basevariantraw.py +22 -23
  60. odxtools/diaglayers/diaglayer.py +24 -22
  61. odxtools/diaglayers/diaglayerraw.py +43 -52
  62. odxtools/diaglayers/diaglayertype.py +1 -2
  63. odxtools/diaglayers/ecushareddata.py +9 -9
  64. odxtools/diaglayers/ecushareddataraw.py +15 -16
  65. odxtools/diaglayers/ecuvariant.py +15 -13
  66. odxtools/diaglayers/ecuvariantraw.py +21 -22
  67. odxtools/diaglayers/functionalgroup.py +12 -11
  68. odxtools/diaglayers/functionalgroupraw.py +17 -18
  69. odxtools/diaglayers/hierarchyelement.py +48 -54
  70. odxtools/diaglayers/hierarchyelementraw.py +10 -11
  71. odxtools/diaglayers/protocol.py +7 -7
  72. odxtools/diaglayers/protocolraw.py +13 -14
  73. odxtools/diagnostictroublecode.py +15 -17
  74. odxtools/diagservice.py +28 -27
  75. odxtools/diagvariable.py +24 -25
  76. odxtools/docrevision.py +18 -17
  77. odxtools/dopbase.py +13 -14
  78. odxtools/dtcconnector.py +8 -7
  79. odxtools/dtcdop.py +24 -20
  80. odxtools/dynamicendmarkerfield.py +10 -9
  81. odxtools/dynamiclengthfield.py +10 -9
  82. odxtools/dyndefinedspec.py +10 -10
  83. odxtools/dynenddopref.py +9 -9
  84. odxtools/dyniddefmodeinfo.py +21 -21
  85. odxtools/ecuvariantpattern.py +8 -10
  86. odxtools/element.py +12 -13
  87. odxtools/encodestate.py +11 -11
  88. odxtools/encoding.py +2 -3
  89. odxtools/endofpdufield.py +9 -10
  90. odxtools/envdataconnector.py +8 -8
  91. odxtools/environmentdata.py +7 -9
  92. odxtools/environmentdatadescription.py +18 -17
  93. odxtools/exceptions.py +5 -5
  94. odxtools/externalaccessmethod.py +4 -6
  95. odxtools/externaldoc.py +6 -6
  96. odxtools/field.py +15 -15
  97. odxtools/functionalclass.py +9 -9
  98. odxtools/inputparam.py +11 -10
  99. odxtools/internalconstr.py +10 -11
  100. odxtools/isotp_state_machine.py +12 -11
  101. odxtools/leadinglengthinfotype.py +4 -6
  102. odxtools/library.py +9 -8
  103. odxtools/linkeddtcdop.py +9 -8
  104. odxtools/loadfile.py +5 -6
  105. odxtools/matchingbasevariantparameter.py +5 -6
  106. odxtools/matchingparameter.py +10 -10
  107. odxtools/message.py +1 -1
  108. odxtools/minmaxlengthtype.py +6 -7
  109. odxtools/modification.py +7 -6
  110. odxtools/multiplexer.py +54 -18
  111. odxtools/multiplexercase.py +13 -13
  112. odxtools/multiplexerdefaultcase.py +11 -10
  113. odxtools/multiplexerswitchkey.py +8 -8
  114. odxtools/nameditemlist.py +13 -13
  115. odxtools/negoutputparam.py +8 -8
  116. odxtools/obd.py +1 -2
  117. odxtools/odxcategory.py +14 -26
  118. odxtools/odxdoccontext.py +16 -0
  119. odxtools/odxlink.py +23 -25
  120. odxtools/odxtypes.py +18 -15
  121. odxtools/outputparam.py +9 -8
  122. odxtools/parameterinfo.py +1 -1
  123. odxtools/parameters/codedconstparameter.py +10 -10
  124. odxtools/parameters/createanyparameter.py +15 -16
  125. odxtools/parameters/dynamicparameter.py +5 -7
  126. odxtools/parameters/lengthkeyparameter.py +10 -10
  127. odxtools/parameters/matchingrequestparameter.py +6 -7
  128. odxtools/parameters/nrcconstparameter.py +13 -13
  129. odxtools/parameters/parameter.py +17 -18
  130. odxtools/parameters/parameterwithdop.py +13 -13
  131. odxtools/parameters/physicalconstantparameter.py +8 -7
  132. odxtools/parameters/reservedparameter.py +6 -8
  133. odxtools/parameters/systemparameter.py +5 -7
  134. odxtools/parameters/tableentryparameter.py +8 -8
  135. odxtools/parameters/tablekeyparameter.py +17 -17
  136. odxtools/parameters/tablestructparameter.py +11 -11
  137. odxtools/parameters/valueparameter.py +11 -11
  138. odxtools/paramlengthinfotype.py +10 -9
  139. odxtools/parentref.py +15 -13
  140. odxtools/physicaldimension.py +15 -15
  141. odxtools/physicaltype.py +5 -6
  142. odxtools/posresponsesuppressible.py +11 -12
  143. odxtools/preconditionstateref.py +11 -11
  144. odxtools/progcode.py +11 -10
  145. odxtools/protstack.py +10 -9
  146. odxtools/relateddiagcommref.py +5 -6
  147. odxtools/relateddoc.py +11 -10
  148. odxtools/request.py +18 -19
  149. odxtools/response.py +19 -20
  150. odxtools/scaleconstr.py +8 -9
  151. odxtools/servicebinner.py +5 -5
  152. odxtools/singleecujob.py +16 -15
  153. odxtools/snrefcontext.py +3 -3
  154. odxtools/specialdata.py +8 -7
  155. odxtools/specialdatagroup.py +17 -17
  156. odxtools/specialdatagroupcaption.py +7 -6
  157. odxtools/standardlengthtype.py +14 -22
  158. odxtools/state.py +7 -6
  159. odxtools/statechart.py +12 -11
  160. odxtools/statemachine.py +4 -3
  161. odxtools/statetransition.py +9 -9
  162. odxtools/statetransitionref.py +19 -19
  163. odxtools/staticfield.py +9 -7
  164. odxtools/structure.py +5 -6
  165. odxtools/subcomponent.py +20 -18
  166. odxtools/subcomponentparamconnector.py +10 -9
  167. odxtools/subcomponentpattern.py +9 -9
  168. odxtools/swvariable.py +6 -7
  169. odxtools/table.py +25 -26
  170. odxtools/tablediagcommconnector.py +9 -8
  171. odxtools/tablerow.py +64 -43
  172. odxtools/tablerowconnector.py +8 -8
  173. odxtools/teammember.py +16 -15
  174. odxtools/templates/macros/printParentRef.xml.jinja2 +3 -1
  175. odxtools/text.py +4 -5
  176. odxtools/uds.py +2 -3
  177. odxtools/unit.py +14 -13
  178. odxtools/unitgroup.py +11 -10
  179. odxtools/unitspec.py +18 -19
  180. odxtools/utils.py +3 -3
  181. odxtools/variablegroup.py +5 -6
  182. odxtools/variantmatcher.py +10 -10
  183. odxtools/variantpattern.py +5 -6
  184. odxtools/version.py +2 -2
  185. odxtools/writepdxfile.py +5 -24
  186. odxtools/xdoc.py +13 -12
  187. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/METADATA +4 -5
  188. odxtools-10.1.0.dist-info/RECORD +265 -0
  189. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/WHEEL +1 -1
  190. odxtools-9.7.0.dist-info/RECORD +0 -264
  191. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/entry_points.txt +0 -0
  192. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/licenses/LICENSE +0 -0
  193. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,12 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .exceptions import odxrequire
8
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
+ from .odxdoccontext import OdxDocContext
9
+ from .odxlink import OdxLinkDatabase, OdxLinkId
9
10
  from .odxtypes import odxstr_to_bool
10
11
  from .snrefcontext import SnRefContext
11
12
  from .specialdatagroup import SpecialDataGroup
@@ -13,34 +14,31 @@ from .text import Text
13
14
  from .utils import dataclass_fields_asdict
14
15
 
15
16
 
16
- @dataclass
17
+ @dataclass(kw_only=True)
17
18
  class DiagnosticTroubleCode(IdentifiableElement):
18
19
  trouble_code: int
19
- display_trouble_code: Optional[str]
20
+ display_trouble_code: str | None = None
20
21
  text: Text
21
- level: Optional[int]
22
- sdgs: List[SpecialDataGroup]
22
+ level: int | None = None
23
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
23
24
 
24
- is_temporary_raw: Optional[bool]
25
+ is_temporary_raw: bool | None = None
25
26
 
26
27
  @property
27
28
  def is_temporary(self) -> bool:
28
29
  return self.is_temporary_raw is True
29
30
 
30
31
  @staticmethod
31
- def from_et(et_element: ElementTree.Element,
32
- doc_frags: List[OdxDocFragment]) -> "DiagnosticTroubleCode":
33
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
32
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DiagnosticTroubleCode":
33
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
34
34
 
35
35
  trouble_code = int(odxrequire(et_element.findtext("TROUBLE-CODE")))
36
36
  display_trouble_code = et_element.findtext("DISPLAY-TROUBLE-CODE")
37
- text = Text.from_et(odxrequire(et_element.find("TEXT")), doc_frags)
37
+ text = Text.from_et(odxrequire(et_element.find("TEXT")), context)
38
38
  level = None
39
39
  if (level_str := et_element.findtext("LEVEL")) is not None:
40
40
  level = int(level_str)
41
- sdgs = [
42
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
43
- ]
41
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
44
42
 
45
43
  is_temporary_raw = odxstr_to_bool(et_element.attrib.get("IS-TEMPORARY"))
46
44
 
@@ -53,8 +51,8 @@ class DiagnosticTroubleCode(IdentifiableElement):
53
51
  is_temporary_raw=is_temporary_raw,
54
52
  **kwargs)
55
53
 
56
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
57
- result: Dict[OdxLinkId, Any] = {}
54
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
55
+ result: dict[OdxLinkId, Any] = {}
58
56
 
59
57
  result[self.odx_id] = self
60
58
 
odxtools/diagservice.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional, Union, cast
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .addressing import Addressing
@@ -9,7 +9,8 @@ from .diagcomm import DiagComm
9
9
  from .exceptions import DecodeError, DecodeMismatch, odxassert, odxraise, odxrequire
10
10
  from .message import Message
11
11
  from .nameditemlist import NamedItemList
12
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
12
+ from .odxdoccontext import OdxDocContext
13
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
13
14
  from .odxtypes import ParameterValue, odxstr_to_bool
14
15
  from .parameters.parameter import Parameter
15
16
  from .posresponsesuppressible import PosResponseSuppressible
@@ -20,28 +21,28 @@ from .transmode import TransMode
20
21
  from .utils import dataclass_fields_asdict
21
22
 
22
23
 
23
- @dataclass
24
+ @dataclass(kw_only=True)
24
25
  class DiagService(DiagComm):
25
26
  """Representation of a diagnostic service description.
26
27
  """
27
28
 
28
- comparam_refs: List[ComparamInstance]
29
+ comparam_refs: list[ComparamInstance] = field(default_factory=list)
29
30
  request_ref: OdxLinkRef
30
- pos_response_refs: List[OdxLinkRef]
31
- neg_response_refs: List[OdxLinkRef]
32
- pos_response_suppressible: Optional[PosResponseSuppressible]
31
+ pos_response_refs: list[OdxLinkRef] = field(default_factory=list)
32
+ neg_response_refs: list[OdxLinkRef] = field(default_factory=list)
33
+ pos_response_suppressible: PosResponseSuppressible | None = None
33
34
 
34
- is_cyclic_raw: Optional[bool]
35
- is_multiple_raw: Optional[bool]
36
- addressing_raw: Optional[Addressing]
37
- transmission_mode_raw: Optional[TransMode]
35
+ is_cyclic_raw: bool | None = None
36
+ is_multiple_raw: bool | None = None
37
+ addressing_raw: Addressing | None = None
38
+ transmission_mode_raw: TransMode | None = None
38
39
 
39
40
  @property
40
41
  def comparams(self) -> NamedItemList[ComparamInstance]:
41
42
  return self._comparams
42
43
 
43
44
  @property
44
- def request(self) -> Optional[Request]:
45
+ def request(self) -> Request | None:
45
46
  return self._request
46
47
 
47
48
  @property
@@ -69,42 +70,42 @@ class DiagService(DiagComm):
69
70
  return self.transmission_mode_raw or TransMode.SEND_AND_RECEIVE
70
71
 
71
72
  @property
72
- def free_parameters(self) -> List[Parameter]:
73
+ def free_parameters(self) -> list[Parameter]:
73
74
  """Return the list of parameters which can be freely specified by
74
75
  the user when encoding the service's request.
75
76
  """
76
77
  return self.request.free_parameters if self.request is not None else []
77
78
 
78
79
  @staticmethod
79
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagService":
80
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DiagService":
80
81
 
81
- kwargs = dataclass_fields_asdict(DiagComm.from_et(et_element, doc_frags))
82
+ kwargs = dataclass_fields_asdict(DiagComm.from_et(et_element, context))
82
83
 
83
84
  comparam_refs = [
84
- ComparamInstance.from_et(el, doc_frags)
85
+ ComparamInstance.from_et(el, context)
85
86
  for el in et_element.iterfind("COMPARAM-REFS/COMPARAM-REF")
86
87
  ]
87
88
 
88
- request_ref = odxrequire(OdxLinkRef.from_et(et_element.find("REQUEST-REF"), doc_frags))
89
+ request_ref = odxrequire(OdxLinkRef.from_et(et_element.find("REQUEST-REF"), context))
89
90
 
90
91
  pos_response_refs = [
91
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
92
+ odxrequire(OdxLinkRef.from_et(el, context))
92
93
  for el in et_element.iterfind("POS-RESPONSE-REFS/POS-RESPONSE-REF")
93
94
  ]
94
95
 
95
96
  neg_response_refs = [
96
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
97
+ odxrequire(OdxLinkRef.from_et(el, context))
97
98
  for el in et_element.iterfind("NEG-RESPONSE-REFS/NEG-RESPONSE-REF")
98
99
  ]
99
100
 
100
101
  pos_response_suppressible = None
101
102
  if (prs_elem := et_element.find("POS-RESPONSE-SUPPRESSABLE")) is not None:
102
- pos_response_suppressible = PosResponseSuppressible.from_et(prs_elem, doc_frags)
103
+ pos_response_suppressible = PosResponseSuppressible.from_et(prs_elem, context)
103
104
 
104
105
  is_cyclic_raw = odxstr_to_bool(et_element.get("IS-CYCLIC"))
105
106
  is_multiple_raw = odxstr_to_bool(et_element.get("IS-MULTIPLE"))
106
107
 
107
- addressing_raw: Optional[Addressing] = None
108
+ addressing_raw: Addressing | None = None
108
109
  if (addressing_raw_str := et_element.get("ADDRESSING")) is not None:
109
110
  try:
110
111
  addressing_raw = Addressing(addressing_raw_str)
@@ -112,7 +113,7 @@ class DiagService(DiagComm):
112
113
  addressing_raw = cast(Addressing, None)
113
114
  odxraise(f"Encountered unknown addressing type '{addressing_raw_str}'")
114
115
 
115
- transmission_mode_raw: Optional[TransMode] = None
116
+ transmission_mode_raw: TransMode | None = None
116
117
  if (transmission_mode_raw_str := et_element.get("TRANSMISSION-MODE")) is not None:
117
118
  try:
118
119
  transmission_mode_raw = TransMode(transmission_mode_raw_str)
@@ -132,7 +133,7 @@ class DiagService(DiagComm):
132
133
  transmission_mode_raw=transmission_mode_raw,
133
134
  **kwargs)
134
135
 
135
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
136
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
136
137
  result = super()._build_odxlinks()
137
138
 
138
139
  for cpr in self.comparam_refs:
@@ -180,20 +181,20 @@ class DiagService(DiagComm):
180
181
 
181
182
  def decode_message(self, raw_message: bytes) -> Message:
182
183
  request_prefix = b''
183
- candidate_coding_objects: List[Union[Request, Response]] = [
184
+ candidate_coding_objects: list[Request | Response] = [
184
185
  *self.positive_responses, *self.negative_responses
185
186
  ]
186
187
  if self.request is not None:
187
188
  request_prefix = self.request.coded_const_prefix()
188
189
  candidate_coding_objects.append(self.request)
189
190
 
190
- coding_objects: List[Union[Request, Response]] = []
191
+ coding_objects: list[Request | Response] = []
191
192
  for candidate_coding_object in candidate_coding_objects:
192
193
  prefix = candidate_coding_object.coded_const_prefix(request_prefix=request_prefix)
193
194
  if len(raw_message) >= len(prefix) and prefix == raw_message[:len(prefix)]:
194
195
  coding_objects.append(candidate_coding_object)
195
196
 
196
- result_list: List[Message] = []
197
+ result_list: list[Message] = []
197
198
  for coding_object in coding_objects:
198
199
  try:
199
200
  result_list.append(
odxtools/diagvariable.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import typing
3
- from dataclasses import dataclass
4
- from typing import Any, Dict, List, Optional, runtime_checkable
3
+ from dataclasses import dataclass, field
4
+ from typing import Any, runtime_checkable
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .admindata import AdminData
@@ -9,7 +9,8 @@ from .commrelation import CommRelation
9
9
  from .element import IdentifiableElement
10
10
  from .exceptions import odxrequire
11
11
  from .nameditemlist import NamedItemList
12
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
12
+ from .odxdoccontext import OdxDocContext
13
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
13
14
  from .odxtypes import odxstr_to_bool
14
15
  from .snrefcontext import SnRefContext
15
16
  from .specialdatagroup import SpecialDataGroup
@@ -28,37 +29,37 @@ class HasDiagVariables(typing.Protocol):
28
29
  ...
29
30
 
30
31
 
31
- @dataclass
32
+ @dataclass(kw_only=True)
32
33
  class DiagVariable(IdentifiableElement):
33
34
  """Representation of a diagnostic variable
34
35
  """
35
36
 
36
- admin_data: Optional[AdminData]
37
- variable_group_ref: Optional[OdxLinkRef]
38
- sw_variables: List[SwVariable]
37
+ admin_data: AdminData | None = None
38
+ variable_group_ref: OdxLinkRef | None = None
39
+ sw_variables: list[SwVariable] = field(default_factory=list)
39
40
 
40
41
  # a diag variable must specify either COMM-RELATIONS or a
41
42
  # reference to a table row
42
- comm_relations: List[CommRelation]
43
+ comm_relations: list[CommRelation] = field(default_factory=list)
43
44
 
44
45
  # these are nested inside the SNREF-TO-TABLEROW tag
45
- table_snref: Optional[str]
46
- table_row_snref: Optional[str]
46
+ table_snref: str | None = None
47
+ table_row_snref: str | None = None
47
48
 
48
- sdgs: List[SpecialDataGroup]
49
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
49
50
 
50
- is_read_before_write_raw: Optional[bool]
51
+ is_read_before_write_raw: bool | None = None
51
52
 
52
53
  @property
53
- def table(self) -> Optional[Table]:
54
+ def table(self) -> Table | None:
54
55
  return self._table
55
56
 
56
57
  @property
57
- def table_row(self) -> Optional[TableRow]:
58
+ def table_row(self) -> TableRow | None:
58
59
  return self._table_row
59
60
 
60
61
  @property
61
- def variable_group(self) -> Optional[VariableGroup]:
62
+ def variable_group(self) -> VariableGroup | None:
62
63
  return self._variable_group
63
64
 
64
65
  @property
@@ -66,17 +67,17 @@ class DiagVariable(IdentifiableElement):
66
67
  return self.is_read_before_write_raw is True
67
68
 
68
69
  @staticmethod
69
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagVariable":
70
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
70
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DiagVariable":
71
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
71
72
 
72
- admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
73
- variable_group_ref = OdxLinkRef.from_et(et_element.find("VARIABLE-GROUP-REF"), doc_frags)
73
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
74
+ variable_group_ref = OdxLinkRef.from_et(et_element.find("VARIABLE-GROUP-REF"), context)
74
75
  sw_variables = NamedItemList([
75
- SwVariable.from_et(swv_elem, doc_frags)
76
+ SwVariable.from_et(swv_elem, context)
76
77
  for swv_elem in et_element.iterfind("SW-VARIABLES/SW-VARIABLE")
77
78
  ])
78
79
  comm_relations = [
79
- CommRelation.from_et(cr_elem, doc_frags)
80
+ CommRelation.from_et(cr_elem, context)
80
81
  for cr_elem in et_element.iterfind("COMM-RELATIONS/COMM-RELATION")
81
82
  ]
82
83
 
@@ -89,9 +90,7 @@ class DiagVariable(IdentifiableElement):
89
90
  table_row_snref_elem = odxrequire(snref_to_tablerow_elem.find("TABLE-ROW-SNREF"))
90
91
  table_row_snref = odxrequire(table_row_snref_elem.attrib.get("SHORT-NAME"))
91
92
 
92
- sdgs = [
93
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
94
- ]
93
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
95
94
 
96
95
  is_read_before_write_raw = odxstr_to_bool(et_element.get("IS-READ-BEFORE-WRITE"))
97
96
 
@@ -106,7 +105,7 @@ class DiagVariable(IdentifiableElement):
106
105
  is_read_before_write_raw=is_read_before_write_raw,
107
106
  **kwargs)
108
107
 
109
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
108
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
110
109
  result = {self.odx_id: self}
111
110
 
112
111
  if self.admin_data is not None:
odxtools/docrevision.py CHANGED
@@ -1,51 +1,52 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .companyrevisioninfo import CompanyRevisionInfo
7
7
  from .exceptions import odxrequire
8
8
  from .modification import Modification
9
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
+ from .odxdoccontext import OdxDocContext
10
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
10
11
  from .snrefcontext import SnRefContext
11
12
  from .teammember import TeamMember
12
13
 
13
14
 
14
- @dataclass
15
+ @dataclass(kw_only=True)
15
16
  class DocRevision:
16
17
  """
17
18
  Representation of a single revision of the relevant object.
18
19
  """
19
20
 
20
- team_member_ref: Optional[OdxLinkRef]
21
- revision_label: Optional[str]
22
- state: Optional[str]
21
+ team_member_ref: OdxLinkRef | None = None
22
+ revision_label: str | None = None
23
+ state: str | None = None
23
24
  date: str
24
- tool: Optional[str]
25
- company_revision_infos: List[CompanyRevisionInfo]
26
- modifications: List[Modification]
25
+ tool: str | None = None
26
+ company_revision_infos: list[CompanyRevisionInfo] = field(default_factory=list)
27
+ modifications: list[Modification] = field(default_factory=list)
27
28
 
28
29
  @property
29
- def team_member(self) -> Optional[TeamMember]:
30
+ def team_member(self) -> TeamMember | None:
30
31
  return self._team_member
31
32
 
32
33
  @staticmethod
33
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DocRevision":
34
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DocRevision":
34
35
 
35
- team_member_ref = OdxLinkRef.from_et(et_element.find("TEAM-MEMBER-REF"), doc_frags)
36
+ team_member_ref = OdxLinkRef.from_et(et_element.find("TEAM-MEMBER-REF"), context)
36
37
  revision_label = et_element.findtext("REVISION-LABEL")
37
38
  state = et_element.findtext("STATE")
38
39
  date = odxrequire(et_element.findtext("DATE"))
39
40
  tool = et_element.findtext("TOOL")
40
41
 
41
42
  company_revision_infos = [
42
- CompanyRevisionInfo.from_et(cri_elem, doc_frags)
43
+ CompanyRevisionInfo.from_et(cri_elem, context)
43
44
  for cri_elem in et_element.iterfind("COMPANY-REVISION-INFOS/"
44
45
  "COMPANY-REVISION-INFO")
45
46
  ]
46
47
 
47
48
  modifications = [
48
- Modification.from_et(mod_elem, doc_frags)
49
+ Modification.from_et(mod_elem, context)
49
50
  for mod_elem in et_element.iterfind("MODIFICATIONS/MODIFICATION")
50
51
  ]
51
52
 
@@ -59,11 +60,11 @@ class DocRevision:
59
60
  modifications=modifications,
60
61
  )
61
62
 
62
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
63
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
63
64
  return {}
64
65
 
65
66
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
66
- self._team_member: Optional[TeamMember] = None
67
+ self._team_member: TeamMember | None = None
67
68
  if self.team_member_ref is not None:
68
69
  self._team_member = odxlinks.resolve(self.team_member_ref, TeamMember)
69
70
 
odxtools/dopbase.py CHANGED
@@ -1,20 +1,21 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
7
7
  from .decodestate import DecodeState
8
8
  from .element import IdentifiableElement
9
9
  from .encodestate import EncodeState
10
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId
11
12
  from .odxtypes import ParameterValue
12
13
  from .snrefcontext import SnRefContext
13
14
  from .specialdatagroup import SpecialDataGroup
14
15
  from .utils import dataclass_fields_asdict
15
16
 
16
17
 
17
- @dataclass
18
+ @dataclass(kw_only=True)
18
19
  class DopBase(IdentifiableElement):
19
20
  """Base class for all (simple and complex) data object properties.
20
21
 
@@ -24,25 +25,23 @@ class DopBase(IdentifiableElement):
24
25
 
25
26
  """
26
27
 
27
- admin_data: Optional[AdminData]
28
- sdgs: List[SpecialDataGroup]
28
+ admin_data: AdminData | None = None
29
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
29
30
 
30
31
  @staticmethod
31
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DopBase":
32
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DopBase":
32
33
 
33
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
34
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
34
35
 
35
36
  admin_data = None
36
37
  if (admin_data_elem := et_element.find("ADMIN-DATA")) is not None:
37
- admin_data = AdminData.from_et(admin_data_elem, doc_frags)
38
+ admin_data = AdminData.from_et(admin_data_elem, context)
38
39
 
39
- sdgs = [
40
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
41
- ]
40
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
42
41
 
43
42
  return DopBase(admin_data=admin_data, sdgs=sdgs, **kwargs)
44
43
 
45
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
44
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
46
45
  result = {self.odx_id: self}
47
46
 
48
47
  for sdg in self.sdgs:
@@ -58,7 +57,7 @@ class DopBase(IdentifiableElement):
58
57
  for sdg in self.sdgs:
59
58
  sdg._resolve_snrefs(context)
60
59
 
61
- def get_static_bit_length(self) -> Optional[int]:
60
+ def get_static_bit_length(self) -> int | None:
62
61
  return None
63
62
 
64
63
  def is_valid_physical_value(self, physical_value: ParameterValue) -> bool:
odxtools/dtcconnector.py CHANGED
@@ -1,18 +1,19 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .diagnostictroublecode import DiagnosticTroubleCode
7
7
  from .dtcdop import DtcDop
8
8
  from .element import NamedElement
9
9
  from .exceptions import odxrequire
10
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
11
12
  from .snrefcontext import SnRefContext
12
13
  from .utils import dataclass_fields_asdict
13
14
 
14
15
 
15
- @dataclass
16
+ @dataclass(kw_only=True)
16
17
  class DtcConnector(NamedElement):
17
18
  dtc_dop_ref: OdxLinkRef
18
19
  dtc_snref: str
@@ -26,16 +27,16 @@ class DtcConnector(NamedElement):
26
27
  return self._dtc
27
28
 
28
29
  @staticmethod
29
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DtcConnector":
30
- kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
30
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DtcConnector":
31
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, context))
31
32
 
32
- dtc_dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DTC-DOP-REF"), doc_frags))
33
+ dtc_dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DTC-DOP-REF"), context))
33
34
  dtc_snref_el = odxrequire(et_element.find("DTC-SNREF"))
34
35
  dtc_snref = odxrequire(dtc_snref_el.get("SHORT-NAME"))
35
36
 
36
37
  return DtcConnector(dtc_dop_ref=dtc_dop_ref, dtc_snref=dtc_snref, **kwargs)
37
38
 
38
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
39
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
39
40
  return {}
40
41
 
41
42
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
odxtools/dtcdop.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional, Union, cast
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -16,23 +16,24 @@ from .encodestate import EncodeState
16
16
  from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
17
17
  from .linkeddtcdop import LinkedDtcDop
18
18
  from .nameditemlist import NamedItemList
19
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
19
+ from .odxdoccontext import OdxDocContext
20
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
20
21
  from .odxtypes import ParameterValue, odxstr_to_bool
21
22
  from .physicaltype import PhysicalType
22
23
  from .snrefcontext import SnRefContext
23
24
  from .utils import dataclass_fields_asdict
24
25
 
25
26
 
26
- @dataclass
27
+ @dataclass(kw_only=True)
27
28
  class DtcDop(DopBase):
28
29
  """A DOP describing a diagnostic trouble code"""
29
30
 
30
31
  diag_coded_type: DiagCodedType
31
32
  physical_type: PhysicalType
32
33
  compu_method: CompuMethod
33
- dtcs_raw: List[Union[DiagnosticTroubleCode, OdxLinkRef]]
34
- linked_dtc_dops_raw: List[LinkedDtcDop]
35
- is_visible_raw: Optional[bool]
34
+ dtcs_raw: list[DiagnosticTroubleCode | OdxLinkRef] = field(default_factory=list)
35
+ linked_dtc_dops_raw: list[LinkedDtcDop] = field(default_factory=list)
36
+ is_visible_raw: bool | None = None
36
37
 
37
38
  @property
38
39
  def dtcs(self) -> NamedItemList[DiagnosticTroubleCode]:
@@ -47,30 +48,29 @@ class DtcDop(DopBase):
47
48
  return self.is_visible_raw is True
48
49
 
49
50
  @staticmethod
50
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DtcDop":
51
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DtcDop":
51
52
  """Reads a DTC-DOP."""
52
- kwargs = dataclass_fields_asdict(DopBase.from_et(et_element, doc_frags))
53
+ kwargs = dataclass_fields_asdict(DopBase.from_et(et_element, context))
53
54
 
54
55
  diag_coded_type = create_any_diag_coded_type_from_et(
55
- odxrequire(et_element.find("DIAG-CODED-TYPE")), doc_frags)
56
- physical_type = PhysicalType.from_et(
57
- odxrequire(et_element.find("PHYSICAL-TYPE")), doc_frags)
56
+ odxrequire(et_element.find("DIAG-CODED-TYPE")), context)
57
+ physical_type = PhysicalType.from_et(odxrequire(et_element.find("PHYSICAL-TYPE")), context)
58
58
  compu_method = create_any_compu_method_from_et(
59
59
  odxrequire(et_element.find("COMPU-METHOD")),
60
- doc_frags,
60
+ context,
61
61
  internal_type=diag_coded_type.base_data_type,
62
62
  physical_type=physical_type.base_data_type,
63
63
  )
64
- dtcs_raw: List[Union[DiagnosticTroubleCode, OdxLinkRef]] = []
64
+ dtcs_raw: list[DiagnosticTroubleCode | OdxLinkRef] = []
65
65
  if (dtcs_elem := et_element.find("DTCS")) is not None:
66
66
  for dtc_proxy_elem in dtcs_elem:
67
67
  if dtc_proxy_elem.tag == "DTC":
68
- dtcs_raw.append(DiagnosticTroubleCode.from_et(dtc_proxy_elem, doc_frags))
68
+ dtcs_raw.append(DiagnosticTroubleCode.from_et(dtc_proxy_elem, context))
69
69
  elif dtc_proxy_elem.tag == "DTC-REF":
70
- dtcs_raw.append(OdxLinkRef.from_et(dtc_proxy_elem, doc_frags))
70
+ dtcs_raw.append(OdxLinkRef.from_et(dtc_proxy_elem, context))
71
71
 
72
72
  linked_dtc_dops_raw = [
73
- LinkedDtcDop.from_et(dtc_ref_elem, doc_frags)
73
+ LinkedDtcDop.from_et(dtc_ref_elem, context)
74
74
  for dtc_ref_elem in et_element.iterfind("LINKED-DTC-DOPS/"
75
75
  "LINKED-DTC-DOP")
76
76
  ]
@@ -155,7 +155,7 @@ class DtcDop(DopBase):
155
155
  return cast(int, None)
156
156
 
157
157
  @override
158
- def encode_into_pdu(self, physical_value: Optional[ParameterValue],
158
+ def encode_into_pdu(self, physical_value: ParameterValue | None,
159
159
  encode_state: EncodeState) -> None:
160
160
  if physical_value is None:
161
161
  odxraise(f"No DTC specified", EncodeError)
@@ -163,7 +163,11 @@ class DtcDop(DopBase):
163
163
 
164
164
  trouble_code = self.convert_to_numerical_trouble_code(physical_value)
165
165
 
166
- internal_trouble_code = int(self.compu_method.convert_physical_to_internal(trouble_code))
166
+ if not isinstance(trouble_code, int):
167
+ odxraise()
168
+ internal_trouble_code = self.compu_method.convert_physical_to_internal(trouble_code)
169
+ if not isinstance(internal_trouble_code, int):
170
+ odxraise()
167
171
 
168
172
  found = False
169
173
  for dtc in self.dtcs:
@@ -178,7 +182,7 @@ class DtcDop(DopBase):
178
182
 
179
183
  self.diag_coded_type.encode_into_pdu(internal_trouble_code, encode_state)
180
184
 
181
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
185
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
182
186
  odxlinks = super()._build_odxlinks()
183
187
 
184
188
  odxlinks.update(self.compu_method._build_odxlinks())