odxtools 9.7.0__py3-none-any.whl → 10.0.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 (189) hide show
  1. odxtools/additionalaudience.py +3 -3
  2. odxtools/admindata.py +8 -8
  3. odxtools/audience.py +10 -10
  4. odxtools/basecomparam.py +5 -5
  5. odxtools/basevariantpattern.py +4 -5
  6. odxtools/basicstructure.py +8 -8
  7. odxtools/cli/_print_utils.py +35 -23
  8. odxtools/cli/browse.py +9 -9
  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 +7 -7
  13. odxtools/cli/main.py +2 -2
  14. odxtools/cli/snoop.py +3 -3
  15. odxtools/codec.py +3 -3
  16. odxtools/commrelation.py +11 -11
  17. odxtools/companydata.py +5 -5
  18. odxtools/companydocinfo.py +8 -8
  19. odxtools/companyrevisioninfo.py +5 -5
  20. odxtools/companyspecificinfo.py +5 -5
  21. odxtools/comparam.py +3 -3
  22. odxtools/comparaminstance.py +10 -10
  23. odxtools/comparamspec.py +3 -3
  24. odxtools/comparamsubset.py +5 -5
  25. odxtools/complexcomparam.py +7 -7
  26. odxtools/compositecodec.py +11 -11
  27. odxtools/compumethods/compucodecompumethod.py +4 -4
  28. odxtools/compumethods/compuconst.py +4 -5
  29. odxtools/compumethods/compudefaultvalue.py +1 -2
  30. odxtools/compumethods/compuinternaltophys.py +6 -6
  31. odxtools/compumethods/compumethod.py +5 -5
  32. odxtools/compumethods/compuphystointernal.py +6 -6
  33. odxtools/compumethods/compurationalcoeffs.py +4 -4
  34. odxtools/compumethods/compuscale.py +9 -10
  35. odxtools/compumethods/createanycompumethod.py +1 -2
  36. odxtools/compumethods/identicalcompumethod.py +1 -2
  37. odxtools/compumethods/limit.py +12 -12
  38. odxtools/compumethods/linearcompumethod.py +2 -2
  39. odxtools/compumethods/linearsegment.py +14 -15
  40. odxtools/compumethods/ratfunccompumethod.py +3 -3
  41. odxtools/compumethods/ratfuncsegment.py +7 -8
  42. odxtools/compumethods/scalelinearcompumethod.py +7 -7
  43. odxtools/compumethods/scaleratfunccompumethod.py +4 -4
  44. odxtools/compumethods/tabintpcompumethod.py +15 -18
  45. odxtools/compumethods/texttablecompumethod.py +3 -3
  46. odxtools/createanycomparam.py +2 -4
  47. odxtools/createanydiagcodedtype.py +1 -2
  48. odxtools/database.py +9 -8
  49. odxtools/dataobjectproperty.py +10 -10
  50. odxtools/decodestate.py +5 -5
  51. odxtools/description.py +5 -5
  52. odxtools/determinenumberofitems.py +4 -4
  53. odxtools/diagcodedtype.py +7 -7
  54. odxtools/diagcomm.py +17 -17
  55. odxtools/diagdatadictionaryspec.py +6 -6
  56. odxtools/diaglayercontainer.py +4 -4
  57. odxtools/diaglayers/basevariant.py +10 -9
  58. odxtools/diaglayers/basevariantraw.py +9 -9
  59. odxtools/diaglayers/diaglayer.py +20 -19
  60. odxtools/diaglayers/diaglayerraw.py +10 -10
  61. odxtools/diaglayers/diaglayertype.py +1 -2
  62. odxtools/diaglayers/ecushareddata.py +4 -4
  63. odxtools/diaglayers/ecushareddataraw.py +6 -6
  64. odxtools/diaglayers/ecuvariant.py +11 -10
  65. odxtools/diaglayers/ecuvariantraw.py +9 -9
  66. odxtools/diaglayers/functionalgroup.py +8 -7
  67. odxtools/diaglayers/functionalgroupraw.py +7 -7
  68. odxtools/diaglayers/hierarchyelement.py +43 -49
  69. odxtools/diaglayers/hierarchyelementraw.py +4 -4
  70. odxtools/diaglayers/protocol.py +4 -4
  71. odxtools/diaglayers/protocolraw.py +6 -6
  72. odxtools/diagnostictroublecode.py +8 -8
  73. odxtools/diagservice.py +18 -18
  74. odxtools/diagvariable.py +14 -14
  75. odxtools/docrevision.py +11 -11
  76. odxtools/dopbase.py +6 -6
  77. odxtools/dtcconnector.py +3 -3
  78. odxtools/dtcdop.py +13 -9
  79. odxtools/dynamicendmarkerfield.py +5 -4
  80. odxtools/dynamiclengthfield.py +5 -4
  81. odxtools/dyndefinedspec.py +5 -5
  82. odxtools/dynenddopref.py +5 -5
  83. odxtools/dyniddefmodeinfo.py +13 -13
  84. odxtools/ecuvariantpattern.py +4 -5
  85. odxtools/element.py +5 -6
  86. odxtools/encodestate.py +11 -11
  87. odxtools/encoding.py +2 -3
  88. odxtools/endofpdufield.py +6 -6
  89. odxtools/envdataconnector.py +3 -3
  90. odxtools/environmentdata.py +3 -4
  91. odxtools/environmentdatadescription.py +11 -11
  92. odxtools/exceptions.py +5 -5
  93. odxtools/externalaccessmethod.py +1 -2
  94. odxtools/externaldoc.py +4 -4
  95. odxtools/field.py +9 -10
  96. odxtools/functionalclass.py +4 -4
  97. odxtools/inputparam.py +6 -6
  98. odxtools/internalconstr.py +4 -5
  99. odxtools/isotp_state_machine.py +12 -11
  100. odxtools/leadinglengthinfotype.py +2 -3
  101. odxtools/library.py +5 -5
  102. odxtools/linkeddtcdop.py +4 -4
  103. odxtools/loadfile.py +5 -6
  104. odxtools/matchingbasevariantparameter.py +2 -3
  105. odxtools/matchingparameter.py +7 -7
  106. odxtools/minmaxlengthtype.py +4 -4
  107. odxtools/modification.py +4 -4
  108. odxtools/multiplexer.py +11 -11
  109. odxtools/multiplexercase.py +6 -6
  110. odxtools/multiplexerdefaultcase.py +6 -6
  111. odxtools/multiplexerswitchkey.py +4 -4
  112. odxtools/nameditemlist.py +14 -14
  113. odxtools/negoutputparam.py +3 -3
  114. odxtools/obd.py +1 -2
  115. odxtools/odxcategory.py +6 -6
  116. odxtools/odxlink.py +19 -20
  117. odxtools/odxtypes.py +21 -18
  118. odxtools/outputparam.py +4 -4
  119. odxtools/parameterinfo.py +1 -1
  120. odxtools/parameters/codedconstparameter.py +5 -5
  121. odxtools/parameters/createanyparameter.py +1 -2
  122. odxtools/parameters/dynamicparameter.py +2 -3
  123. odxtools/parameters/lengthkeyparameter.py +5 -5
  124. odxtools/parameters/matchingrequestparameter.py +3 -4
  125. odxtools/parameters/nrcconstparameter.py +7 -7
  126. odxtools/parameters/parameter.py +11 -11
  127. odxtools/parameters/parameterwithdop.py +9 -9
  128. odxtools/parameters/physicalconstantparameter.py +4 -4
  129. odxtools/parameters/reservedparameter.py +3 -4
  130. odxtools/parameters/systemparameter.py +2 -3
  131. odxtools/parameters/tableentryparameter.py +3 -3
  132. odxtools/parameters/tablekeyparameter.py +10 -10
  133. odxtools/parameters/tablestructparameter.py +7 -7
  134. odxtools/parameters/valueparameter.py +7 -7
  135. odxtools/paramlengthinfotype.py +5 -3
  136. odxtools/parentref.py +9 -9
  137. odxtools/physicaldimension.py +11 -11
  138. odxtools/physicaltype.py +3 -4
  139. odxtools/posresponsesuppressible.py +9 -10
  140. odxtools/preconditionstateref.py +7 -7
  141. odxtools/progcode.py +6 -6
  142. odxtools/protstack.py +4 -4
  143. odxtools/relateddiagcommref.py +1 -2
  144. odxtools/relateddoc.py +6 -6
  145. odxtools/request.py +9 -9
  146. odxtools/response.py +10 -10
  147. odxtools/scaleconstr.py +3 -4
  148. odxtools/servicebinner.py +5 -5
  149. odxtools/singleecujob.py +4 -4
  150. odxtools/snrefcontext.py +2 -2
  151. odxtools/specialdata.py +5 -5
  152. odxtools/specialdatagroup.py +9 -9
  153. odxtools/specialdatagroupcaption.py +3 -3
  154. odxtools/standardlengthtype.py +10 -10
  155. odxtools/state.py +3 -3
  156. odxtools/statechart.py +4 -4
  157. odxtools/statemachine.py +4 -3
  158. odxtools/statetransition.py +4 -4
  159. odxtools/statetransitionref.py +18 -18
  160. odxtools/staticfield.py +5 -4
  161. odxtools/structure.py +2 -3
  162. odxtools/subcomponent.py +5 -5
  163. odxtools/subcomponentparamconnector.py +5 -5
  164. odxtools/subcomponentpattern.py +4 -4
  165. odxtools/swvariable.py +3 -4
  166. odxtools/table.py +14 -14
  167. odxtools/tablediagcommconnector.py +5 -5
  168. odxtools/tablerow.py +30 -30
  169. odxtools/tablerowconnector.py +3 -3
  170. odxtools/teammember.py +11 -11
  171. odxtools/text.py +2 -3
  172. odxtools/uds.py +2 -3
  173. odxtools/unit.py +9 -9
  174. odxtools/unitgroup.py +5 -5
  175. odxtools/unitspec.py +6 -6
  176. odxtools/utils.py +3 -3
  177. odxtools/variablegroup.py +2 -2
  178. odxtools/variantmatcher.py +10 -10
  179. odxtools/variantpattern.py +3 -3
  180. odxtools/version.py +2 -2
  181. odxtools/writepdxfile.py +5 -5
  182. odxtools/xdoc.py +9 -9
  183. {odxtools-9.7.0.dist-info → odxtools-10.0.0.dist-info}/METADATA +4 -5
  184. odxtools-10.0.0.dist-info/RECORD +264 -0
  185. odxtools-9.7.0.dist-info/RECORD +0 -264
  186. {odxtools-9.7.0.dist-info → odxtools-10.0.0.dist-info}/WHEEL +0 -0
  187. {odxtools-9.7.0.dist-info → odxtools-10.0.0.dist-info}/entry_points.txt +0 -0
  188. {odxtools-9.7.0.dist-info → odxtools-10.0.0.dist-info}/licenses/LICENSE +0 -0
  189. {odxtools-9.7.0.dist-info → odxtools-10.0.0.dist-info}/top_level.txt +0 -0
odxtools/tablerow.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass, fields
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
3
+ from typing import TYPE_CHECKING, Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
@@ -33,22 +33,22 @@ class TableRow(IdentifiableElement):
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
35
35
  # attributes below is not None
36
- dop_ref: Optional[OdxLinkRef]
37
- dop_snref: Optional[str]
38
- structure_ref: Optional[OdxLinkRef]
39
- structure_snref: Optional[str]
40
-
41
- sdgs: List[SpecialDataGroup]
42
- audience: Optional[Audience]
43
- functional_class_refs: List[OdxLinkRef]
44
- state_transition_refs: List[StateTransitionRef]
45
- pre_condition_state_refs: List[PreConditionStateRef]
46
- admin_data: Optional[AdminData]
47
-
48
- is_executable_raw: Optional[bool]
49
- semantic: Optional[str]
50
- is_mandatory_raw: Optional[bool]
51
- is_final_raw: Optional[bool]
36
+ dop_ref: OdxLinkRef | None
37
+ dop_snref: str | None
38
+ structure_ref: OdxLinkRef | None
39
+ structure_snref: str | None
40
+
41
+ sdgs: list[SpecialDataGroup]
42
+ audience: Audience | None
43
+ functional_class_refs: list[OdxLinkRef]
44
+ state_transition_refs: list[StateTransitionRef]
45
+ pre_condition_state_refs: list[PreConditionStateRef]
46
+ admin_data: AdminData | None
47
+
48
+ is_executable_raw: bool | None
49
+ semantic: str | None
50
+ is_mandatory_raw: bool | None
51
+ is_final_raw: bool | None
52
52
 
53
53
  @property
54
54
  def table(self) -> "Table":
@@ -57,16 +57,16 @@ class TableRow(IdentifiableElement):
57
57
  # the value of the key expressed in the type represented by the
58
58
  # referenced DOP
59
59
  @property
60
- def key(self) -> Optional[AtomicOdxType]:
60
+ def key(self) -> AtomicOdxType | None:
61
61
  return self._key
62
62
 
63
63
  @property
64
- def dop(self) -> Optional[DataObjectProperty]:
64
+ def dop(self) -> DataObjectProperty | None:
65
65
  """The data object property object resolved by dop_ref."""
66
66
  return self._dop
67
67
 
68
68
  @property
69
- def structure(self) -> Optional[Structure]:
69
+ def structure(self) -> Structure | None:
70
70
  """The structure associated with this table row."""
71
71
  return self._structure
72
72
 
@@ -87,12 +87,12 @@ class TableRow(IdentifiableElement):
87
87
  return self.is_final_raw is True
88
88
 
89
89
  @staticmethod
90
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> Any:
90
+ def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> Any:
91
91
  raise RuntimeError(
92
92
  "Calling TableRow.from_et() is not allowed. Use TableRow.tablerow_from_et().")
93
93
 
94
94
  @staticmethod
95
- def tablerow_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
95
+ def tablerow_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
96
96
  table_ref: OdxLinkRef) -> "TableRow":
97
97
  """Reads a TABLE-ROW."""
98
98
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
@@ -100,12 +100,12 @@ class TableRow(IdentifiableElement):
100
100
  key_raw = odxrequire(et_element.findtext("KEY"))
101
101
 
102
102
  dop_ref = OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), doc_frags)
103
- dop_snref: Optional[str] = None
103
+ dop_snref: str | None = None
104
104
  if (dop_snref_elem := et_element.find("DATA-OBJECT-PROP-SNREF")) is not None:
105
105
  dop_snref = dop_snref_elem.attrib["SHORT-NAME"]
106
106
 
107
107
  structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), doc_frags)
108
- structure_snref: Optional[str] = None
108
+ structure_snref: str | None = None
109
109
  if (structure_snref_elem := et_element.find("STRUCTURE-SNREF")) is not None:
110
110
  structure_snref = structure_snref_elem.attrib["SHORT-NAME"]
111
111
 
@@ -159,8 +159,8 @@ class TableRow(IdentifiableElement):
159
159
  **kwargs)
160
160
 
161
161
  def __post_init__(self) -> None:
162
- self._dop: Optional[DataObjectProperty] = None
163
- self._structure: Optional[Structure] = None
162
+ self._dop: DataObjectProperty | None = None
163
+ self._structure: Structure | None = None
164
164
 
165
165
  n = sum([0 if x is None else 1 for x in (self.dop_ref, self.dop_snref)])
166
166
  odxassert(
@@ -174,7 +174,7 @@ class TableRow(IdentifiableElement):
174
174
  f"Table row {self.short_name}: The structure can either be defined using ODXLINK or SNREF but not both."
175
175
  )
176
176
 
177
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
177
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
178
178
  result = {self.odx_id: self}
179
179
 
180
180
  for sdg in self.sdgs:
@@ -199,7 +199,7 @@ class TableRow(IdentifiableElement):
199
199
 
200
200
  if self.dop_ref is not None:
201
201
  self._dop = odxlinks.resolve(self.dop_ref)
202
- if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
202
+ if not isinstance(self._dop, DataObjectProperty | DtcDop):
203
203
  odxraise("The DOP-REF of TABLE-ROWs must reference a simple DOP!")
204
204
  if self.structure_ref is not None:
205
205
  self._structure = odxlinks.resolve(self.structure_ref, Structure)
@@ -243,7 +243,7 @@ class TableRow(IdentifiableElement):
243
243
  self._structure = resolve_snref(self.structure_snref, ddd_spec.structures, Structure)
244
244
  if self.dop_snref is not None:
245
245
  self._dop = resolve_snref(self.dop_snref, ddd_spec.data_object_props)
246
- if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
246
+ if not isinstance(self._dop, DataObjectProperty | DtcDop):
247
247
  odxraise("The DOP-SNREF of TABLE-ROWs must reference a simple DOP!")
248
248
 
249
249
  if self.audience is not None:
@@ -258,7 +258,7 @@ class TableRow(IdentifiableElement):
258
258
  for pc_ref in self.pre_condition_state_refs:
259
259
  pc_ref._resolve_snrefs(context)
260
260
 
261
- def __reduce__(self) -> Tuple[Any, ...]:
261
+ def __reduce__(self) -> tuple[Any, ...]:
262
262
  """This ensures that the object can be correctly reconstructed during unpickling."""
263
263
  state = self.__dict__.copy()
264
264
  return self.__class__, tuple([getattr(self, x.name) for x in fields(self)]), state
@@ -1,6 +1,6 @@
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 .element import NamedElement
@@ -27,7 +27,7 @@ class TableRowConnector(NamedElement):
27
27
 
28
28
  @staticmethod
29
29
  def from_et(et_element: ElementTree.Element,
30
- doc_frags: List[OdxDocFragment]) -> "TableRowConnector":
30
+ doc_frags: list[OdxDocFragment]) -> "TableRowConnector":
31
31
  kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
32
32
 
33
33
  table_ref = odxrequire(OdxLinkRef.from_et(et_element.find("TABLE-REF"), doc_frags))
@@ -36,7 +36,7 @@ class TableRowConnector(NamedElement):
36
36
 
37
37
  return TableRowConnector(table_ref=table_ref, table_row_snref=table_row_snref, **kwargs)
38
38
 
39
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
39
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
40
40
  return {}
41
41
 
42
42
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
odxtools/teammember.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
@@ -12,17 +12,17 @@ from .utils import dataclass_fields_asdict
12
12
 
13
13
  @dataclass
14
14
  class TeamMember(IdentifiableElement):
15
- roles: List[str]
16
- department: Optional[str]
17
- address: Optional[str]
18
- zipcode: Optional[str] # the tag for this is "ZIP", but `zip` is a keyword in python
19
- city: Optional[str]
20
- phone: Optional[str]
21
- fax: Optional[str]
22
- email: Optional[str]
15
+ roles: list[str]
16
+ department: str | None
17
+ address: str | None
18
+ zipcode: str | None # the tag for this is "ZIP", but `zip` is a keyword in python
19
+ city: str | None
20
+ phone: str | None
21
+ fax: str | None
22
+ email: str | None
23
23
 
24
24
  @staticmethod
25
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "TeamMember":
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
27
 
28
28
  roles = [odxrequire(role_elem.text) for role_elem in et_element.iterfind("ROLES/ROLE")]
@@ -45,7 +45,7 @@ class TeamMember(IdentifiableElement):
45
45
  email=email,
46
46
  **kwargs)
47
47
 
48
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
48
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
49
49
  result = {self.odx_id: self}
50
50
 
51
51
  return result
odxtools/text.py CHANGED
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import List, Optional
3
2
  from xml.etree import ElementTree
4
3
 
5
4
  from .odxlink import OdxDocFragment
@@ -8,10 +7,10 @@ from .odxlink import OdxDocFragment
8
7
  @dataclass
9
8
  class Text:
10
9
  text: str
11
- text_identifier: Optional[str]
10
+ text_identifier: str | None
12
11
 
13
12
  @staticmethod
14
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Text":
13
+ def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Text":
15
14
  # Extract the contents of the tag as a string.
16
15
  raw_string = et_element.text or ""
17
16
  for e in et_element:
odxtools/uds.py CHANGED
@@ -1,7 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from enum import IntEnum
3
3
  from itertools import chain
4
- from typing import Optional
5
4
 
6
5
  import odxtools.obd as obd
7
6
 
@@ -82,7 +81,7 @@ _sid_to_name = {
82
81
  SID = IntEnum("UdsSID", ((i.name, i.value) for i in chain(obd.SID, UDSSID))) # type: ignore[misc]
83
82
 
84
83
 
85
- def sid_to_name(sid: int) -> Optional[str]:
84
+ def sid_to_name(sid: int) -> str | None:
86
85
  if sid in _sid_to_name:
87
86
  return _sid_to_name[sid]
88
87
  elif 0x81 <= sid and sid <= 0x82:
@@ -142,7 +141,7 @@ def negative_response_id(service_id: int) -> int:
142
141
  return NegativeResponseId
143
142
 
144
143
 
145
- def is_response_pending(telegram_payload: bytes, request_sid: Optional[int] = None) -> bool:
144
+ def is_response_pending(telegram_payload: bytes, request_sid: int | None = None) -> bool:
146
145
  # "response pending" responses exhibit at least three bytes
147
146
  if len(telegram_payload) < 3:
148
147
  return False
odxtools/unit.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
@@ -53,21 +53,21 @@ class Unit(IdentifiableElement):
53
53
  ```
54
54
  """
55
55
  display_name: str
56
- factor_si_to_unit: Optional[float]
57
- offset_si_to_unit: Optional[float]
58
- physical_dimension_ref: Optional[OdxLinkRef]
56
+ factor_si_to_unit: float | None
57
+ offset_si_to_unit: float | None
58
+ physical_dimension_ref: OdxLinkRef | None
59
59
 
60
60
  @property
61
- def physical_dimension(self) -> Optional[PhysicalDimension]:
61
+ def physical_dimension(self) -> PhysicalDimension | None:
62
62
  return self._physical_dimension
63
63
 
64
64
  @staticmethod
65
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Unit":
65
+ def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Unit":
66
66
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
67
67
 
68
68
  display_name = odxrequire(et_element.findtext("DISPLAY-NAME"))
69
69
 
70
- def read_optional_float(element: ElementTree.Element, name: str) -> Optional[float]:
70
+ def read_optional_float(element: ElementTree.Element, name: str) -> float | None:
71
71
  if (elem_str := element.findtext(name)) is not None:
72
72
  return float(elem_str)
73
73
  else:
@@ -85,11 +85,11 @@ class Unit(IdentifiableElement):
85
85
  physical_dimension_ref=physical_dimension_ref,
86
86
  **kwargs)
87
87
 
88
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
88
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
89
89
  return {self.odx_id: self}
90
90
 
91
91
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
92
- self._physical_dimension: Optional[PhysicalDimension] = None
92
+ self._physical_dimension: PhysicalDimension | None = None
93
93
  if self.physical_dimension_ref:
94
94
  self._physical_dimension = odxlinks.resolve(self.physical_dimension_ref,
95
95
  PhysicalDimension)
odxtools/unitgroup.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional, cast
3
+ from typing import Any, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import NamedElement
@@ -20,15 +20,15 @@ class UnitGroup(NamedElement):
20
20
  There are two categories of groups: COUNTRY and EQUIV-UNITS.
21
21
  """
22
22
  category: UnitGroupCategory
23
- unit_refs: List[OdxLinkRef]
24
- oid: Optional[str]
23
+ unit_refs: list[OdxLinkRef]
24
+ oid: str | None
25
25
 
26
26
  @property
27
27
  def units(self) -> NamedItemList[Unit]:
28
28
  return self._units
29
29
 
30
30
  @staticmethod
31
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "UnitGroup":
31
+ def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "UnitGroup":
32
32
  kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
33
33
 
34
34
  category_str = odxrequire(et_element.findtext("CATEGORY"))
@@ -46,7 +46,7 @@ class UnitGroup(NamedElement):
46
46
 
47
47
  return UnitGroup(category=category, unit_refs=unit_refs, oid=oid, **kwargs)
48
48
 
49
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
49
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
50
50
  return {}
51
51
 
52
52
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
odxtools/unitspec.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
@@ -25,11 +25,11 @@ class UnitSpec:
25
25
  The following odx elements are not internalized: ADMIN-DATA, SDGS
26
26
  """
27
27
 
28
- admin_data: Optional[AdminData]
28
+ admin_data: AdminData | None
29
29
  unit_groups: NamedItemList[UnitGroup]
30
30
  units: NamedItemList[Unit]
31
31
  physical_dimensions: NamedItemList[PhysicalDimension]
32
- sdgs: List[SpecialDataGroup]
32
+ sdgs: list[SpecialDataGroup]
33
33
 
34
34
  def __post_init__(self) -> None:
35
35
  self.unit_groups = NamedItemList(self.unit_groups)
@@ -37,7 +37,7 @@ class UnitSpec:
37
37
  self.physical_dimensions = NamedItemList(self.physical_dimensions)
38
38
 
39
39
  @staticmethod
40
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "UnitSpec":
40
+ def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "UnitSpec":
41
41
 
42
42
  admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
43
43
  unit_groups = NamedItemList([
@@ -60,8 +60,8 @@ class UnitSpec:
60
60
  physical_dimensions=physical_dimensions,
61
61
  sdgs=sdgs)
62
62
 
63
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
64
- odxlinks: Dict[OdxLinkId, Any] = {}
63
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
64
+ odxlinks: dict[OdxLinkId, Any] = {}
65
65
  for unit in self.units:
66
66
  odxlinks.update(unit._build_odxlinks())
67
67
  for dim in self.physical_dimensions:
odxtools/utils.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import dataclasses
3
3
  import re
4
- from typing import TYPE_CHECKING, Any, Dict, Optional
4
+ from typing import TYPE_CHECKING, Any, Optional
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .exceptions import odxraise
@@ -12,7 +12,7 @@ if TYPE_CHECKING:
12
12
  from .snrefcontext import SnRefContext
13
13
 
14
14
 
15
- def read_hex_binary(et_element: Optional[ElementTree.Element]) -> Optional[int]:
15
+ def read_hex_binary(et_element: ElementTree.Element | None) -> int | None:
16
16
  """Convert the contents of an xsd:hexBinary to an integer
17
17
  """
18
18
  if et_element is None:
@@ -76,7 +76,7 @@ def retarget_snrefs(database: "Database",
76
76
  retarget_snrefs(database, pr.layer, context)
77
77
 
78
78
 
79
- def dataclass_fields_asdict(obj: Any) -> Dict[str, Any]:
79
+ def dataclass_fields_asdict(obj: Any) -> dict[str, Any]:
80
80
  """Extract all attributes from a dataclass object that are fields.
81
81
 
82
82
  This is a non-recursive version of `dataclasses.asdict()`. Its
odxtools/variablegroup.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import typing
3
3
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, List, runtime_checkable
4
+ from typing import TYPE_CHECKING, runtime_checkable
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .element import IdentifiableElement, NamedElement
@@ -26,7 +26,7 @@ class VariableGroup(IdentifiableElement):
26
26
 
27
27
  @staticmethod
28
28
  def from_et(et_element: ElementTree.Element,
29
- doc_frags: List[OdxDocFragment]) -> "VariableGroup":
29
+ doc_frags: list[OdxDocFragment]) -> "VariableGroup":
30
30
  kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
31
31
 
32
32
  return VariableGroup(**kwargs)
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
+ from collections.abc import Generator
2
3
  from copy import copy
3
4
  from enum import Enum
4
- from typing import Dict, Generator, List, Optional, Tuple, Union
5
5
 
6
6
  from .diaglayers.basevariant import BaseVariant
7
7
  from .diaglayers.ecuvariant import EcuVariant
@@ -56,18 +56,18 @@ class VariantMatcher:
56
56
  MATCH = 2
57
57
 
58
58
  def __init__(self,
59
- variant_candidates: Union[List[EcuVariant], List[BaseVariant]],
59
+ variant_candidates: list[EcuVariant] | list[BaseVariant],
60
60
  use_cache: bool = True):
61
61
 
62
62
  self.variant_candidates = variant_candidates
63
63
  self.use_cache = use_cache
64
- self.req_resp_cache: Dict[bytes, bytes] = {}
65
- self._recent_ident_response: Optional[bytes] = None
64
+ self.req_resp_cache: dict[bytes, bytes] = {}
65
+ self._recent_ident_response: bytes | None = None
66
66
 
67
67
  self._state = VariantMatcher.State.PENDING
68
- self._matching_variant: Optional[Union[EcuVariant, BaseVariant]] = None
68
+ self._matching_variant: EcuVariant | BaseVariant | None = None
69
69
 
70
- def request_loop(self) -> Generator[Tuple[bool, bytes], None, None]:
70
+ def request_loop(self) -> Generator[tuple[bool, bytes], None, None]:
71
71
  """The request loop yielding tuples of byte sequences of
72
72
  requests and the whether physical addressing ought to be used
73
73
  to send them
@@ -86,7 +86,7 @@ class VariantMatcher:
86
86
 
87
87
  self._matching_variant = None
88
88
  for variant in self.variant_candidates:
89
- variant_patterns: Union[List[EcuVariantPattern], List[BaseVariantPattern]]
89
+ variant_patterns: list[EcuVariantPattern] | list[BaseVariantPattern]
90
90
  if isinstance(variant, EcuVariant):
91
91
  variant_patterns = variant.ecu_variant_patterns
92
92
  elif isinstance(variant, BaseVariant):
@@ -158,13 +158,13 @@ class VariantMatcher:
158
158
  return self._state == VariantMatcher.State.MATCH
159
159
 
160
160
  @property
161
- def matching_variant(self) -> Optional[Union[EcuVariant, BaseVariant]]:
161
+ def matching_variant(self) -> EcuVariant | BaseVariant | None:
162
162
  """Returns the matched, i.e., active ecu variant if such a variant has been found."""
163
163
  return self._matching_variant
164
164
 
165
165
  def _ident_response_matches(
166
166
  self,
167
- variant: Union[EcuVariant, BaseVariant],
167
+ variant: EcuVariant | BaseVariant,
168
168
  matching_param: MatchingParameter,
169
169
  response_bytes: bytes,
170
170
  ) -> bool:
@@ -175,7 +175,7 @@ class VariantMatcher:
175
175
 
176
176
  # ISO 22901 requires that snref or snpathref is resolvable in
177
177
  # at least one POS-RESPONSE or NEG-RESPONSE
178
- all_responses: List[Response] = []
178
+ all_responses: list[Response] = []
179
179
  all_responses.extend(service.positive_responses)
180
180
  all_responses.extend(service.negative_responses)
181
181
  all_responses.extend(variant.global_negative_responses)
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, List, Union
3
+ from typing import TYPE_CHECKING
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .exceptions import odxraise
@@ -26,7 +26,7 @@ class VariantPattern:
26
26
  """
27
27
 
28
28
  def get_matching_parameters(
29
- self) -> Union[List["MatchingParameter"], List["MatchingBaseVariantParameter"]]:
29
+ self) -> list["MatchingParameter"] | list["MatchingBaseVariantParameter"]:
30
30
  odxraise(
31
31
  f"VariantPattern subclass `{type(self).__name__}` does not "
32
32
  f"implement `.get_match_parameters()`", RuntimeError)
@@ -34,5 +34,5 @@ class VariantPattern:
34
34
 
35
35
  @staticmethod
36
36
  def from_et(et_element: ElementTree.Element,
37
- doc_frags: List[OdxDocFragment]) -> "VariantPattern":
37
+ doc_frags: list[OdxDocFragment]) -> "VariantPattern":
38
38
  return VariantPattern()
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.7.0'
21
- __version_tuple__ = version_tuple = (9, 7, 0)
20
+ __version__ = version = '10.0.0'
21
+ __version_tuple__ = version_tuple = (10, 0, 0)
odxtools/writepdxfile.py CHANGED
@@ -5,7 +5,7 @@ import mimetypes
5
5
  import os
6
6
  import time
7
7
  import zipfile
8
- from typing import Any, Dict, Optional
8
+ from typing import Any
9
9
 
10
10
  import jinja2
11
11
 
@@ -14,7 +14,7 @@ import odxtools
14
14
  from .database import Database
15
15
  from .odxtypes import bool_to_odxstr
16
16
 
17
- odxdatabase: Optional[Database] = None
17
+ odxdatabase: Database | None = None
18
18
 
19
19
 
20
20
  def jinja2_odxraise_helper(msg: str) -> None:
@@ -39,14 +39,14 @@ def get_parent_container_name(dl_short_name: str) -> str:
39
39
  f"container for diagnostic layer '{dl_short_name}'.")
40
40
 
41
41
 
42
- def make_xml_attrib(attrib_name: str, attrib_val: Optional[Any]) -> str:
42
+ def make_xml_attrib(attrib_name: str, attrib_val: Any | None) -> str:
43
43
  if attrib_val is None:
44
44
  return ""
45
45
 
46
46
  return f' {attrib_name}="{attrib_val}"'
47
47
 
48
48
 
49
- def make_bool_xml_attrib(attrib_name: str, attrib_val: Optional[bool]) -> str:
49
+ def make_bool_xml_attrib(attrib_name: str, attrib_val: bool | None) -> str:
50
50
  if attrib_val is None:
51
51
  return ""
52
52
 
@@ -147,7 +147,7 @@ def write_pdx_file(
147
147
  jinja_env.globals["make_bool_xml_attrib"] = make_bool_xml_attrib
148
148
  jinja_env.globals["get_parent_container_name"] = get_parent_container_name
149
149
 
150
- vars: Dict[str, Any] = {}
150
+ vars: dict[str, Any] = {}
151
151
  vars["odxtools_version"] = odxtools.__version__
152
152
  vars["database"] = database
153
153
 
odxtools/xdoc.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import NamedElement
@@ -11,15 +11,15 @@ from .utils import dataclass_fields_asdict
11
11
 
12
12
  @dataclass
13
13
  class XDoc(NamedElement):
14
- number: Optional[str]
15
- state: Optional[str]
16
- date: Optional[str]
17
- publisher: Optional[str]
18
- url: Optional[str]
19
- position: Optional[str]
14
+ number: str | None
15
+ state: str | None
16
+ date: str | None
17
+ publisher: str | None
18
+ url: str | None
19
+ position: str | None
20
20
 
21
21
  @staticmethod
22
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "XDoc":
22
+ def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "XDoc":
23
23
  kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
24
24
  number = et_element.findtext("NUMBER")
25
25
  state = et_element.findtext("STATE")
@@ -37,7 +37,7 @@ class XDoc(NamedElement):
37
37
  position=position,
38
38
  **kwargs)
39
39
 
40
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
40
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
41
41
  return {}
42
42
 
43
43
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: odxtools
3
- Version: 9.7.0
3
+ Version: 10.0.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>
@@ -10,16 +10,16 @@ Project-URL: Bug Tracker, https://github.com/mercedes-benz/odxtools/issues
10
10
  Project-URL: Repository, https://github.com/mercedes-benz/odxtools
11
11
  Keywords: can,can bus,DoIP,odx,pdx,obd,uds,automotive,diagnostics
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.8
14
- Classifier: Programming Language :: Python :: 3.9
15
13
  Classifier: Programming Language :: Python :: 3.10
16
14
  Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Development Status :: 5 - Production/Stable
18
18
  Classifier: Environment :: Console
19
19
  Classifier: Intended Audience :: Developers
20
20
  Classifier: License :: OSI Approved :: MIT License
21
21
  Classifier: Operating System :: OS Independent
22
- Requires-Python: >=3.8
22
+ Requires-Python: >=3.10
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Requires-Dist: bitstruct>=8.17
@@ -35,7 +35,6 @@ Provides-Extra: browse-tool
35
35
  Requires-Dist: InquirerPy>=0.3.4; extra == "browse-tool"
36
36
  Provides-Extra: test
37
37
  Requires-Dist: mypy>=1.5; extra == "test"
38
- Requires-Dist: types-tabulate>=0.9.0.3; extra == "test"
39
38
  Requires-Dist: ruff>=0.0.290; extra == "test"
40
39
  Requires-Dist: pytest>=7.4; extra == "test"
41
40
  Requires-Dist: coverage>=7.3; extra == "test"