odxtools 6.6.1__py3-none-any.whl → 9.3.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 (222) hide show
  1. odxtools/__init__.py +7 -5
  2. odxtools/additionalaudience.py +3 -5
  3. odxtools/admindata.py +5 -7
  4. odxtools/audience.py +10 -13
  5. odxtools/basecomparam.py +3 -5
  6. odxtools/basicstructure.py +55 -241
  7. odxtools/cli/_parser_utils.py +16 -1
  8. odxtools/cli/_print_utils.py +169 -134
  9. odxtools/cli/browse.py +127 -103
  10. odxtools/cli/compare.py +114 -87
  11. odxtools/cli/decode.py +2 -1
  12. odxtools/cli/dummy_sub_parser.py +3 -1
  13. odxtools/cli/find.py +2 -1
  14. odxtools/cli/list.py +26 -16
  15. odxtools/cli/main.py +1 -0
  16. odxtools/cli/snoop.py +32 -6
  17. odxtools/codec.py +211 -0
  18. odxtools/commrelation.py +122 -0
  19. odxtools/companydata.py +5 -7
  20. odxtools/companydocinfo.py +7 -8
  21. odxtools/companyrevisioninfo.py +3 -5
  22. odxtools/companyspecificinfo.py +8 -9
  23. odxtools/comparam.py +4 -6
  24. odxtools/comparaminstance.py +14 -14
  25. odxtools/comparamspec.py +16 -54
  26. odxtools/comparamsubset.py +22 -62
  27. odxtools/complexcomparam.py +5 -7
  28. odxtools/compumethods/compucodecompumethod.py +63 -0
  29. odxtools/compumethods/compuconst.py +31 -0
  30. odxtools/compumethods/compudefaultvalue.py +27 -0
  31. odxtools/compumethods/compuinternaltophys.py +56 -0
  32. odxtools/compumethods/compuinversevalue.py +7 -0
  33. odxtools/compumethods/compumethod.py +94 -15
  34. odxtools/compumethods/compuphystointernal.py +56 -0
  35. odxtools/compumethods/compurationalcoeffs.py +20 -9
  36. odxtools/compumethods/compuscale.py +67 -32
  37. odxtools/compumethods/createanycompumethod.py +31 -172
  38. odxtools/compumethods/identicalcompumethod.py +31 -6
  39. odxtools/compumethods/limit.py +70 -36
  40. odxtools/compumethods/linearcompumethod.py +70 -181
  41. odxtools/compumethods/linearsegment.py +190 -0
  42. odxtools/compumethods/ratfunccompumethod.py +106 -0
  43. odxtools/compumethods/ratfuncsegment.py +87 -0
  44. odxtools/compumethods/scalelinearcompumethod.py +132 -26
  45. odxtools/compumethods/scaleratfunccompumethod.py +113 -0
  46. odxtools/compumethods/tabintpcompumethod.py +123 -92
  47. odxtools/compumethods/texttablecompumethod.py +117 -57
  48. odxtools/createanydiagcodedtype.py +10 -67
  49. odxtools/database.py +167 -87
  50. odxtools/dataobjectproperty.py +25 -32
  51. odxtools/decodestate.py +14 -17
  52. odxtools/description.py +47 -0
  53. odxtools/determinenumberofitems.py +4 -5
  54. odxtools/diagcodedtype.py +37 -106
  55. odxtools/diagcomm.py +24 -12
  56. odxtools/diagdatadictionaryspec.py +120 -96
  57. odxtools/diaglayercontainer.py +46 -54
  58. odxtools/diaglayers/basevariant.py +128 -0
  59. odxtools/diaglayers/basevariantraw.py +123 -0
  60. odxtools/diaglayers/diaglayer.py +432 -0
  61. odxtools/{diaglayerraw.py → diaglayers/diaglayerraw.py} +105 -120
  62. odxtools/diaglayers/diaglayertype.py +42 -0
  63. odxtools/diaglayers/ecushareddata.py +96 -0
  64. odxtools/diaglayers/ecushareddataraw.py +87 -0
  65. odxtools/diaglayers/ecuvariant.py +124 -0
  66. odxtools/diaglayers/ecuvariantraw.py +129 -0
  67. odxtools/diaglayers/functionalgroup.py +110 -0
  68. odxtools/diaglayers/functionalgroupraw.py +106 -0
  69. odxtools/{diaglayer.py → diaglayers/hierarchyelement.py} +273 -472
  70. odxtools/diaglayers/hierarchyelementraw.py +58 -0
  71. odxtools/diaglayers/protocol.py +64 -0
  72. odxtools/diaglayers/protocolraw.py +91 -0
  73. odxtools/diagnostictroublecode.py +8 -9
  74. odxtools/diagservice.py +57 -44
  75. odxtools/diagvariable.py +113 -0
  76. odxtools/docrevision.py +5 -7
  77. odxtools/dopbase.py +15 -15
  78. odxtools/dtcdop.py +170 -50
  79. odxtools/dynamicendmarkerfield.py +134 -0
  80. odxtools/dynamiclengthfield.py +47 -42
  81. odxtools/dyndefinedspec.py +177 -0
  82. odxtools/dynenddopref.py +38 -0
  83. odxtools/ecuvariantmatcher.py +6 -7
  84. odxtools/element.py +13 -15
  85. odxtools/encodestate.py +199 -22
  86. odxtools/endofpdufield.py +31 -18
  87. odxtools/environmentdata.py +8 -1
  88. odxtools/environmentdatadescription.py +198 -36
  89. odxtools/exceptions.py +11 -2
  90. odxtools/field.py +10 -10
  91. odxtools/functionalclass.py +3 -5
  92. odxtools/inputparam.py +3 -12
  93. odxtools/internalconstr.py +14 -5
  94. odxtools/isotp_state_machine.py +14 -6
  95. odxtools/leadinglengthinfotype.py +37 -18
  96. odxtools/library.py +66 -0
  97. odxtools/loadfile.py +64 -0
  98. odxtools/matchingparameter.py +3 -3
  99. odxtools/message.py +0 -7
  100. odxtools/minmaxlengthtype.py +61 -33
  101. odxtools/modification.py +3 -5
  102. odxtools/multiplexer.py +135 -75
  103. odxtools/multiplexercase.py +39 -18
  104. odxtools/multiplexerdefaultcase.py +15 -12
  105. odxtools/multiplexerswitchkey.py +4 -5
  106. odxtools/nameditemlist.py +33 -8
  107. odxtools/negoutputparam.py +3 -5
  108. odxtools/odxcategory.py +83 -0
  109. odxtools/odxlink.py +62 -53
  110. odxtools/odxtypes.py +93 -8
  111. odxtools/outputparam.py +5 -16
  112. odxtools/parameterinfo.py +219 -61
  113. odxtools/parameters/codedconstparameter.py +45 -32
  114. odxtools/parameters/createanyparameter.py +19 -193
  115. odxtools/parameters/dynamicparameter.py +25 -4
  116. odxtools/parameters/lengthkeyparameter.py +83 -25
  117. odxtools/parameters/matchingrequestparameter.py +48 -18
  118. odxtools/parameters/nrcconstparameter.py +76 -54
  119. odxtools/parameters/parameter.py +97 -73
  120. odxtools/parameters/parameterwithdop.py +41 -38
  121. odxtools/parameters/physicalconstantparameter.py +41 -20
  122. odxtools/parameters/reservedparameter.py +36 -18
  123. odxtools/parameters/systemparameter.py +74 -7
  124. odxtools/parameters/tableentryparameter.py +47 -7
  125. odxtools/parameters/tablekeyparameter.py +142 -55
  126. odxtools/parameters/tablestructparameter.py +79 -58
  127. odxtools/parameters/valueparameter.py +39 -21
  128. odxtools/paramlengthinfotype.py +56 -33
  129. odxtools/parentref.py +20 -3
  130. odxtools/physicaldimension.py +3 -8
  131. odxtools/progcode.py +26 -11
  132. odxtools/protstack.py +3 -5
  133. odxtools/py.typed +0 -0
  134. odxtools/relateddoc.py +7 -9
  135. odxtools/request.py +120 -10
  136. odxtools/response.py +123 -23
  137. odxtools/scaleconstr.py +14 -8
  138. odxtools/servicebinner.py +1 -1
  139. odxtools/singleecujob.py +12 -10
  140. odxtools/snrefcontext.py +29 -0
  141. odxtools/specialdata.py +3 -5
  142. odxtools/specialdatagroup.py +7 -9
  143. odxtools/specialdatagroupcaption.py +3 -6
  144. odxtools/standardlengthtype.py +80 -14
  145. odxtools/state.py +3 -5
  146. odxtools/statechart.py +13 -19
  147. odxtools/statetransition.py +8 -18
  148. odxtools/staticfield.py +107 -0
  149. odxtools/subcomponent.py +288 -0
  150. odxtools/swvariable.py +21 -0
  151. odxtools/table.py +9 -9
  152. odxtools/tablerow.py +30 -15
  153. odxtools/teammember.py +3 -5
  154. odxtools/templates/comparam-spec.odx-c.xml.jinja2 +4 -24
  155. odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +5 -26
  156. odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +15 -31
  157. odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +1 -1
  158. odxtools/templates/macros/printAudience.xml.jinja2 +1 -1
  159. odxtools/templates/macros/printBaseVariant.xml.jinja2 +53 -0
  160. odxtools/templates/macros/printCompanyData.xml.jinja2 +4 -7
  161. odxtools/templates/macros/printComparam.xml.jinja2 +6 -4
  162. odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
  163. odxtools/templates/macros/printCompuMethod.xml.jinja2 +147 -0
  164. odxtools/templates/macros/printDOP.xml.jinja2 +27 -137
  165. odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
  166. odxtools/templates/macros/printDiagComm.xml.jinja2 +1 -1
  167. odxtools/templates/macros/printDiagLayer.xml.jinja2 +222 -0
  168. odxtools/templates/macros/printDiagVariable.xml.jinja2 +66 -0
  169. odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +48 -0
  170. odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +16 -0
  171. odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +1 -1
  172. odxtools/templates/macros/printEcuSharedData.xml.jinja2 +30 -0
  173. odxtools/templates/macros/printEcuVariant.xml.jinja2 +53 -0
  174. odxtools/templates/macros/printEcuVariantPattern.xml.jinja2 +1 -1
  175. odxtools/templates/macros/printElementId.xml.jinja2 +8 -3
  176. odxtools/templates/macros/printEndOfPdu.xml.jinja2 +1 -1
  177. odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +1 -1
  178. odxtools/templates/macros/printFunctionalClass.xml.jinja2 +1 -1
  179. odxtools/templates/macros/printFunctionalGroup.xml.jinja2 +40 -0
  180. odxtools/templates/macros/printHierarchyElement.xml.jinja2 +24 -0
  181. odxtools/templates/macros/printLibrary.xml.jinja2 +21 -0
  182. odxtools/templates/macros/printMux.xml.jinja2 +5 -3
  183. odxtools/templates/macros/printOdxCategory.xml.jinja2 +28 -0
  184. odxtools/templates/macros/printParam.xml.jinja2 +18 -19
  185. odxtools/templates/macros/printProtStack.xml.jinja2 +1 -1
  186. odxtools/templates/macros/printProtocol.xml.jinja2 +30 -0
  187. odxtools/templates/macros/printRequest.xml.jinja2 +1 -1
  188. odxtools/templates/macros/printResponse.xml.jinja2 +1 -1
  189. odxtools/templates/macros/printService.xml.jinja2 +3 -2
  190. odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +5 -26
  191. odxtools/templates/macros/printSpecialData.xml.jinja2 +1 -1
  192. odxtools/templates/macros/printState.xml.jinja2 +1 -1
  193. odxtools/templates/macros/printStateChart.xml.jinja2 +1 -1
  194. odxtools/templates/macros/printStateTransition.xml.jinja2 +1 -1
  195. odxtools/templates/macros/printStaticField.xml.jinja2 +15 -0
  196. odxtools/templates/macros/printStructure.xml.jinja2 +1 -1
  197. odxtools/templates/macros/printSubComponent.xml.jinja2 +104 -0
  198. odxtools/templates/macros/printTable.xml.jinja2 +4 -5
  199. odxtools/templates/macros/printUnitSpec.xml.jinja2 +3 -5
  200. odxtools/uds.py +2 -10
  201. odxtools/unit.py +4 -8
  202. odxtools/unitgroup.py +3 -5
  203. odxtools/unitspec.py +17 -17
  204. odxtools/utils.py +38 -20
  205. odxtools/variablegroup.py +32 -0
  206. odxtools/version.py +2 -2
  207. odxtools/{write_pdx_file.py → writepdxfile.py} +22 -12
  208. odxtools/xdoc.py +3 -5
  209. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/METADATA +44 -33
  210. odxtools-9.3.0.dist-info/RECORD +228 -0
  211. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/WHEEL +1 -1
  212. odxtools/createcompanydatas.py +0 -17
  213. odxtools/createsdgs.py +0 -19
  214. odxtools/diaglayertype.py +0 -30
  215. odxtools/load_file.py +0 -13
  216. odxtools/load_odx_d_file.py +0 -6
  217. odxtools/load_pdx_file.py +0 -8
  218. odxtools/templates/macros/printVariant.xml.jinja2 +0 -208
  219. odxtools-6.6.1.dist-info/RECORD +0 -180
  220. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/LICENSE +0 -0
  221. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/entry_points.txt +0 -0
  222. {odxtools-6.6.1.dist-info → odxtools-9.3.0.dist-info}/top_level.txt +0 -0
@@ -1,63 +1,82 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
3
  from itertools import chain
4
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
+ from typing import Any, Dict, List, Optional
5
5
  from xml.etree import ElementTree
6
6
 
7
+ from .admindata import AdminData
7
8
  from .basicstructure import BasicStructure
8
- from .createsdgs import create_sdgs_from_et
9
9
  from .dataobjectproperty import DataObjectProperty
10
10
  from .dopbase import DopBase
11
11
  from .dtcdop import DtcDop
12
+ from .dynamicendmarkerfield import DynamicEndmarkerField
12
13
  from .dynamiclengthfield import DynamicLengthField
13
14
  from .endofpdufield import EndOfPduField
14
15
  from .environmentdata import EnvironmentData
15
16
  from .environmentdatadescription import EnvironmentDataDescription
16
17
  from .exceptions import odxraise
17
- from .globals import logger
18
18
  from .multiplexer import Multiplexer
19
19
  from .nameditemlist import NamedItemList
20
20
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
21
+ from .snrefcontext import SnRefContext
21
22
  from .specialdatagroup import SpecialDataGroup
23
+ from .staticfield import StaticField
22
24
  from .structure import Structure
23
25
  from .table import Table
24
26
  from .unitspec import UnitSpec
25
27
 
26
- if TYPE_CHECKING:
27
- from .diaglayer import DiagLayer
28
-
29
28
 
30
29
  @dataclass
31
30
  class DiagDataDictionarySpec:
31
+ admin_data: Optional[AdminData]
32
32
  dtc_dops: NamedItemList[DtcDop]
33
+ env_data_descs: NamedItemList[EnvironmentDataDescription]
33
34
  data_object_props: NamedItemList[DataObjectProperty]
34
35
  structures: NamedItemList[BasicStructure]
35
- end_of_pdu_fields: NamedItemList[EndOfPduField]
36
+ static_fields: NamedItemList[StaticField]
36
37
  dynamic_length_fields: NamedItemList[DynamicLengthField]
37
- tables: NamedItemList[Table]
38
- env_data_descs: NamedItemList[EnvironmentDataDescription]
39
- env_datas: NamedItemList[EnvironmentData]
38
+ dynamic_endmarker_fields: NamedItemList[DynamicEndmarkerField]
39
+ end_of_pdu_fields: NamedItemList[EndOfPduField]
40
40
  muxs: NamedItemList[Multiplexer]
41
+ env_datas: NamedItemList[EnvironmentData]
41
42
  unit_spec: Optional[UnitSpec]
43
+ tables: NamedItemList[Table]
42
44
  sdgs: List[SpecialDataGroup]
43
45
 
44
46
  def __post_init__(self) -> None:
45
47
  self._all_data_object_properties: NamedItemList[DopBase] = NamedItemList(
46
48
  chain(
47
49
  self.dtc_dops,
50
+ self.env_data_descs,
48
51
  self.data_object_props,
49
52
  self.structures,
50
- self.end_of_pdu_fields,
53
+ self.static_fields,
51
54
  self.dynamic_length_fields,
52
- self.env_data_descs,
53
- self.env_datas,
55
+ self.dynamic_endmarker_fields,
56
+ self.end_of_pdu_fields,
54
57
  self.muxs,
58
+ self.env_datas,
55
59
  ))
56
60
 
57
61
  @staticmethod
58
62
  def from_et(et_element: ElementTree.Element,
59
63
  doc_frags: List[OdxDocFragment]) -> "DiagDataDictionarySpec":
60
- # Parse DOP-BASEs
64
+ admin_data = None
65
+ if (admin_data_elem := et_element.find("ADMIN-DATA")) is not None:
66
+ admin_data = AdminData.from_et(admin_data_elem, doc_frags)
67
+
68
+ dtc_dops = []
69
+ for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP"):
70
+ dtc_dop = DtcDop.from_et(dtc_dop_elem, doc_frags)
71
+ if not isinstance(dtc_dop, DtcDop):
72
+ odxraise()
73
+ dtc_dops.append(dtc_dop)
74
+
75
+ env_data_descs = [
76
+ EnvironmentDataDescription.from_et(env_data_desc_element, doc_frags)
77
+ for env_data_desc_element in et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC")
78
+ ]
79
+
61
80
  data_object_props = [
62
81
  DataObjectProperty.from_et(dop_element, doc_frags)
63
82
  for dop_element in et_element.iterfind("DATA-OBJECT-PROPS/DATA-OBJECT-PROP")
@@ -68,9 +87,9 @@ class DiagDataDictionarySpec:
68
87
  for structure_element in et_element.iterfind("STRUCTURES/STRUCTURE")
69
88
  ]
70
89
 
71
- end_of_pdu_fields = [
72
- EndOfPduField.from_et(eofp_element, doc_frags)
73
- for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD")
90
+ static_fields = [
91
+ StaticField.from_et(dl_element, doc_frags)
92
+ for dl_element in et_element.iterfind("STATIC-FIELDS/STATIC-FIELD")
74
93
  ]
75
94
 
76
95
  dynamic_length_fields = [
@@ -78,21 +97,19 @@ class DiagDataDictionarySpec:
78
97
  for dl_element in et_element.iterfind("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD")
79
98
  ]
80
99
 
81
- dtc_dops = []
82
- for dtc_dop_elem in et_element.iterfind("DTC-DOPS/DTC-DOP"):
83
- dtc_dop = DtcDop.from_et(dtc_dop_elem, doc_frags)
84
- if not isinstance(dtc_dop, DtcDop):
85
- odxraise()
86
- dtc_dops.append(dtc_dop)
100
+ dynamic_endmarker_fields = [
101
+ DynamicEndmarkerField.from_et(dl_element, doc_frags) for dl_element in
102
+ et_element.iterfind("DYNAMIC-ENDMARKER-FIELDS/DYNAMIC-ENDMARKER-FIELD")
103
+ ]
87
104
 
88
- tables = [
89
- Table.from_et(table_element, doc_frags)
90
- for table_element in et_element.iterfind("TABLES/TABLE")
105
+ end_of_pdu_fields = [
106
+ EndOfPduField.from_et(eofp_element, doc_frags)
107
+ for eofp_element in et_element.iterfind("END-OF-PDU-FIELDS/END-OF-PDU-FIELD")
91
108
  ]
92
109
 
93
- env_data_descs = [
94
- EnvironmentDataDescription.from_et(env_data_desc_element, doc_frags)
95
- for env_data_desc_element in et_element.iterfind("ENV-DATA-DESCS/ENV-DATA-DESC")
110
+ muxs = [
111
+ Multiplexer.from_et(mux_element, doc_frags)
112
+ for mux_element in et_element.iterfind("MUXS/MUX")
96
113
  ]
97
114
 
98
115
  env_data_elements = chain(
@@ -105,42 +122,34 @@ class DiagDataDictionarySpec:
105
122
  for env_data_element in env_data_elements
106
123
  ]
107
124
 
108
- muxs = [
109
- Multiplexer.from_et(mux_element, doc_frags)
110
- for mux_element in et_element.iterfind("MUXS/MUX")
111
- ]
112
-
113
125
  if (spec_elem := et_element.find("UNIT-SPEC")) is not None:
114
126
  unit_spec = UnitSpec.from_et(spec_elem, doc_frags)
115
127
  else:
116
128
  unit_spec = None
117
129
 
118
- # TODO: Parse different specs.. Which of them are needed?
119
- for (path, name) in [
120
- ("STATIC-FIELDS", "static fields"),
121
- ("DYNAMIC-LENGTH-FIELDS/DYNAMIC-LENGTH-FIELD", "dynamic length fields"),
122
- (
123
- "DYNAMIC-ENDMARKER-FIELDS/DYNAMIC-ENDMARKER-FIELD",
124
- "dynamic endmarker fields",
125
- ),
126
- ]:
127
- num = len(list(et_element.iterfind(path)))
128
- if num > 0:
129
- logger.info(f"Not implemented: Did not parse {num} {name}.")
130
-
131
- sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
130
+ tables = [
131
+ Table.from_et(table_element, doc_frags)
132
+ for table_element in et_element.iterfind("TABLES/TABLE")
133
+ ]
134
+
135
+ sdgs = [
136
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
137
+ ]
132
138
 
133
139
  return DiagDataDictionarySpec(
140
+ admin_data=admin_data,
141
+ dtc_dops=NamedItemList(dtc_dops),
142
+ env_data_descs=NamedItemList(env_data_descs),
134
143
  data_object_props=NamedItemList(data_object_props),
135
144
  structures=NamedItemList(structures),
136
- end_of_pdu_fields=NamedItemList(end_of_pdu_fields),
145
+ static_fields=NamedItemList(static_fields),
137
146
  dynamic_length_fields=NamedItemList(dynamic_length_fields),
138
- dtc_dops=NamedItemList(dtc_dops),
147
+ dynamic_endmarker_fields=NamedItemList(dynamic_endmarker_fields),
148
+ end_of_pdu_fields=NamedItemList(end_of_pdu_fields),
149
+ muxs=NamedItemList(muxs),
150
+ env_datas=NamedItemList(env_datas),
139
151
  unit_spec=unit_spec,
140
152
  tables=NamedItemList(tables),
141
- env_data_descs=NamedItemList(env_data_descs),
142
- env_datas=NamedItemList(env_datas),
143
- muxs=NamedItemList(muxs),
144
153
  sdgs=sdgs,
145
154
  )
146
155
 
@@ -148,81 +157,96 @@ class DiagDataDictionarySpec:
148
157
  # note that DataDictionarySpec objects do not exhibit an ODXLINK id.
149
158
  odxlinks = {}
150
159
 
151
- for data_object_prop in self.data_object_props:
152
- odxlinks.update(data_object_prop._build_odxlinks())
160
+ if self.admin_data is not None:
161
+ odxlinks.update(self.admin_data._build_odxlinks())
153
162
  for dtc_dop in self.dtc_dops:
154
163
  odxlinks.update(dtc_dop._build_odxlinks())
155
164
  for env_data_desc in self.env_data_descs:
156
165
  odxlinks.update(env_data_desc._build_odxlinks())
157
- for env_data in self.env_datas:
158
- odxlinks.update(env_data._build_odxlinks())
159
- for mux in self.muxs:
160
- odxlinks.update(mux._build_odxlinks())
161
- for sdg in self.sdgs:
162
- odxlinks.update(sdg._build_odxlinks())
166
+ for data_object_prop in self.data_object_props:
167
+ odxlinks.update(data_object_prop._build_odxlinks())
163
168
  for structure in self.structures:
164
169
  odxlinks.update(structure._build_odxlinks())
170
+ for static_field in self.static_fields:
171
+ odxlinks.update(static_field._build_odxlinks())
165
172
  for dynamic_length_field in self.dynamic_length_fields:
166
173
  odxlinks.update(dynamic_length_field._build_odxlinks())
174
+ for dynamic_endmarker_field in self.dynamic_endmarker_fields:
175
+ odxlinks.update(dynamic_endmarker_field._build_odxlinks())
167
176
  for end_of_pdu_field in self.end_of_pdu_fields:
168
177
  odxlinks.update(end_of_pdu_field._build_odxlinks())
169
- for table in self.tables:
170
- odxlinks.update(table._build_odxlinks())
171
-
178
+ for mux in self.muxs:
179
+ odxlinks.update(mux._build_odxlinks())
180
+ for env_data in self.env_datas:
181
+ odxlinks.update(env_data._build_odxlinks())
172
182
  if self.unit_spec is not None:
173
183
  odxlinks.update(self.unit_spec._build_odxlinks())
184
+ for table in self.tables:
185
+ odxlinks.update(table._build_odxlinks())
186
+ for sdg in self.sdgs:
187
+ odxlinks.update(sdg._build_odxlinks())
174
188
 
175
189
  return odxlinks
176
190
 
177
191
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
178
- for data_object_prop in self.data_object_props:
179
- data_object_prop._resolve_odxlinks(odxlinks)
192
+ if self.admin_data is not None:
193
+ self.admin_data._resolve_odxlinks(odxlinks)
180
194
  for dtc_dop in self.dtc_dops:
181
195
  dtc_dop._resolve_odxlinks(odxlinks)
196
+ for env_data_desc in self.env_data_descs:
197
+ env_data_desc._resolve_odxlinks(odxlinks)
198
+ for data_object_prop in self.data_object_props:
199
+ data_object_prop._resolve_odxlinks(odxlinks)
200
+ for structure in self.structures:
201
+ structure._resolve_odxlinks(odxlinks)
202
+ for static_field in self.static_fields:
203
+ static_field._resolve_odxlinks(odxlinks)
182
204
  for dynamic_length_field in self.dynamic_length_fields:
183
205
  dynamic_length_field._resolve_odxlinks(odxlinks)
206
+ for dynamic_endmarker_field in self.dynamic_endmarker_fields:
207
+ dynamic_endmarker_field._resolve_odxlinks(odxlinks)
184
208
  for end_of_pdu_field in self.end_of_pdu_fields:
185
209
  end_of_pdu_field._resolve_odxlinks(odxlinks)
186
- for env_data_desc in self.env_data_descs:
187
- env_data_desc._resolve_odxlinks(odxlinks)
188
- for env_data in self.env_datas:
189
- env_data._resolve_odxlinks(odxlinks)
190
210
  for mux in self.muxs:
191
211
  mux._resolve_odxlinks(odxlinks)
192
- for sdg in self.sdgs:
193
- sdg._resolve_odxlinks(odxlinks)
194
- for structure in self.structures:
195
- structure._resolve_odxlinks(odxlinks)
196
- for table in self.tables:
197
- table._resolve_odxlinks(odxlinks)
198
-
212
+ for env_data in self.env_datas:
213
+ env_data._resolve_odxlinks(odxlinks)
199
214
  if self.unit_spec is not None:
200
215
  self.unit_spec._resolve_odxlinks(odxlinks)
216
+ for table in self.tables:
217
+ table._resolve_odxlinks(odxlinks)
218
+ for sdg in self.sdgs:
219
+ sdg._resolve_odxlinks(odxlinks)
201
220
 
202
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
203
- for data_object_prop in self.data_object_props:
204
- data_object_prop._resolve_snrefs(diag_layer)
221
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
222
+ if self.admin_data is not None:
223
+ self.admin_data._resolve_snrefs(context)
205
224
  for dtc_dop in self.dtc_dops:
206
- dtc_dop._resolve_snrefs(diag_layer)
225
+ dtc_dop._resolve_snrefs(context)
226
+ for env_data_desc in self.env_data_descs:
227
+ env_data_desc._resolve_snrefs(context)
228
+ for data_object_prop in self.data_object_props:
229
+ data_object_prop._resolve_snrefs(context)
230
+ for structure in self.structures:
231
+ structure._resolve_snrefs(context)
232
+ for static_field in self.static_fields:
233
+ static_field._resolve_snrefs(context)
207
234
  for dynamic_length_field in self.dynamic_length_fields:
208
- dynamic_length_field._resolve_snrefs(diag_layer)
235
+ dynamic_length_field._resolve_snrefs(context)
236
+ for dynamic_endmarker_field in self.dynamic_endmarker_fields:
237
+ dynamic_endmarker_field._resolve_snrefs(context)
209
238
  for end_of_pdu_field in self.end_of_pdu_fields:
210
- end_of_pdu_field._resolve_snrefs(diag_layer)
211
- for env_data_desc in self.env_data_descs:
212
- env_data_desc._resolve_snrefs(diag_layer)
213
- for env_data in self.env_datas:
214
- env_data._resolve_snrefs(diag_layer)
239
+ end_of_pdu_field._resolve_snrefs(context)
215
240
  for mux in self.muxs:
216
- mux._resolve_snrefs(diag_layer)
217
- for sdg in self.sdgs:
218
- sdg._resolve_snrefs(diag_layer)
219
- for structure in self.structures:
220
- structure._resolve_snrefs(diag_layer)
221
- for table in self.tables:
222
- table._resolve_snrefs(diag_layer)
223
-
241
+ mux._resolve_snrefs(context)
242
+ for env_data in self.env_datas:
243
+ env_data._resolve_snrefs(context)
224
244
  if self.unit_spec is not None:
225
- self.unit_spec._resolve_snrefs(diag_layer)
245
+ self.unit_spec._resolve_snrefs(context)
246
+ for table in self.tables:
247
+ table._resolve_snrefs(context)
248
+ for sdg in self.sdgs:
249
+ sdg._resolve_snrefs(context)
226
250
 
227
251
  @property
228
252
  def all_data_object_properties(self) -> NamedItemList[DopBase]:
@@ -1,32 +1,39 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
3
  from itertools import chain
4
- from typing import Any, Dict, List, Optional, Union
4
+ from typing import TYPE_CHECKING, Any, Dict, List, Union
5
5
  from xml.etree import ElementTree
6
6
 
7
- from .admindata import AdminData
8
- from .companydata import CompanyData
9
- from .createcompanydatas import create_company_datas_from_et
10
- from .createsdgs import create_sdgs_from_et
11
- from .diaglayer import DiagLayer
12
- from .element import IdentifiableElement
13
- from .exceptions import odxrequire
7
+ from .diaglayers.basevariant import BaseVariant
8
+ from .diaglayers.diaglayer import DiagLayer
9
+ from .diaglayers.ecushareddata import EcuSharedData
10
+ from .diaglayers.ecuvariant import EcuVariant
11
+ from .diaglayers.functionalgroup import FunctionalGroup
12
+ from .diaglayers.protocol import Protocol
14
13
  from .nameditemlist import NamedItemList
14
+ from .odxcategory import OdxCategory
15
15
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
16
- from .specialdatagroup import SpecialDataGroup
16
+ from .snrefcontext import SnRefContext
17
17
  from .utils import dataclass_fields_asdict
18
18
 
19
+ if TYPE_CHECKING:
20
+ from .database import Database
21
+
19
22
 
20
23
  @dataclass
21
- class DiagLayerContainer(IdentifiableElement):
22
- admin_data: Optional[AdminData]
23
- company_datas: NamedItemList[CompanyData]
24
- ecu_shared_datas: NamedItemList[DiagLayer]
25
- protocols: NamedItemList[DiagLayer]
26
- functional_groups: NamedItemList[DiagLayer]
27
- base_variants: NamedItemList[DiagLayer]
28
- ecu_variants: NamedItemList[DiagLayer]
29
- sdgs: List[SpecialDataGroup]
24
+ class DiagLayerContainer(OdxCategory):
25
+ ecu_shared_datas: NamedItemList[EcuSharedData]
26
+ protocols: NamedItemList[Protocol]
27
+ functional_groups: NamedItemList[FunctionalGroup]
28
+ base_variants: NamedItemList[BaseVariant]
29
+ ecu_variants: NamedItemList[EcuVariant]
30
+
31
+ @property
32
+ def ecus(self) -> NamedItemList[EcuVariant]:
33
+ """ECU variants defined in the container
34
+
35
+ This property is an alias for `.ecu_variants`"""
36
+ return self.ecu_variants
30
37
 
31
38
  def __post_init__(self) -> None:
32
39
  self._diag_layers = NamedItemList[DiagLayer](chain(
@@ -41,56 +48,41 @@ class DiagLayerContainer(IdentifiableElement):
41
48
  def from_et(et_element: ElementTree.Element,
42
49
  doc_frags: List[OdxDocFragment]) -> "DiagLayerContainer":
43
50
 
44
- short_name = odxrequire(et_element.findtext("SHORT-NAME"))
45
- # create the current ODX "document fragment" (description of the
46
- # current document for references and IDs)
47
- doc_frags = [OdxDocFragment(short_name, "CONTAINER")]
48
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
51
+ cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="CONTAINER")
52
+ doc_frags = cat.odx_id.doc_fragments
53
+ kwargs = dataclass_fields_asdict(cat)
49
54
 
50
- admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
51
- company_datas = create_company_datas_from_et(et_element.find("COMPANY-DATAS"), doc_frags)
52
55
  ecu_shared_datas = NamedItemList([
53
- DiagLayer.from_et(dl_element, doc_frags)
56
+ EcuSharedData.from_et(dl_element, doc_frags)
54
57
  for dl_element in et_element.iterfind("ECU-SHARED-DATAS/ECU-SHARED-DATA")
55
58
  ])
56
59
  protocols = NamedItemList([
57
- DiagLayer.from_et(dl_element, doc_frags)
60
+ Protocol.from_et(dl_element, doc_frags)
58
61
  for dl_element in et_element.iterfind("PROTOCOLS/PROTOCOL")
59
62
  ])
60
63
  functional_groups = NamedItemList([
61
- DiagLayer.from_et(dl_element, doc_frags)
64
+ FunctionalGroup.from_et(dl_element, doc_frags)
62
65
  for dl_element in et_element.iterfind("FUNCTIONAL-GROUPS/FUNCTIONAL-GROUP")
63
66
  ])
64
67
  base_variants = NamedItemList([
65
- DiagLayer.from_et(dl_element, doc_frags)
68
+ BaseVariant.from_et(dl_element, doc_frags)
66
69
  for dl_element in et_element.iterfind("BASE-VARIANTS/BASE-VARIANT")
67
70
  ])
68
71
  ecu_variants = NamedItemList([
69
- DiagLayer.from_et(dl_element, doc_frags)
72
+ EcuVariant.from_et(dl_element, doc_frags)
70
73
  for dl_element in et_element.iterfind("ECU-VARIANTS/ECU-VARIANT")
71
74
  ])
72
- sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
73
75
 
74
76
  return DiagLayerContainer(
75
- admin_data=admin_data,
76
- company_datas=company_datas,
77
77
  ecu_shared_datas=ecu_shared_datas,
78
78
  protocols=protocols,
79
79
  functional_groups=functional_groups,
80
80
  base_variants=base_variants,
81
81
  ecu_variants=ecu_variants,
82
- sdgs=sdgs,
83
82
  **kwargs)
84
83
 
85
84
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
86
- result = {self.odx_id: self}
87
-
88
- if self.admin_data is not None:
89
- result.update(self.admin_data._build_odxlinks())
90
- for cd in self.company_datas:
91
- result.update(cd._build_odxlinks())
92
- for sdg in self.sdgs:
93
- result.update(sdg._build_odxlinks())
85
+ result = super()._build_odxlinks()
94
86
 
95
87
  for ecu_shared_data in self.ecu_shared_datas:
96
88
  result.update(ecu_shared_data._build_odxlinks())
@@ -106,12 +98,7 @@ class DiagLayerContainer(IdentifiableElement):
106
98
  return result
107
99
 
108
100
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
109
- if self.admin_data is not None:
110
- self.admin_data._resolve_odxlinks(odxlinks)
111
- for cd in self.company_datas:
112
- cd._resolve_odxlinks(odxlinks)
113
- for sdg in self.sdgs:
114
- sdg._resolve_odxlinks(odxlinks)
101
+ super()._resolve_odxlinks(odxlinks)
115
102
 
116
103
  for ecu_shared_data in self.ecu_shared_datas:
117
104
  ecu_shared_data._resolve_odxlinks(odxlinks)
@@ -124,17 +111,22 @@ class DiagLayerContainer(IdentifiableElement):
124
111
  for ecu_variant in self.ecu_variants:
125
112
  ecu_variant._resolve_odxlinks(odxlinks)
126
113
 
127
- def _finalize_init(self, odxlinks: OdxLinkDatabase) -> None:
114
+ def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None:
115
+ super()._finalize_init(database, odxlinks)
116
+
128
117
  for ecu_shared_data in self.ecu_shared_datas:
129
- ecu_shared_data._finalize_init(odxlinks)
118
+ ecu_shared_data._finalize_init(database, odxlinks)
130
119
  for protocol in self.protocols:
131
- protocol._finalize_init(odxlinks)
120
+ protocol._finalize_init(database, odxlinks)
132
121
  for functional_group in self.functional_groups:
133
- functional_group._finalize_init(odxlinks)
122
+ functional_group._finalize_init(database, odxlinks)
134
123
  for base_variant in self.base_variants:
135
- base_variant._finalize_init(odxlinks)
124
+ base_variant._finalize_init(database, odxlinks)
136
125
  for ecu_variant in self.ecu_variants:
137
- ecu_variant._finalize_init(odxlinks)
126
+ ecu_variant._finalize_init(database, odxlinks)
127
+
128
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
129
+ super()._resolve_snrefs(context)
138
130
 
139
131
  @property
140
132
  def diag_layers(self) -> NamedItemList[DiagLayer]:
@@ -0,0 +1,128 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from copy import deepcopy
3
+ from dataclasses import dataclass
4
+ from typing import Any, Dict, Iterable, List, Optional, Union, cast
5
+ from xml.etree import ElementTree
6
+
7
+ from typing_extensions import override
8
+
9
+ from ..diagvariable import DiagVariable
10
+ from ..dyndefinedspec import DynDefinedSpec
11
+ from ..exceptions import odxassert
12
+ from ..nameditemlist import NamedItemList
13
+ from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef
14
+ from ..parentref import ParentRef
15
+ from ..variablegroup import VariableGroup
16
+ from .basevariantraw import BaseVariantRaw
17
+ from .diaglayer import DiagLayer
18
+ from .hierarchyelement import HierarchyElement
19
+
20
+
21
+ @dataclass
22
+ class BaseVariant(HierarchyElement):
23
+ """This is a diagnostic layer for common functionality of an ECU
24
+ """
25
+
26
+ @property
27
+ def base_variant_raw(self) -> BaseVariantRaw:
28
+ return cast(BaseVariantRaw, self.diag_layer_raw)
29
+
30
+ #####
31
+ # <properties forwarded to the "raw" base variant>
32
+ #####
33
+ @property
34
+ def diag_variables_raw(self) -> List[Union[DiagVariable, OdxLinkRef]]:
35
+ return self.base_variant_raw.diag_variables_raw
36
+
37
+ @property
38
+ def dyn_defined_spec(self) -> Optional[DynDefinedSpec]:
39
+ return self.base_variant_raw.dyn_defined_spec
40
+
41
+ @property
42
+ def parent_refs(self) -> List[ParentRef]:
43
+ return self.base_variant_raw.parent_refs
44
+
45
+ #####
46
+ # </properties forwarded to the "raw" base variant>
47
+ #####
48
+
49
+ #######
50
+ # <properties subject to value inheritance>
51
+ #######
52
+ @property
53
+ def diag_variables(self) -> NamedItemList[DiagVariable]:
54
+ return self._diag_variables
55
+
56
+ @property
57
+ def variable_groups(self) -> NamedItemList[VariableGroup]:
58
+ return self._variable_groups
59
+
60
+ #######
61
+ # </properties subject to value inheritance>
62
+ #######
63
+
64
+ @staticmethod
65
+ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "BaseVariant":
66
+ base_variant_raw = BaseVariantRaw.from_et(et_element, doc_frags)
67
+
68
+ return BaseVariant(diag_layer_raw=base_variant_raw)
69
+
70
+ def __post_init__(self) -> None:
71
+ super().__post_init__()
72
+
73
+ odxassert(
74
+ isinstance(self.diag_layer_raw, BaseVariantRaw),
75
+ "The raw diagnostic layer passed to BaseVariant "
76
+ "must be a BaseVariantRaw")
77
+
78
+ def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
79
+ """Create a deep copy of the base variant
80
+
81
+ Note that the copied diagnostic layer is not fully
82
+ initialized, so `_finalize_init()` should to be called on it
83
+ before it can be used normally.
84
+ """
85
+
86
+ result = super().__deepcopy__(memo)
87
+
88
+ # note that the self.base_variant_raw object is *not* copied at
89
+ # this place because the attribute points to the same object
90
+ # as self.diag_layer_raw.
91
+ result.base_variant_raw = deepcopy(self.base_variant_raw, memo)
92
+
93
+ return result
94
+
95
+ @override
96
+ def _compute_value_inheritance(self, odxlinks: OdxLinkDatabase) -> None:
97
+ super()._compute_value_inheritance(odxlinks)
98
+
99
+ self._diag_variables = NamedItemList(self._compute_available_diag_variables(odxlinks))
100
+ self._variable_groups = NamedItemList(self._compute_available_variable_groups(odxlinks))
101
+
102
+ def _compute_available_diag_variables(self,
103
+ odxlinks: OdxLinkDatabase) -> Iterable[DiagVariable]:
104
+
105
+ def get_local_objects_fn(dl: DiagLayer) -> Iterable[DiagVariable]:
106
+ if not hasattr(dl.diag_layer_raw, "diag_variables"):
107
+ return []
108
+
109
+ return dl.diag_layer_raw.diag_variables # type: ignore[no-any-return]
110
+
111
+ def not_inherited_fn(parent_ref: ParentRef) -> List[str]:
112
+ return parent_ref.not_inherited_variables
113
+
114
+ return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)
115
+
116
+ def _compute_available_variable_groups(self,
117
+ odxlinks: OdxLinkDatabase) -> Iterable[VariableGroup]:
118
+
119
+ def get_local_objects_fn(dl: DiagLayer) -> Iterable[VariableGroup]:
120
+ if not hasattr(dl.diag_layer_raw, "variable_groups"):
121
+ return []
122
+
123
+ return dl.diag_layer_raw.variable_groups # type: ignore[no-any-return]
124
+
125
+ def not_inherited_fn(parent_ref: ParentRef) -> List[str]:
126
+ return []
127
+
128
+ return self._compute_available_objects(get_local_objects_fn, not_inherited_fn)