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,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from itertools import chain
4
- from typing import Any, Dict, List, Optional
4
+ from typing import Any
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .admindata import AdminData
@@ -15,7 +15,8 @@ from .environmentdata import EnvironmentData
15
15
  from .environmentdatadescription import EnvironmentDataDescription
16
16
  from .multiplexer import Multiplexer
17
17
  from .nameditemlist import NamedItemList
18
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
18
+ from .odxdoccontext import OdxDocContext
19
+ from .odxlink import OdxLinkDatabase, OdxLinkId
19
20
  from .snrefcontext import SnRefContext
20
21
  from .specialdatagroup import SpecialDataGroup
21
22
  from .staticfield import StaticField
@@ -24,72 +25,73 @@ from .table import Table
24
25
  from .unitspec import UnitSpec
25
26
 
26
27
 
27
- @dataclass
28
+ @dataclass(kw_only=True)
28
29
  class DiagDataDictionarySpec:
29
- admin_data: Optional[AdminData]
30
- dtc_dops: NamedItemList[DtcDop]
31
- env_data_descs: NamedItemList[EnvironmentDataDescription]
32
- data_object_props: NamedItemList[DataObjectProperty]
33
- structures: NamedItemList[Structure]
34
- static_fields: NamedItemList[StaticField]
35
- dynamic_length_fields: NamedItemList[DynamicLengthField]
36
- dynamic_endmarker_fields: NamedItemList[DynamicEndmarkerField]
37
- end_of_pdu_fields: NamedItemList[EndOfPduField]
38
- muxs: NamedItemList[Multiplexer]
39
- env_datas: NamedItemList[EnvironmentData]
40
- unit_spec: Optional[UnitSpec]
41
- tables: NamedItemList[Table]
42
- sdgs: List[SpecialDataGroup]
30
+ admin_data: AdminData | None = None
31
+ dtc_dops: NamedItemList[DtcDop] = field(default_factory=NamedItemList)
32
+ env_data_descs: NamedItemList[EnvironmentDataDescription] = field(default_factory=NamedItemList)
33
+ data_object_props: NamedItemList[DataObjectProperty] = field(default_factory=NamedItemList)
34
+ structures: NamedItemList[Structure] = field(default_factory=NamedItemList)
35
+ static_fields: NamedItemList[StaticField] = field(default_factory=NamedItemList)
36
+ dynamic_length_fields: NamedItemList[DynamicLengthField] = field(default_factory=NamedItemList)
37
+ dynamic_endmarker_fields: NamedItemList[DynamicEndmarkerField] = field(
38
+ default_factory=NamedItemList)
39
+ end_of_pdu_fields: NamedItemList[EndOfPduField] = field(default_factory=NamedItemList)
40
+ muxs: NamedItemList[Multiplexer] = field(default_factory=NamedItemList)
41
+ env_datas: NamedItemList[EnvironmentData] = field(default_factory=NamedItemList)
42
+ unit_spec: UnitSpec | None = None
43
+ tables: NamedItemList[Table] = field(default_factory=NamedItemList)
44
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
43
45
 
44
46
  @staticmethod
45
47
  def from_et(et_element: ElementTree.Element,
46
- doc_frags: List[OdxDocFragment]) -> "DiagDataDictionarySpec":
48
+ context: OdxDocContext) -> "DiagDataDictionarySpec":
47
49
  admin_data = None
48
50
  if (admin_data_elem := et_element.find("ADMIN-DATA")) is not None:
49
- admin_data = AdminData.from_et(admin_data_elem, doc_frags)
51
+ admin_data = AdminData.from_et(admin_data_elem, context)
50
52
 
51
53
  dtc_dops = NamedItemList([
52
- DtcDop.from_et(dtc_dop_elem, doc_frags)
54
+ DtcDop.from_et(dtc_dop_elem, context)
53
55
  for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP")
54
56
  ])
55
57
 
56
58
  env_data_descs = NamedItemList([
57
- EnvironmentDataDescription.from_et(env_data_desc_element, doc_frags)
59
+ EnvironmentDataDescription.from_et(env_data_desc_element, context)
58
60
  for env_data_desc_element in et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC")
59
61
  ])
60
62
 
61
63
  data_object_props = NamedItemList([
62
- DataObjectProperty.from_et(dop_element, doc_frags)
64
+ DataObjectProperty.from_et(dop_element, context)
63
65
  for dop_element in et_element.iterfind("DATA-OBJECT-PROPS/DATA-OBJECT-PROP")
64
66
  ])
65
67
 
66
68
  structures = NamedItemList([
67
- Structure.from_et(structure_element, doc_frags)
69
+ Structure.from_et(structure_element, context)
68
70
  for structure_element in et_element.iterfind("STRUCTURES/STRUCTURE")
69
71
  ])
70
72
 
71
73
  static_fields = NamedItemList([
72
- StaticField.from_et(dl_element, doc_frags)
74
+ StaticField.from_et(dl_element, context)
73
75
  for dl_element in et_element.iterfind("STATIC-FIELDS/STATIC-FIELD")
74
76
  ])
75
77
 
76
78
  dynamic_length_fields = NamedItemList([
77
- DynamicLengthField.from_et(dl_element, doc_frags)
79
+ DynamicLengthField.from_et(dl_element, context)
78
80
  for dl_element in et_element.iterfind("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD")
79
81
  ])
80
82
 
81
83
  dynamic_endmarker_fields = NamedItemList([
82
- DynamicEndmarkerField.from_et(dl_element, doc_frags) for dl_element in
84
+ DynamicEndmarkerField.from_et(dl_element, context) for dl_element in
83
85
  et_element.iterfind("DYNAMIC-ENDMARKER-FIELDS/DYNAMIC-ENDMARKER-FIELD")
84
86
  ])
85
87
 
86
88
  end_of_pdu_fields = NamedItemList([
87
- EndOfPduField.from_et(eofp_element, doc_frags)
89
+ EndOfPduField.from_et(eofp_element, context)
88
90
  for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD")
89
91
  ])
90
92
 
91
93
  muxs = NamedItemList([
92
- Multiplexer.from_et(mux_element, doc_frags)
94
+ Multiplexer.from_et(mux_element, context)
93
95
  for mux_element in et_element.iterfind("MUXS/MUX")
94
96
  ])
95
97
 
@@ -99,23 +101,21 @@ class DiagDataDictionarySpec:
99
101
  et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC/ENV-DATAS/ENV-DATA"),
100
102
  )
101
103
  env_datas = NamedItemList([
102
- EnvironmentData.from_et(env_data_element, doc_frags)
104
+ EnvironmentData.from_et(env_data_element, context)
103
105
  for env_data_element in env_data_elements
104
106
  ])
105
107
 
106
108
  if (spec_elem := et_element.find("UNIT-SPEC")) is not None:
107
- unit_spec = UnitSpec.from_et(spec_elem, doc_frags)
109
+ unit_spec = UnitSpec.from_et(spec_elem, context)
108
110
  else:
109
111
  unit_spec = None
110
112
 
111
113
  tables = NamedItemList([
112
- Table.from_et(table_element, doc_frags)
114
+ Table.from_et(table_element, context)
113
115
  for table_element in et_element.iterfind("TABLES/TABLE")
114
116
  ])
115
117
 
116
- sdgs = [
117
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
118
- ]
118
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
119
119
 
120
120
  return DiagDataDictionarySpec(
121
121
  admin_data=admin_data,
@@ -149,7 +149,7 @@ class DiagDataDictionarySpec:
149
149
  self.env_datas,
150
150
  ))
151
151
 
152
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
152
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
153
153
  # note that DataDictionarySpec objects do not exhibit an ODXLINK id.
154
154
  odxlinks = {}
155
155
 
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from itertools import chain
4
- from typing import TYPE_CHECKING, Any, Dict, List, Union
4
+ from typing import TYPE_CHECKING, Any
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .diaglayers.basevariant import BaseVariant
@@ -10,8 +10,10 @@ from .diaglayers.ecushareddata import EcuSharedData
10
10
  from .diaglayers.ecuvariant import EcuVariant
11
11
  from .diaglayers.functionalgroup import FunctionalGroup
12
12
  from .diaglayers.protocol import Protocol
13
+ from .exceptions import odxrequire
13
14
  from .nameditemlist import NamedItemList
14
15
  from .odxcategory import OdxCategory
16
+ from .odxdoccontext import OdxDocContext
15
17
  from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
16
18
  from .snrefcontext import SnRefContext
17
19
  from .utils import dataclass_fields_asdict
@@ -20,13 +22,13 @@ if TYPE_CHECKING:
20
22
  from .database import Database
21
23
 
22
24
 
23
- @dataclass
25
+ @dataclass(kw_only=True)
24
26
  class DiagLayerContainer(OdxCategory):
25
- protocols: NamedItemList[Protocol]
26
- functional_groups: NamedItemList[FunctionalGroup]
27
- ecu_shared_datas: NamedItemList[EcuSharedData]
28
- base_variants: NamedItemList[BaseVariant]
29
- ecu_variants: NamedItemList[EcuVariant]
27
+ protocols: NamedItemList[Protocol] = field(default_factory=NamedItemList)
28
+ functional_groups: NamedItemList[FunctionalGroup] = field(default_factory=NamedItemList)
29
+ ecu_shared_datas: NamedItemList[EcuSharedData] = field(default_factory=NamedItemList)
30
+ base_variants: NamedItemList[BaseVariant] = field(default_factory=NamedItemList)
31
+ ecu_variants: NamedItemList[EcuVariant] = field(default_factory=NamedItemList)
30
32
 
31
33
  @property
32
34
  def diag_layers(self) -> NamedItemList[DiagLayer]:
@@ -40,33 +42,32 @@ class DiagLayerContainer(OdxCategory):
40
42
  return self.ecu_variants
41
43
 
42
44
  @staticmethod
43
- def from_et(et_element: ElementTree.Element,
44
- doc_frags: List[OdxDocFragment]) -> "DiagLayerContainer":
45
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DiagLayerContainer":
45
46
 
46
- cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type=DocType.CONTAINER)
47
- doc_frags = cat.odx_id.doc_fragments
47
+ cat = OdxCategory.from_et(et_element, context)
48
48
  kwargs = dataclass_fields_asdict(cat)
49
49
 
50
- protocols = NamedItemList([
51
- Protocol.from_et(dl_element, doc_frags)
52
- for dl_element in et_element.iterfind("PROTOCOLS/PROTOCOL")
53
- ])
54
- functional_groups = NamedItemList([
55
- FunctionalGroup.from_et(dl_element, doc_frags)
56
- for dl_element in et_element.iterfind("FUNCTIONAL-GROUPS/FUNCTIONAL-GROUP")
57
- ])
58
- ecu_shared_datas = NamedItemList([
59
- EcuSharedData.from_et(dl_element, doc_frags)
60
- for dl_element in et_element.iterfind("ECU-SHARED-DATAS/ECU-SHARED-DATA")
61
- ])
62
- base_variants = NamedItemList([
63
- BaseVariant.from_et(dl_element, doc_frags)
64
- for dl_element in et_element.iterfind("BASE-VARIANTS/BASE-VARIANT")
65
- ])
66
- ecu_variants = NamedItemList([
67
- EcuVariant.from_et(dl_element, doc_frags)
68
- for dl_element in et_element.iterfind("ECU-VARIANTS/ECU-VARIANT")
69
- ])
50
+ def get_layer_context(diag_layer_et: ElementTree.Element) -> OdxDocContext:
51
+ layer_sn = odxrequire(diag_layer_et.findtext("SHORT-NAME"))
52
+ layer_docfrag = OdxDocFragment(layer_sn, DocType.LAYER)
53
+ # add layer doc fragment to container doc fragment
54
+ return OdxDocContext(context.version, (context.doc_fragments[0], layer_docfrag))
55
+
56
+ protocols = NamedItemList(
57
+ Protocol.from_et(layer_et, get_layer_context(layer_et))
58
+ for layer_et in et_element.iterfind("PROTOCOLS/PROTOCOL"))
59
+ functional_groups = NamedItemList(
60
+ FunctionalGroup.from_et(layer_et, get_layer_context(layer_et))
61
+ for layer_et in et_element.iterfind("FUNCTIONAL-GROUPS/FUNCTIONAL-GROUP"))
62
+ ecu_shared_datas = NamedItemList(
63
+ EcuSharedData.from_et(layer_et, get_layer_context(layer_et))
64
+ for layer_et in et_element.iterfind("ECU-SHARED-DATAS/ECU-SHARED-DATA"))
65
+ base_variants = NamedItemList(
66
+ BaseVariant.from_et(layer_et, get_layer_context(layer_et))
67
+ for layer_et in et_element.iterfind("BASE-VARIANTS/BASE-VARIANT"))
68
+ ecu_variants = NamedItemList(
69
+ EcuVariant.from_et(layer_et, get_layer_context(layer_et))
70
+ for layer_et in et_element.iterfind("ECU-VARIANTS/ECU-VARIANT"))
70
71
 
71
72
  return DiagLayerContainer(
72
73
  protocols=protocols,
@@ -85,7 +86,7 @@ class DiagLayerContainer(OdxCategory):
85
86
  self.ecu_variants,
86
87
  ),)
87
88
 
88
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
89
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
89
90
  result = super()._build_odxlinks()
90
91
 
91
92
  for protocol in self.protocols:
@@ -132,5 +133,5 @@ class DiagLayerContainer(OdxCategory):
132
133
  def _resolve_snrefs(self, context: SnRefContext) -> None:
133
134
  super()._resolve_snrefs(context)
134
135
 
135
- def __getitem__(self, key: Union[int, str]) -> DiagLayer:
136
+ def __getitem__(self, key: int | str) -> DiagLayer:
136
137
  return self.diag_layers[key]
@@ -1,7 +1,8 @@
1
1
  # SPDX-License-Identifier: MIT
2
+ from collections.abc import Iterable
2
3
  from copy import deepcopy
3
4
  from dataclasses import dataclass
4
- from typing import Any, Dict, Iterable, List, Optional, Union, cast
5
+ from typing import Any, cast
5
6
  from xml.etree import ElementTree
6
7
 
7
8
  from typing_extensions import override
@@ -11,7 +12,8 @@ from ..diagvariable import DiagVariable
11
12
  from ..dyndefinedspec import DynDefinedSpec
12
13
  from ..exceptions import odxassert
13
14
  from ..nameditemlist import NamedItemList
14
- from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef
15
+ from ..odxdoccontext import OdxDocContext
16
+ from ..odxlink import OdxLinkDatabase, OdxLinkRef
15
17
  from ..parentref import ParentRef
16
18
  from ..variablegroup import VariableGroup
17
19
  from .basevariantraw import BaseVariantRaw
@@ -19,7 +21,7 @@ from .diaglayer import DiagLayer
19
21
  from .hierarchyelement import HierarchyElement
20
22
 
21
23
 
22
- @dataclass
24
+ @dataclass(kw_only=True)
23
25
  class BaseVariant(HierarchyElement):
24
26
  """This is a diagnostic layer for common functionality of an ECU
25
27
  """
@@ -32,19 +34,19 @@ class BaseVariant(HierarchyElement):
32
34
  # <properties forwarded to the "raw" base variant>
33
35
  #####
34
36
  @property
35
- def diag_variables_raw(self) -> List[Union[DiagVariable, OdxLinkRef]]:
37
+ def diag_variables_raw(self) -> list[DiagVariable | OdxLinkRef]:
36
38
  return self.base_variant_raw.diag_variables_raw
37
39
 
38
40
  @property
39
- def dyn_defined_spec(self) -> Optional[DynDefinedSpec]:
41
+ def dyn_defined_spec(self) -> DynDefinedSpec | None:
40
42
  return self.base_variant_raw.dyn_defined_spec
41
43
 
42
44
  @property
43
- def base_variant_pattern(self) -> Optional[BaseVariantPattern]:
45
+ def base_variant_pattern(self) -> BaseVariantPattern | None:
44
46
  return self.base_variant_raw.base_variant_pattern
45
47
 
46
48
  @property
47
- def parent_refs(self) -> List[ParentRef]:
49
+ def parent_refs(self) -> list[ParentRef]:
48
50
  return self.base_variant_raw.parent_refs
49
51
 
50
52
  #####
@@ -67,8 +69,8 @@ class BaseVariant(HierarchyElement):
67
69
  #######
68
70
 
69
71
  @staticmethod
70
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "BaseVariant":
71
- base_variant_raw = BaseVariantRaw.from_et(et_element, doc_frags)
72
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "BaseVariant":
73
+ base_variant_raw = BaseVariantRaw.from_et(et_element, context)
72
74
 
73
75
  return BaseVariant(diag_layer_raw=base_variant_raw)
74
76
 
@@ -80,7 +82,7 @@ class BaseVariant(HierarchyElement):
80
82
  "The raw diagnostic layer passed to BaseVariant "
81
83
  "must be a BaseVariantRaw")
82
84
 
83
- def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
85
+ def __deepcopy__(self, memo: dict[int, Any]) -> Any:
84
86
  """Create a deep copy of the base variant
85
87
 
86
88
  Note that the copied diagnostic layer is not fully
@@ -113,7 +115,7 @@ class BaseVariant(HierarchyElement):
113
115
 
114
116
  return dl.diag_layer_raw.diag_variables # type: ignore[no-any-return]
115
117
 
116
- def not_inherited_fn(parent_ref: ParentRef) -> List[str]:
118
+ def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
117
119
  return parent_ref.not_inherited_variables
118
120
 
119
121
  return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
@@ -127,7 +129,7 @@ class BaseVariant(HierarchyElement):
127
129
 
128
130
  return dl.diag_layer_raw.variable_groups # type: ignore[no-any-return]
129
131
 
130
- def not_inherited_fn(parent_ref: ParentRef) -> List[str]:
132
+ def not_inherited_fn(parent_ref: ParentRef) -> list[str]:
131
133
  return []
132
134
 
133
135
  return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional, Union
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from ..basevariantpattern import BaseVariantPattern
@@ -8,7 +8,8 @@ from ..diagvariable import DiagVariable
8
8
  from ..dyndefinedspec import DynDefinedSpec
9
9
  from ..exceptions import odxraise
10
10
  from ..nameditemlist import NamedItemList
11
- from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from ..odxdoccontext import OdxDocContext
12
+ from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
12
13
  from ..parentref import ParentRef
13
14
  from ..snrefcontext import SnRefContext
14
15
  from ..utils import dataclass_fields_asdict
@@ -16,60 +17,58 @@ from ..variablegroup import VariableGroup
16
17
  from .hierarchyelementraw import HierarchyElementRaw
17
18
 
18
19
 
19
- @dataclass
20
+ @dataclass(kw_only=True)
20
21
  class BaseVariantRaw(HierarchyElementRaw):
21
22
  """This is a diagnostic layer for common functionality of an ECU
22
23
  """
23
24
 
24
- diag_variables_raw: List[Union[DiagVariable, OdxLinkRef]]
25
- variable_groups: NamedItemList[VariableGroup]
26
- dyn_defined_spec: Optional[DynDefinedSpec]
27
- base_variant_pattern: Optional[BaseVariantPattern]
28
- parent_refs: List[ParentRef]
25
+ diag_variables_raw: list[DiagVariable | OdxLinkRef] = field(default_factory=list)
26
+ variable_groups: NamedItemList[VariableGroup] = field(default_factory=NamedItemList)
27
+ dyn_defined_spec: DynDefinedSpec | None = None
28
+ base_variant_pattern: BaseVariantPattern | None = None
29
+ parent_refs: list[ParentRef] = field(default_factory=list)
29
30
 
30
31
  @property
31
32
  def diag_variables(self) -> NamedItemList[DiagVariable]:
32
33
  return self._diag_variables
33
34
 
34
35
  @staticmethod
35
- def from_et(et_element: ElementTree.Element,
36
- doc_frags: List[OdxDocFragment]) -> "BaseVariantRaw":
37
- # objects contained by diagnostic layers exibit an additional
36
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "BaseVariantRaw":
37
+ # objects contained by diagnostic layers exhibit an additional
38
38
  # document fragment for the diag layer, so we use the document
39
39
  # fragments of the odx id of the diag layer for IDs of
40
40
  # contained objects.
41
- her = HierarchyElementRaw.from_et(et_element, doc_frags)
41
+ her = HierarchyElementRaw.from_et(et_element, context)
42
42
  kwargs = dataclass_fields_asdict(her)
43
- doc_frags = her.odx_id.doc_fragments
44
43
 
45
- diag_variables_raw: List[Union[DiagVariable, OdxLinkRef]] = []
44
+ diag_variables_raw: list[DiagVariable | OdxLinkRef] = []
46
45
  if (dv_elems := et_element.find("DIAG-VARIABLES")) is not None:
47
46
  for dv_proxy_elem in dv_elems:
48
- dv_proxy: Union[OdxLinkRef, DiagVariable]
47
+ dv_proxy: OdxLinkRef | DiagVariable
49
48
  if dv_proxy_elem.tag == "DIAG-VARIABLE-REF":
50
- dv_proxy = OdxLinkRef.from_et(dv_proxy_elem, doc_frags)
49
+ dv_proxy = OdxLinkRef.from_et(dv_proxy_elem, context)
51
50
  elif dv_proxy_elem.tag == "DIAG-VARIABLE":
52
- dv_proxy = DiagVariable.from_et(dv_proxy_elem, doc_frags)
51
+ dv_proxy = DiagVariable.from_et(dv_proxy_elem, context)
53
52
  else:
54
53
  odxraise()
55
54
 
56
55
  diag_variables_raw.append(dv_proxy)
57
56
 
58
57
  variable_groups = NamedItemList([
59
- VariableGroup.from_et(vg_elem, doc_frags)
58
+ VariableGroup.from_et(vg_elem, context)
60
59
  for vg_elem in et_element.iterfind("VARIABLE-GROUPS/VARIABLE-GROUP")
61
60
  ])
62
61
 
63
62
  dyn_defined_spec = None
64
63
  if (dds_elem := et_element.find("DYN-DEFINED-SPEC")) is not None:
65
- dyn_defined_spec = DynDefinedSpec.from_et(dds_elem, doc_frags)
64
+ dyn_defined_spec = DynDefinedSpec.from_et(dds_elem, context)
66
65
 
67
66
  base_variant_pattern = None
68
67
  if (bvp_elem := et_element.find("BASE-VARIANT-PATTERN")) is not None:
69
- base_variant_pattern = BaseVariantPattern.from_et(bvp_elem, doc_frags)
68
+ base_variant_pattern = BaseVariantPattern.from_et(bvp_elem, context)
70
69
 
71
70
  parent_refs = [
72
- ParentRef.from_et(pr_elem, doc_frags)
71
+ ParentRef.from_et(pr_elem, context)
73
72
  for pr_elem in et_element.iterfind("PARENT-REFS/PARENT-REF")
74
73
  ]
75
74
 
@@ -81,7 +80,7 @@ class BaseVariantRaw(HierarchyElementRaw):
81
80
  parent_refs=parent_refs,
82
81
  **kwargs)
83
82
 
84
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
83
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
85
84
  result = super()._build_odxlinks()
86
85
 
87
86
  for dv_proxy in self.diag_variables_raw:
@@ -1,9 +1,10 @@
1
1
  # SPDX-License-Identifier: MIT
2
+ from collections.abc import Callable, Iterable
2
3
  from copy import copy, deepcopy
3
4
  from dataclasses import dataclass
4
5
  from functools import cached_property
5
6
  from itertools import chain
6
- from typing import Any, Callable, Dict, Iterable, List, Optional, Union, cast
7
+ from typing import Any, Union, cast
7
8
  from xml.etree import ElementTree
8
9
 
9
10
  from ..admindata import AdminData
@@ -16,7 +17,8 @@ from ..exceptions import DecodeError, odxassert, odxraise
16
17
  from ..library import Library
17
18
  from ..message import Message
18
19
  from ..nameditemlist import NamedItemList, TNamed
19
- from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
20
+ from ..odxdoccontext import OdxDocContext
21
+ from ..odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
20
22
  from ..parentref import ParentRef
21
23
  from ..request import Request
22
24
  from ..response import Response
@@ -29,10 +31,10 @@ from ..unitgroup import UnitGroup
29
31
  from .diaglayerraw import DiagLayerRaw
30
32
  from .diaglayertype import DiagLayerType
31
33
 
32
- PrefixTree = Dict[int, Union[List[DiagService], "PrefixTree"]]
34
+ PrefixTree = dict[int, Union[list[DiagService], "PrefixTree"]]
33
35
 
34
36
 
35
- @dataclass
37
+ @dataclass(kw_only=True)
36
38
  class DiagLayer:
37
39
  """This class represents a "logical view" upon a diagnostic layer
38
40
  according to the ODX standard.
@@ -44,8 +46,8 @@ class DiagLayer:
44
46
  diag_layer_raw: DiagLayerRaw
45
47
 
46
48
  @staticmethod
47
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DiagLayer":
48
- diag_layer_raw = DiagLayerRaw.from_et(et_element, doc_frags)
49
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DiagLayer":
50
+ diag_layer_raw = DiagLayerRaw.from_et(et_element, context)
49
51
 
50
52
  # Create DiagLayer
51
53
  return DiagLayer(diag_layer_raw=diag_layer_raw)
@@ -72,7 +74,7 @@ class DiagLayer:
72
74
  else:
73
75
  self._diag_data_dictionary_spec = self.diag_layer_raw.diag_data_dictionary_spec
74
76
 
75
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
77
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
76
78
  """Construct a mapping from IDs to all objects that are contained in this diagnostic layer."""
77
79
  result = self.diag_layer_raw._build_odxlinks()
78
80
 
@@ -91,7 +93,7 @@ class DiagLayer:
91
93
  # reference. This mechanism can thus be seen as a kind of
92
94
  # "poor man's inheritance".
93
95
  if self.import_refs:
94
- imported_links: Dict[OdxLinkId, Any] = {}
96
+ imported_links: dict[OdxLinkId, Any] = {}
95
97
  for import_ref in self.import_refs:
96
98
  imported_dl = odxlinks.resolve(import_ref, DiagLayer)
97
99
 
@@ -168,7 +170,7 @@ class DiagLayer:
168
170
  """
169
171
  return get_local_objects(self)
170
172
 
171
- def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
173
+ def __deepcopy__(self, memo: dict[int, Any]) -> Any:
172
174
  """Create a deep copy of the diagnostic layer
173
175
 
174
176
  Note that the copied diagnostic layer is not fully
@@ -210,15 +212,15 @@ class DiagLayer:
210
212
  return self.diag_layer_raw.short_name
211
213
 
212
214
  @property
213
- def long_name(self) -> Optional[str]:
215
+ def long_name(self) -> str | None:
214
216
  return self.diag_layer_raw.long_name
215
217
 
216
218
  @property
217
- def description(self) -> Optional[Description]:
219
+ def description(self) -> Description | None:
218
220
  return self.diag_layer_raw.description
219
221
 
220
222
  @property
221
- def admin_data(self) -> Optional[AdminData]:
223
+ def admin_data(self) -> AdminData | None:
222
224
  return self.diag_layer_raw.admin_data
223
225
 
224
226
  @property
@@ -258,7 +260,7 @@ class DiagLayer:
258
260
  return self.diag_layer_raw.global_negative_responses
259
261
 
260
262
  @property
261
- def import_refs(self) -> List[OdxLinkRef]:
263
+ def import_refs(self) -> list[OdxLinkRef]:
262
264
  return self.diag_layer_raw.import_refs
263
265
 
264
266
  @property
@@ -270,7 +272,7 @@ class DiagLayer:
270
272
  return self.diag_layer_raw.sub_components
271
273
 
272
274
  @property
273
- def sdgs(self) -> List[SpecialDataGroup]:
275
+ def sdgs(self) -> list[SpecialDataGroup]:
274
276
  return self.diag_layer_raw.sdgs
275
277
 
276
278
  @property
@@ -359,13 +361,13 @@ class DiagLayer:
359
361
  if sub_tree.get(-1) is None:
360
362
  sub_tree[-1] = [service]
361
363
  else:
362
- cast(List[DiagService], sub_tree[-1]).append(service)
364
+ cast(list[DiagService], sub_tree[-1]).append(service)
363
365
 
364
- def _find_services_for_uds(self, message: bytes) -> List[DiagService]:
366
+ def _find_services_for_uds(self, message: bytes) -> list[DiagService]:
365
367
  prefix_tree = self._prefix_tree
366
368
 
367
369
  # Find matching service(s) in prefix tree
368
- possible_services: List[DiagService] = []
370
+ possible_services: list[DiagService] = []
369
371
  for b in message:
370
372
  if b in prefix_tree:
371
373
  odxassert(isinstance(prefix_tree[b], dict))
@@ -373,11 +375,11 @@ class DiagLayer:
373
375
  else:
374
376
  break
375
377
  if -1 in prefix_tree:
376
- possible_services += cast(List[DiagService], prefix_tree[-1])
378
+ possible_services += cast(list[DiagService], prefix_tree[-1])
377
379
  return possible_services
378
380
 
379
- def _decode(self, message: bytes, candidate_services: Iterable[DiagService]) -> List[Message]:
380
- decoded_messages: List[Message] = []
381
+ def _decode(self, message: bytes, candidate_services: Iterable[DiagService]) -> list[Message]:
382
+ decoded_messages: list[Message] = []
381
383
 
382
384
  for service in candidate_services:
383
385
  try:
@@ -415,12 +417,12 @@ class DiagLayer:
415
417
 
416
418
  return decoded_messages
417
419
 
418
- def decode(self, message: bytes) -> List[Message]:
420
+ def decode(self, message: bytes) -> list[Message]:
419
421
  candidate_services = self._find_services_for_uds(message)
420
422
 
421
423
  return self._decode(message, candidate_services)
422
424
 
423
- def decode_response(self, response: bytes, request: bytes) -> List[Message]:
425
+ def decode_response(self, response: bytes, request: bytes) -> list[Message]:
424
426
  candidate_services = self._find_services_for_uds(request)
425
427
  if candidate_services is None:
426
428
  raise DecodeError(f"Couldn't find corresponding service for request {request.hex()}.")