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
odxtools/database.py CHANGED
@@ -1,8 +1,9 @@
1
1
  # SPDX-License-Identifier: MIT
2
+ from collections import OrderedDict
2
3
  from itertools import chain
3
4
  from os import PathLike
4
5
  from pathlib import Path
5
- from typing import IO, Any, Dict, List, Optional, OrderedDict, Union
6
+ from typing import IO, Any, Union
6
7
  from xml.etree import ElementTree
7
8
  from zipfile import ZipFile
8
9
 
@@ -19,7 +20,8 @@ from .diaglayers.functionalgroup import FunctionalGroup
19
20
  from .diaglayers.protocol import Protocol
20
21
  from .exceptions import odxraise, odxrequire
21
22
  from .nameditemlist import NamedItemList
22
- from .odxlink import OdxLinkDatabase, OdxLinkId
23
+ from .odxdoccontext import OdxDocContext
24
+ from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
23
25
  from .snrefcontext import SnRefContext
24
26
 
25
27
 
@@ -30,7 +32,7 @@ class Database:
30
32
  """
31
33
 
32
34
  def __init__(self) -> None:
33
- self.model_version: Optional[Version] = None
35
+ self.model_version: Version | None = None
34
36
  self.auxiliary_files: OrderedDict[str, IO[bytes]] = OrderedDict()
35
37
 
36
38
  # create an empty database object
@@ -68,17 +70,13 @@ class Database:
68
70
 
69
71
  def add_auxiliary_file(self,
70
72
  aux_file_name: Union[str, "PathLike[Any]"],
71
- aux_file_obj: Optional[IO[bytes]] = None) -> None:
73
+ aux_file_obj: IO[bytes] | None = None) -> None:
72
74
  if aux_file_obj is None:
73
75
  aux_file_obj = open(aux_file_name, "rb")
74
76
 
75
77
  self.auxiliary_files[str(aux_file_name)] = aux_file_obj
76
78
 
77
79
  def _process_xml_tree(self, root: ElementTree.Element) -> None:
78
- dlcs: List[DiagLayerContainer] = []
79
- comparam_subsets: List[ComparamSubset] = []
80
- comparam_specs: List[ComparamSpec] = []
81
-
82
80
  # ODX spec version
83
81
  model_version = Version(root.attrib.get("MODEL-VERSION", "2.0"))
84
82
  if self.model_version is not None and self.model_version != model_version:
@@ -87,28 +85,33 @@ class Database:
87
85
 
88
86
  self.model_version = model_version
89
87
 
90
- dlc = root.find("DIAG-LAYER-CONTAINER")
91
- if dlc is not None:
92
- dlcs.append(DiagLayerContainer.from_et(dlc, []))
93
-
94
- # In ODX 2.0 there was only COMPARAM-SPEC. In ODX 2.2 the
95
- # content of COMPARAM-SPEC was moved to COMPARAM-SUBSET
96
- # and COMPARAM-SPEC became a container for PROT-STACKS and
97
- # a PROT-STACK references a list of COMPARAM-SUBSET
98
- cp_subset = root.find("COMPARAM-SUBSET")
99
- if cp_subset is not None:
100
- comparam_subsets.append(ComparamSubset.from_et(cp_subset, []))
101
-
102
- cp_spec = root.find("COMPARAM-SPEC")
103
- if cp_spec is not None:
88
+ child_elements = list(root)
89
+ if len(child_elements) != 1:
90
+ odxraise("Each ODX document must contain exactly one category.")
91
+
92
+ category_et = child_elements[0]
93
+ category_sn = odxrequire(category_et.findtext("SHORT-NAME"))
94
+ category_tag = category_et.tag
95
+
96
+ if category_tag == "DIAG-LAYER-CONTAINER":
97
+ context = OdxDocContext(model_version,
98
+ (OdxDocFragment(category_sn, DocType.CONTAINER),))
99
+ self._diag_layer_containers.append(DiagLayerContainer.from_et(category_et, context))
100
+ elif category_tag == "COMPARAM-SUBSET":
101
+ context = OdxDocContext(model_version,
102
+ (OdxDocFragment(category_sn, DocType.COMPARAM_SUBSET),))
103
+ self._comparam_subsets.append(ComparamSubset.from_et(category_et, context))
104
+ elif category_tag == "COMPARAM-SPEC":
105
+ # In ODX 2.0 there was only COMPARAM-SPEC. In ODX 2.2 the
106
+ # content of COMPARAM-SPEC was moved to COMPARAM-SUBSET
107
+ # and COMPARAM-SPEC became a container for PROT-STACKS and
108
+ # a PROT-STACK references a list of COMPARAM-SUBSET
109
+ context = OdxDocContext(model_version,
110
+ (OdxDocFragment(category_sn, DocType.COMPARAM_SPEC),))
104
111
  if model_version < Version("2.2"):
105
- comparam_subsets.append(ComparamSubset.from_et(cp_spec, []))
106
- else: # odx >= 2.2
107
- comparam_specs.append(ComparamSpec.from_et(cp_spec, []))
108
-
109
- self._diag_layer_containers.extend(dlcs)
110
- self._comparam_subsets.extend(comparam_subsets)
111
- self._comparam_specs.extend(comparam_specs)
112
+ self._comparam_subsets.append(ComparamSubset.from_et(category_et, context))
113
+ else:
114
+ self._comparam_specs.append(ComparamSpec.from_et(category_et, context))
112
115
 
113
116
  def refresh(self) -> None:
114
117
  # Create wrapper objects
@@ -160,8 +163,8 @@ class Database:
160
163
  for dlc in self.diag_layer_containers:
161
164
  dlc._resolve_snrefs(context)
162
165
 
163
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
164
- result: Dict[OdxLinkId, Any] = {}
166
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
167
+ result: dict[OdxLinkId, Any] = {}
165
168
 
166
169
  for subset in self.comparam_subsets:
167
170
  result.update(subset._build_odxlinks())
@@ -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 .compumethods.compumethod import CompuMethod
@@ -12,7 +12,8 @@ from .dopbase import DopBase
12
12
  from .encodestate import EncodeState
13
13
  from .exceptions import EncodeError, odxraise, odxrequire
14
14
  from .internalconstr import InternalConstr
15
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
15
+ from .odxdoccontext import OdxDocContext
16
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
16
17
  from .odxtypes import AtomicOdxType, BytesTypes, ParameterValue
17
18
  from .physicaltype import PhysicalType
18
19
  from .snrefcontext import SnRefContext
@@ -20,7 +21,7 @@ from .unit import Unit
20
21
  from .utils import dataclass_fields_asdict
21
22
 
22
23
 
23
- @dataclass
24
+ @dataclass(kw_only=True)
24
25
  class DataObjectProperty(DopBase):
25
26
  """This class represents a DATA-OBJECT-PROP.
26
27
 
@@ -37,42 +38,40 @@ class DataObjectProperty(DopBase):
37
38
  #: The type of the value in the physical world
38
39
  physical_type: PhysicalType
39
40
 
40
- internal_constr: Optional[InternalConstr]
41
+ internal_constr: InternalConstr | None = None
41
42
 
42
43
  #: The unit associated with physical values (e.g. 'm/s^2')
43
- unit_ref: Optional[OdxLinkRef]
44
+ unit_ref: OdxLinkRef | None = None
44
45
 
45
- physical_constr: Optional[InternalConstr]
46
+ physical_constr: InternalConstr | None = None
46
47
 
47
48
  @property
48
- def unit(self) -> Optional[Unit]:
49
+ def unit(self) -> Unit | None:
49
50
  return self._unit
50
51
 
51
52
  @staticmethod
52
- def from_et(et_element: ElementTree.Element,
53
- doc_frags: List[OdxDocFragment]) -> "DataObjectProperty":
53
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DataObjectProperty":
54
54
  """Reads a DATA-OBJECT-PROP."""
55
- kwargs = dataclass_fields_asdict(DopBase.from_et(et_element, doc_frags))
55
+ kwargs = dataclass_fields_asdict(DopBase.from_et(et_element, context))
56
56
 
57
57
  diag_coded_type = create_any_diag_coded_type_from_et(
58
- odxrequire(et_element.find("DIAG-CODED-TYPE")), doc_frags)
59
- physical_type = PhysicalType.from_et(
60
- odxrequire(et_element.find("PHYSICAL-TYPE")), doc_frags)
58
+ odxrequire(et_element.find("DIAG-CODED-TYPE")), context)
59
+ physical_type = PhysicalType.from_et(odxrequire(et_element.find("PHYSICAL-TYPE")), context)
61
60
  compu_method = create_any_compu_method_from_et(
62
61
  odxrequire(et_element.find("COMPU-METHOD")),
63
- doc_frags,
62
+ context,
64
63
  internal_type=diag_coded_type.base_data_type,
65
64
  physical_type=physical_type.base_data_type,
66
65
  )
67
66
  internal_constr = None
68
67
  if (internal_constr_elem := et_element.find("INTERNAL-CONSTR")) is not None:
69
68
  internal_constr = InternalConstr.constr_from_et(
70
- internal_constr_elem, doc_frags, value_type=diag_coded_type.base_data_type)
71
- unit_ref = OdxLinkRef.from_et(et_element.find("UNIT-REF"), doc_frags)
69
+ internal_constr_elem, context, value_type=diag_coded_type.base_data_type)
70
+ unit_ref = OdxLinkRef.from_et(et_element.find("UNIT-REF"), context)
72
71
  physical_constr = None
73
72
  if (physical_constr_elem := et_element.find("PHYS-CONSTR")) is not None:
74
73
  physical_constr = InternalConstr.constr_from_et(
75
- physical_constr_elem, doc_frags, value_type=physical_type.base_data_type)
74
+ physical_constr_elem, context, value_type=physical_type.base_data_type)
76
75
 
77
76
  return DataObjectProperty(
78
77
  compu_method=compu_method,
@@ -83,7 +82,7 @@ class DataObjectProperty(DopBase):
83
82
  physical_constr=physical_constr,
84
83
  **kwargs)
85
84
 
86
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
85
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
87
86
  result = super()._build_odxlinks()
88
87
  result.update(self.compu_method._build_odxlinks())
89
88
  result.update(self.diag_coded_type._build_odxlinks())
@@ -96,7 +95,7 @@ class DataObjectProperty(DopBase):
96
95
  self.compu_method._resolve_odxlinks(odxlinks)
97
96
  self.diag_coded_type._resolve_odxlinks(odxlinks)
98
97
 
99
- self._unit: Optional[Unit] = None
98
+ self._unit: Unit | None = None
100
99
  if self.unit_ref:
101
100
  self._unit = odxlinks.resolve(self.unit_ref, Unit)
102
101
 
@@ -106,7 +105,7 @@ class DataObjectProperty(DopBase):
106
105
  self.compu_method._resolve_snrefs(context)
107
106
  self.diag_coded_type._resolve_snrefs(context)
108
107
 
109
- def get_static_bit_length(self) -> Optional[int]:
108
+ def get_static_bit_length(self) -> int | None:
110
109
  return self.diag_coded_type.get_static_bit_length()
111
110
 
112
111
  def encode_into_pdu(self, physical_value: ParameterValue, encode_state: EncodeState) -> None:
odxtools/decodestate.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass, field
3
- from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from .encoding import Encoding, get_string_encoding
6
6
  from .exceptions import DecodeError, odxassert, odxraise, strict_mode
@@ -41,22 +41,22 @@ class DecodeState:
41
41
  cursor_bit_position: int = 0
42
42
 
43
43
  #: values of the length key parameters decoded so far
44
- length_keys: Dict[str, int] = field(default_factory=dict)
44
+ length_keys: dict[str, int] = field(default_factory=dict)
45
45
 
46
46
  #: values of the table key parameters decoded so far
47
- table_keys: Dict[str, "TableRow"] = field(default_factory=dict)
47
+ table_keys: dict[str, "TableRow"] = field(default_factory=dict)
48
48
 
49
49
  #: List of parameters that have been decoded so far. The journal
50
50
  #: is used by some types of parameters which depend on the values of
51
51
  #: other parameters; i.e., environment data description parameters
52
- journal: List[Tuple["Parameter", Optional[ParameterValue]]] = field(default_factory=list)
52
+ journal: list[tuple["Parameter", ParameterValue | None]] = field(default_factory=list)
53
53
 
54
54
  def extract_atomic_value(
55
55
  self,
56
56
  *,
57
57
  bit_length: int,
58
58
  base_data_type: DataType,
59
- base_type_encoding: Optional[Encoding],
59
+ base_type_encoding: Encoding | None,
60
60
  is_highlow_byte_order: bool,
61
61
  ) -> AtomicOdxType:
62
62
  """Extract an internal value from a blob of raw bytes.
odxtools/description.py CHANGED
@@ -1,22 +1,22 @@
1
- from dataclasses import dataclass
2
- from typing import List, Optional
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional
3
3
  from xml.etree import ElementTree
4
4
 
5
5
  from .exceptions import odxrequire
6
6
  from .externaldoc import ExternalDoc
7
- from .odxlink import OdxDocFragment
7
+ from .odxdoccontext import OdxDocContext
8
8
 
9
9
 
10
- @dataclass
10
+ @dataclass(kw_only=True)
11
11
  class Description:
12
12
  text: str
13
- external_docs: List[ExternalDoc]
13
+ external_docs: list[ExternalDoc] = field(default_factory=list)
14
14
 
15
- text_identifier: Optional[str]
15
+ text_identifier: str | None = None
16
16
 
17
17
  @staticmethod
18
- def from_et(et_element: Optional[ElementTree.Element],
19
- doc_frags: List[OdxDocFragment]) -> Optional["Description"]:
18
+ def from_et(et_element: ElementTree.Element | None,
19
+ context: OdxDocContext) -> Optional["Description"]:
20
20
  if et_element is None:
21
21
  return None
22
22
 
@@ -35,7 +35,7 @@ class Description:
35
35
 
36
36
  external_docs = \
37
37
  [
38
- odxrequire(ExternalDoc.from_et(ed, doc_frags)) for ed in et_element.iterfind("EXTERNAL-DOCS/EXTERNAL-DOC")
38
+ odxrequire(ExternalDoc.from_et(ed, context)) for ed in et_element.iterfind("EXTERNAL-DOCS/EXTERNAL-DOC")
39
39
  ]
40
40
 
41
41
  text_identifier = et_element.attrib.get("TI")
@@ -1,21 +1,22 @@
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 .dataobjectproperty import DataObjectProperty
7
7
  from .exceptions import odxrequire
8
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
8
+ from .odxdoccontext import OdxDocContext
9
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
10
  from .snrefcontext import SnRefContext
10
11
 
11
12
 
12
- @dataclass
13
+ @dataclass(kw_only=True)
13
14
  class DetermineNumberOfItems:
14
15
  """
15
16
  The object that determines the number of items of dynamic fields
16
17
  """
17
18
  byte_position: int
18
- bit_position: Optional[int]
19
+ bit_position: int | None = None
19
20
  dop_ref: OdxLinkRef
20
21
 
21
22
  @property
@@ -24,11 +25,11 @@ class DetermineNumberOfItems:
24
25
 
25
26
  @staticmethod
26
27
  def from_et(et_element: ElementTree.Element,
27
- doc_frags: List[OdxDocFragment]) -> "DetermineNumberOfItems":
28
+ context: OdxDocContext) -> "DetermineNumberOfItems":
28
29
  byte_position = int(odxrequire(et_element.findtext("BYTE-POSITION")))
29
30
  bit_position_str = et_element.findtext("BIT-POSITION")
30
31
  bit_position = int(bit_position_str) if bit_position_str is not None else None
31
- dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), doc_frags))
32
+ dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), context))
32
33
 
33
34
  return DetermineNumberOfItems(
34
35
  byte_position=byte_position,
@@ -36,7 +37,7 @@ class DetermineNumberOfItems:
36
37
  dop_ref=dop_ref,
37
38
  )
38
39
 
39
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
40
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
40
41
  return {}
41
42
 
42
43
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
odxtools/diagcodedtype.py CHANGED
@@ -1,13 +1,14 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Literal, Optional, Union, cast
3
+ from typing import Any, Literal, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .decodestate import DecodeState
7
7
  from .encodestate import EncodeState
8
8
  from .encoding import Encoding
9
9
  from .exceptions import odxassert, odxraise, odxrequire
10
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId
11
12
  from .odxtypes import AtomicOdxType, DataType, odxstr_to_bool
12
13
  from .snrefcontext import SnRefContext
13
14
 
@@ -20,12 +21,12 @@ DctType = Literal[
20
21
  ]
21
22
 
22
23
 
23
- @dataclass
24
+ @dataclass(kw_only=True)
24
25
  class DiagCodedType:
25
- base_type_encoding: Optional[Encoding]
26
+ base_type_encoding: Encoding | None = None
26
27
  base_data_type: DataType
27
28
 
28
- is_highlow_byte_order_raw: Optional[bool]
29
+ is_highlow_byte_order_raw: bool | None = None
29
30
 
30
31
  @property
31
32
  def dct_type(self) -> DctType:
@@ -38,8 +39,7 @@ class DiagCodedType:
38
39
  return self.is_highlow_byte_order_raw in [None, True]
39
40
 
40
41
  @staticmethod
41
- def from_et(et_element: ElementTree.Element,
42
- doc_frags: List[OdxDocFragment]) -> "DiagCodedType":
42
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DiagCodedType":
43
43
  base_type_encoding = None
44
44
  if (base_type_encoding_str := et_element.get("BASE-TYPE-ENCODING")) is not None:
45
45
  try:
@@ -61,7 +61,7 @@ class DiagCodedType:
61
61
  base_data_type=base_data_type,
62
62
  is_highlow_byte_order_raw=is_highlow_byte_order_raw)
63
63
 
64
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]: # noqa: B027
64
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]: # noqa: B027
65
65
  return {}
66
66
 
67
67
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None: # noqa: B027
@@ -72,10 +72,10 @@ class DiagCodedType:
72
72
  """Recursively resolve any short-name references"""
73
73
  pass
74
74
 
75
- def get_static_bit_length(self) -> Optional[int]:
75
+ def get_static_bit_length(self) -> int | None:
76
76
  return None
77
77
 
78
- def _minimal_byte_length_of(self, internal_value: Union[bytes, str]) -> int:
78
+ def _minimal_byte_length_of(self, internal_value: bytes | str) -> int:
79
79
  """Helper method to get the minimal byte length.
80
80
  (needed for LeadingLength- and MinMaxLengthType)
81
81
  """
odxtools/diagcomm.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
2
+ from dataclasses import dataclass, field
3
+ from typing import TYPE_CHECKING, Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
@@ -10,7 +10,8 @@ from .element import IdentifiableElement
10
10
  from .exceptions import odxraise, odxrequire
11
11
  from .functionalclass import FunctionalClass
12
12
  from .nameditemlist import NamedItemList
13
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
13
+ from .odxdoccontext import OdxDocContext
14
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
14
15
  from .odxtypes import odxstr_to_bool
15
16
  from .preconditionstateref import PreConditionStateRef
16
17
  from .relateddiagcommref import RelatedDiagCommRef
@@ -25,7 +26,7 @@ if TYPE_CHECKING:
25
26
  from .diaglayers.protocol import Protocol
26
27
 
27
28
 
28
- @dataclass
29
+ @dataclass(kw_only=True)
29
30
  class DiagComm(IdentifiableElement):
30
31
  """Representation of a diagnostic communication object.
31
32
 
@@ -34,21 +35,21 @@ class DiagComm(IdentifiableElement):
34
35
 
35
36
  """
36
37
 
37
- admin_data: Optional[AdminData]
38
- sdgs: List[SpecialDataGroup]
39
- functional_class_refs: List[OdxLinkRef]
40
- audience: Optional[Audience]
41
- protocol_snrefs: List[str]
42
- related_diag_comm_refs: List[RelatedDiagCommRef]
43
- pre_condition_state_refs: List[PreConditionStateRef]
44
- state_transition_refs: List[StateTransitionRef]
38
+ admin_data: AdminData | None = None
39
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
40
+ functional_class_refs: list[OdxLinkRef] = field(default_factory=list)
41
+ audience: Audience | None = None
42
+ protocol_snrefs: list[str] = field(default_factory=list)
43
+ related_diag_comm_refs: list[RelatedDiagCommRef] = field(default_factory=list)
44
+ pre_condition_state_refs: list[PreConditionStateRef] = field(default_factory=list)
45
+ state_transition_refs: list[StateTransitionRef] = field(default_factory=list)
45
46
 
46
47
  # attributes
47
- semantic: Optional[str]
48
- diagnostic_class: Optional[DiagClassType]
49
- is_mandatory_raw: Optional[bool]
50
- is_executable_raw: Optional[bool]
51
- is_final_raw: Optional[bool]
48
+ semantic: str | None = None
49
+ diagnostic_class: DiagClassType | None = None
50
+ is_mandatory_raw: bool | None = None
51
+ is_executable_raw: bool | None = None
52
+ is_final_raw: bool | None = None
52
53
 
53
54
  @property
54
55
  def functional_classes(self) -> NamedItemList[FunctionalClass]:
@@ -83,22 +84,20 @@ class DiagComm(IdentifiableElement):
83
84
  return self.is_final_raw is True
84
85
 
85
86
  @staticmethod
86
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagComm":
87
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
87
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DiagComm":
88
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
88
89
 
89
- admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
90
- sdgs = [
91
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
92
- ]
90
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
91
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
93
92
 
94
93
  functional_class_refs = [
95
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
94
+ odxrequire(OdxLinkRef.from_et(el, context))
96
95
  for el in et_element.iterfind("FUNCT-CLASS-REFS/FUNCT-CLASS-REF")
97
96
  ]
98
97
 
99
98
  audience = None
100
99
  if (audience_elem := et_element.find("AUDIENCE")) is not None:
101
- audience = Audience.from_et(audience_elem, doc_frags)
100
+ audience = Audience.from_et(audience_elem, context)
102
101
 
103
102
  protocol_snrefs = [
104
103
  odxrequire(el.get("SHORT-NAME"))
@@ -106,23 +105,23 @@ class DiagComm(IdentifiableElement):
106
105
  ]
107
106
 
108
107
  related_diag_comm_refs = [
109
- RelatedDiagCommRef.from_et(el, doc_frags)
108
+ RelatedDiagCommRef.from_et(el, context)
110
109
  for el in et_element.iterfind("RELATED-DIAG-COMM-REFS/RELATED-DIAG-COMM-REF")
111
110
  ]
112
111
 
113
112
  pre_condition_state_refs = [
114
- PreConditionStateRef.from_et(el, doc_frags)
113
+ PreConditionStateRef.from_et(el, context)
115
114
  for el in et_element.iterfind("PRE-CONDITION-STATE-REFS/PRE-CONDITION-STATE-REF")
116
115
  ]
117
116
 
118
117
  state_transition_refs = [
119
- StateTransitionRef.from_et(el, doc_frags)
118
+ StateTransitionRef.from_et(el, context)
120
119
  for el in et_element.iterfind("STATE-TRANSITION-REFS/STATE-TRANSITION-REF")
121
120
  ]
122
121
 
123
122
  semantic = et_element.attrib.get("SEMANTIC")
124
123
 
125
- diagnostic_class: Optional[DiagClassType] = None
124
+ diagnostic_class: DiagClassType | None = None
126
125
  if (diagnostic_class_str := et_element.attrib.get("DIAGNOSTIC-CLASS")) is not None:
127
126
  try:
128
127
  diagnostic_class = DiagClassType(diagnostic_class_str)
@@ -149,7 +148,7 @@ class DiagComm(IdentifiableElement):
149
148
  is_final_raw=is_final_raw,
150
149
  **kwargs)
151
150
 
152
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
151
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
153
152
  result = {self.odx_id: self}
154
153
 
155
154
  if self.admin_data is not None: