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
@@ -0,0 +1,104 @@
1
+ {#- -*- mode: sgml; tab-width: 1; indent-tabs-mode: nil -*-
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ -#}
5
+
6
+ {%- import('macros/printElementId.xml.jinja2') as peid %}
7
+ {%- import('macros/printEcuVariantPattern.xml.jinja2') as pevp %}
8
+
9
+ {%- macro printSubComponentPattern(pat) %}
10
+ <SUB-COMPONENT-PATTERN>
11
+ <MATCHING-PARAMETERS>
12
+ {%- for mp in pat.matching_parameters %}
13
+ {{ pvp.printMatchingParameter(mp)|indent(4) }}
14
+ {%- endfor %}
15
+ </MATCHING-PARAMETERS>
16
+ </SUB-COMPONENT-PATTERN>
17
+ {%- endmacro %}
18
+
19
+ {%- macro printSubComponentParamConnector(conn) %}
20
+ <SUB-COMPONENT-PARAM-CONNECTOR{#- #} {{-peid.printElementIdAttribs(conn)}}>
21
+ {{ peid.printElementIdSubtags(conn)|indent(2) }}
22
+ <DIAG-COMM-SNREF {{- make_xml_attrib("SHORT-NAME", conn.diag_comm_snref ) }} />
23
+ {%- if conn.out_param_if_refs %}
24
+ <OUT-PARAM-IF-REFS>
25
+ {%- for snref in conn.out_param_if_refs %}
26
+ <OUT-PARAM-IF-SNREF SHORT-NAME="{{snref}}" />
27
+ {%- endfor %}
28
+ </OUT-PARAM-IF-REFS>
29
+ {%- endif %}
30
+ {%- if conn.in_param_if_refs %}
31
+ <IN-PARAM-IF-REFS>
32
+ {%- for snref in conn.in_param_if_refs %}
33
+ <IN-PARAM-IF-SNREF SHORT-NAME="{{snref}}" />
34
+ {%- endfor %}
35
+ </IN-PARAM-IF-REFS>
36
+ {%- endif %}
37
+ </SUB-COMPONENT-PARAM-CONNECTOR>
38
+ {%- endmacro %}
39
+
40
+ {%- macro printTableRowConnector(conn) %}
41
+ <TABLE-ROW-CONNECTOR>
42
+ {{ peid.printElementIdSubtags(conn)|indent(2) }}
43
+ <TABLE-REF ID-REF="{{ conn.table_ref.ref_id }}" />
44
+ <TABLE-ROW-SNREF {{- make_xml_attrib("SHORT-NAME", conn.table_row_snref ) }} />
45
+ </TABLE-ROW-CONNECTOR>
46
+ {%- endmacro %}
47
+
48
+ {%- macro printEnvDataConnector(conn) %}
49
+ <ENV-DATA-CONNECTOR>
50
+ {{ peid.printElementIdSubtags(conn)|indent(2) }}
51
+ <ENV-DATA-DESC-REF ID-REF="{{ conn.env_data_desc_ref.ref_id }}" />
52
+ <ENV-DATA-SNREF {{- make_xml_attrib("SHORT-NAME", conn.env_data_snref ) }} />
53
+ </ENV-DATA-CONNECTOR>
54
+ {%- endmacro %}
55
+
56
+ {%- macro printDtcConnector(conn) %}
57
+ <DTC-CONNECTOR>
58
+ {{ peid.printElementIdSubtags(conn)|indent(2) }}
59
+ <DTC-DOP-REF ID-REF="{{ conn.dtc_dop_ref.ref_id }}" />
60
+ <DOP-SNREF {{- make_xml_attrib("SHORT-NAME", conn.dtc_snref ) }} />
61
+ </DTC-CONNECTOR>
62
+ {%- endmacro %}
63
+
64
+ {%- macro printSubComponent(sc) %}
65
+ <SUB-COMPONENT{#- #} {{-peid.printElementIdAttribs(sc)}}
66
+ {{- make_xml_attrib("SEMANTIC", sc.semantic) }}>
67
+ {{ peid.printElementIdSubtags(sc)|indent(2) }}
68
+ {%- if sc.sub_component_patterns %}
69
+ <SUB-COMPONENT-PATTERNS>
70
+ {%- for scp in sc.sub_component_patterns %}
71
+ {{ printSubComponentPattern(scp)|indent(4) }}
72
+ {%- endfor %}
73
+ </SUB-COMPONENT-PATTERNS>
74
+ {%- endif %}
75
+ {%- if sc.sub_component_param_connectors %}
76
+ <SUB-COMPONENT-PARAM-CONNECTORS>
77
+ {%- for conn in sc.sub_component_param_connectors %}
78
+ {{ printSubComponentParamConnector(conn)|indent(4) }}
79
+ {%- endfor %}
80
+ </SUB-COMPONENT-PARAM-CONNECTORS>
81
+ {%- endif %}
82
+ {%- if sc.table_row_connectors %}
83
+ <TABLE-ROW-CONNECTORS>
84
+ {%- for conn in sc.table_row_connectors %}
85
+ {{ printTableRowConnector(conn)|indent(4) }}
86
+ {%- endfor %}
87
+ </TABLE-ROW-CONNECTORS>
88
+ {%- endif %}
89
+ {%- if sc.env_data_connectors %}
90
+ <ENV-DATA-CONNECTORS>
91
+ {%- for conn in sc.env_data_connectors %}
92
+ {{ printEnvDataConnector(conn)|indent(4) }}
93
+ {%- endfor %}
94
+ </ENV-DATA-CONNECTORS>
95
+ {%- endif %}
96
+ {%- if sc.dtc_connectors %}
97
+ <DTC-CONNECTORS>
98
+ {%- for conn in sc.dtc_connectors %}
99
+ {{ printDtcConnector(conn)|indent(4) }}
100
+ {%- endfor %}
101
+ </DTC-CONNECTORS>
102
+ {%- endif %}
103
+ </SUB-COMPONENT>
104
+ {%- endmacro %}
@@ -5,9 +5,10 @@
5
5
 
6
6
  {%- import('macros/printElementId.xml.jinja2') as peid %}
7
7
  {%- import('macros/printSpecialData.xml.jinja2') as psd %}
8
+ {%- import('macros/printDescription.xml.jinja2') as pd %}
8
9
 
9
10
  {%- macro printTable(table) %}
10
- <TABLE ID="{{table.odx_id.local_id}}"
11
+ <TABLE {{-peid.printElementIdAttribs(table)}}
11
12
  {{-make_xml_attrib("SEMANTIC", table.semantic)}}>
12
13
  {{ peid.printElementIdSubtags(table)|indent(1) }}
13
14
  {%- if table.key_dop_ref %}
@@ -15,15 +16,13 @@
15
16
  {%- endif %}
16
17
  {%- for table_row in table.table_rows_raw %}
17
18
  {%- if hasattr(table_row, "key") %}
18
- <TABLE-ROW ID="{{table_row.odx_id.local_id}}"
19
+ <TABLE-ROW {{-peid.printElementIdAttribs(table_row)}}
19
20
  {{-make_xml_attrib("SEMANTIC", table_row.semantic)}}>
20
21
  <SHORT-NAME>{{table_row.short_name}}</SHORT-NAME>
21
22
  {%- if table_row.long_name %}
22
23
  <LONG-NAME>{{table_row.long_name|e}}</LONG-NAME>
23
24
  {%- endif %}
24
- {%- if table_row.description %}
25
- <DESC>{{table_row.description}}</DESC>
26
- {%- endif %}
25
+ {{ pd.printDescription(table_row.description) }}
27
26
  <KEY>{{table_row.key|e}}</KEY>
28
27
  {%- if table_row.dop_ref %}
29
28
  <DATA-OBJECT-PROP-REF ID-REF="{{ table_row.dop_ref.ref_id }}" />
@@ -35,8 +35,7 @@
35
35
 
36
36
 
37
37
  {%- macro printUnit(unit) -%}
38
- <UNIT ID="{{unit.odx_id.local_id}}"
39
- {{-make_xml_attrib("OID", unit.oid)}}>
38
+ <UNIT {{-peid.printElementIdAttribs(unit)}}>
40
39
  {{ peid.printElementIdSubtags(unit)|indent(1) }}
41
40
  <DISPLAY-NAME>{{ unit.display_name }}</DISPLAY-NAME>
42
41
  {%- if unit.factor_si_to_unit is not none %}
@@ -52,7 +51,7 @@
52
51
  {%- endmacro -%}
53
52
 
54
53
  {%- macro printUnitGroup(group) -%}
55
- <UNIT-GROUP {%- if group.oid %} OID="{{group.oid}}" {%- endif %}>
54
+ <UNIT-GROUP {{-make_xml_attrib("OID", group.oid)}}>
56
55
  {{ peid.printElementIdSubtags(group)|indent(1) }}
57
56
  <CATEGORY>{{ group.category.value }}</CATEGORY>
58
57
  {%- if group.unit_refs %}
@@ -66,8 +65,7 @@
66
65
  {%- endmacro -%}
67
66
 
68
67
  {%- macro printPhysicalDimesion(dim) -%}
69
- <PHYSICAL-DIMENSION ID="{{dim.odx_id.local_id}}"
70
- {{-make_xml_attrib("OID",dim.oid)}}>
68
+ <PHYSICAL-DIMENSION {{-peid.printElementIdAttribs(dim)}}>
71
69
  {{ peid.printElementIdSubtags(dim)|indent(1) }}
72
70
  {%- if dim.length_exp %}
73
71
  <LENGTH-EXP>{{ dim.length_exp }}</LENGTH-EXP>
odxtools/uds.py CHANGED
@@ -3,8 +3,6 @@ from enum import IntEnum
3
3
  from itertools import chain
4
4
  from typing import Optional
5
5
 
6
- from deprecation import deprecated
7
-
8
6
  import odxtools.obd as obd
9
7
 
10
8
 
@@ -62,13 +60,13 @@ _sid_to_name = {
62
60
  0x85: "Control DTC Settings",
63
61
  0x86: "Response on Event",
64
62
  0x87: "Link Control",
65
- 0x22: "Read Data by Identifier ",
63
+ 0x22: "Read Data by Identifier",
66
64
  0x23: "Read Memory by Address",
67
65
  0x24: "Read Scaling Data by Identifier",
68
66
  0x2a: "Read Data by Periodic Identifier",
69
67
  0x2c: "Dynamically Define Data Identifier",
70
68
  0x2e: "Write Data by Identifier",
71
- 0x3d: "Write Memory by Address ",
69
+ 0x3d: "Write Memory by Address",
72
70
  0x14: "Clear Diagnostic Information",
73
71
  0x19: "Read DTC Information",
74
72
  0x2f: "Input Output Control by Identifier",
@@ -170,9 +168,3 @@ def is_response_pending(telegram_payload: bytes, request_sid: Optional[int] = No
170
168
 
171
169
  # if all of the above applies, we received a "stay tuned" response
172
170
  return True
173
-
174
-
175
- # previous versions of odxtools had a typo here. hit happens!
176
- @deprecated(details="use is_response_pending()")
177
- def is_reponse_pending(telegram_payload: bytes, request_sid: Optional[int] = None) -> bool:
178
- return is_reponse_pending(telegram_payload, request_sid)
odxtools/unit.py CHANGED
@@ -1,17 +1,15 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
3
+ from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .exceptions import odxassert, odxrequire
8
8
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
9
  from .physicaldimension import PhysicalDimension
10
+ from .snrefcontext import SnRefContext
10
11
  from .utils import dataclass_fields_asdict
11
12
 
12
- if TYPE_CHECKING:
13
- from .diaglayer import DiagLayer
14
-
15
13
 
16
14
  @dataclass
17
15
  class Unit(IdentifiableElement):
@@ -55,7 +53,6 @@ class Unit(IdentifiableElement):
55
53
  ```
56
54
  """
57
55
  display_name: str
58
- oid: Optional[str]
59
56
  factor_si_to_unit: Optional[float]
60
57
  offset_si_to_unit: Optional[float]
61
58
  physical_dimension_ref: Optional[OdxLinkRef]
@@ -66,7 +63,7 @@ class Unit(IdentifiableElement):
66
63
  @staticmethod
67
64
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Unit":
68
65
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
69
- oid = et_element.get("OID")
66
+
70
67
  display_name = odxrequire(et_element.findtext("DISPLAY-NAME"))
71
68
 
72
69
  def read_optional_float(element: ElementTree.Element, name: str) -> Optional[float]:
@@ -82,7 +79,6 @@ class Unit(IdentifiableElement):
82
79
 
83
80
  return Unit(
84
81
  display_name=display_name,
85
- oid=oid,
86
82
  factor_si_to_unit=factor_si_to_unit,
87
83
  offset_si_to_unit=offset_si_to_unit,
88
84
  physical_dimension_ref=physical_dimension_ref,
@@ -104,5 +100,5 @@ class Unit(IdentifiableElement):
104
100
  f"The physical_dimension_ref must be resolved to a PhysicalDimension."
105
101
  f" {self.physical_dimension_ref} referenced {self._physical_dimension}")
106
102
 
107
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
103
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
108
104
  pass
odxtools/unitgroup.py CHANGED
@@ -1,19 +1,17 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
3
  from enum import Enum
4
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
4
+ from typing import Any, Dict, List, Optional, cast
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .element import NamedElement
8
8
  from .exceptions import odxraise, odxrequire
9
9
  from .nameditemlist import NamedItemList
10
10
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from .snrefcontext import SnRefContext
11
12
  from .unit import Unit
12
13
  from .utils import dataclass_fields_asdict
13
14
 
14
- if TYPE_CHECKING:
15
- from .diaglayer import DiagLayer
16
-
17
15
 
18
16
  class UnitGroupCategory(Enum):
19
17
  COUNTRY = "COUNTRY"
@@ -57,7 +55,7 @@ class UnitGroup(NamedElement):
57
55
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
58
56
  self._units = NamedItemList[Unit]([odxlinks.resolve(ref) for ref in self.unit_refs])
59
57
 
60
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
58
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
61
59
  pass
62
60
 
63
61
  @property
odxtools/unitspec.py CHANGED
@@ -1,19 +1,16 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Union
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .createsdgs import create_sdgs_from_et
7
6
  from .nameditemlist import NamedItemList
8
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
9
8
  from .physicaldimension import PhysicalDimension
9
+ from .snrefcontext import SnRefContext
10
10
  from .specialdatagroup import SpecialDataGroup
11
11
  from .unit import Unit
12
12
  from .unitgroup import UnitGroup
13
13
 
14
- if TYPE_CHECKING:
15
- from .diaglayer import DiagLayer
16
-
17
14
 
18
15
  @dataclass
19
16
  class UnitSpec:
@@ -28,9 +25,9 @@ class UnitSpec:
28
25
  """
29
26
 
30
27
  # TODO (?): Why are there type errors...
31
- unit_groups: Union[NamedItemList[UnitGroup], List[UnitGroup]]
32
- units: Union[NamedItemList[Unit], List[Unit]]
33
- physical_dimensions: Union[NamedItemList[PhysicalDimension], List[PhysicalDimension]]
28
+ unit_groups: NamedItemList[UnitGroup]
29
+ units: NamedItemList[Unit]
30
+ physical_dimensions: NamedItemList[PhysicalDimension]
34
31
  sdgs: List[SpecialDataGroup]
35
32
 
36
33
  def __post_init__(self) -> None:
@@ -41,15 +38,18 @@ class UnitSpec:
41
38
  @staticmethod
42
39
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "UnitSpec":
43
40
 
44
- unit_groups = [
41
+ unit_groups = NamedItemList([
45
42
  UnitGroup.from_et(el, doc_frags) for el in et_element.iterfind("UNIT-GROUPS/UNIT-GROUP")
46
- ]
47
- units = [Unit.from_et(el, doc_frags) for el in et_element.iterfind("UNITS/UNIT")]
48
- physical_dimensions = [
43
+ ])
44
+ units = NamedItemList(
45
+ [Unit.from_et(el, doc_frags) for el in et_element.iterfind("UNITS/UNIT")])
46
+ physical_dimensions = NamedItemList([
49
47
  PhysicalDimension.from_et(el, doc_frags)
50
48
  for el in et_element.iterfind("PHYSICAL-DIMENSIONS/PHYSICAL-DIMENSION")
49
+ ])
50
+ sdgs = [
51
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
51
52
  ]
52
- sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
53
53
 
54
54
  return UnitSpec(
55
55
  unit_groups=unit_groups,
@@ -76,10 +76,10 @@ class UnitSpec:
76
76
  for sdg in self.sdgs:
77
77
  sdg._resolve_odxlinks(odxlinks)
78
78
 
79
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
79
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
80
80
  for unit in self.units:
81
- unit._resolve_snrefs(diag_layer)
81
+ unit._resolve_snrefs(context)
82
82
  for group in self.unit_groups:
83
- group._resolve_snrefs(diag_layer)
83
+ group._resolve_snrefs(context)
84
84
  for sdg in self.sdgs:
85
- sdg._resolve_snrefs(diag_layer)
85
+ sdg._resolve_snrefs(context)
odxtools/utils.py CHANGED
@@ -1,32 +1,50 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import dataclasses
3
3
  import re
4
- from typing import Any, Dict, Optional
5
- from xml.etree import ElementTree
4
+ from typing import TYPE_CHECKING, Any, Dict, Optional
5
+
6
+ if TYPE_CHECKING:
7
+ from .database import Database
8
+ from .diaglayers.diaglayer import DiagLayer
9
+ from .snrefcontext import SnRefContext
10
+
11
+
12
+ def retarget_snrefs(database: "Database",
13
+ diag_layer: "DiagLayer",
14
+ context: Optional["SnRefContext"] = None) -> None:
15
+ """Re-resolve the short name references reachable by a
16
+ DiagLayer to this DiagLayer
17
+
18
+ This implies that after the SNREFs have been retargeted, accessing
19
+ the resolved objects via a different diagnostic layer might not be
20
+ correct. E.g.: If the ECU variants "V1" and "V2" are derived from
21
+ the base variant "BV", BV defines a short name reference to a data
22
+ object property called "Foo" and V1 and V2 both define a "Foo"
23
+ DOP, the reference in the base variant to Foo ought to be resolved
24
+ differently depending on whether it is accessed via V1 or
25
+ V2. Since odxtools resolves all references ahead of time, a fixed
26
+ variant has to be chosen. This method allows to switch the variant
27
+ to another one.
6
28
 
29
+ """
30
+ from .snrefcontext import SnRefContext
7
31
 
8
- def create_description_from_et(et_element: Optional[ElementTree.Element],) -> Optional[str]:
9
- """Read a description tag.
10
-
11
- The description is located underneath the DESC tag of an an ODX
12
- element."""
13
-
14
- if et_element is None:
15
- return None
32
+ if context is None:
33
+ context = SnRefContext()
16
34
 
17
- if et_element.tag != "DESC":
18
- raise TypeError(f"Attempted to extract an ODX description from a "
19
- f"'{et_element.tag}' XML node. (Must be a 'DESC' node!)")
35
+ if context.database is None:
36
+ context.database = database
20
37
 
21
- # Extract the contents of the tag as a XHTML string.
22
- raw_string = et_element.text or ""
23
- for e in et_element:
24
- raw_string += ElementTree.tostring(e, encoding="unicode")
38
+ if context.diag_layer is None:
39
+ context.diag_layer = diag_layer
25
40
 
26
- # remove white spaces at the beginning and at the end of lines
27
- stripped_lines = [x.strip() for x in raw_string.split("\n")]
41
+ # retarget the objects "owned" by the layer itself
42
+ diag_layer._resolve_snrefs(context)
28
43
 
29
- return "\n".join(stripped_lines).strip()
44
+ # retarget all parents of the current layer (if any)
45
+ if (parent_refs := getattr(diag_layer, "parent_refs", None)) is not None:
46
+ for pr in parent_refs:
47
+ retarget_snrefs(database, pr.layer, context)
30
48
 
31
49
 
32
50
  def dataclass_fields_asdict(obj: Any) -> Dict[str, Any]:
@@ -0,0 +1,32 @@
1
+ # SPDX-License-Identifier: MIT
2
+ import typing
3
+ from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING, List, runtime_checkable
5
+ from xml.etree import ElementTree
6
+
7
+ from .element import IdentifiableElement, NamedElement
8
+ from .nameditemlist import NamedItemList
9
+ from .odxlink import OdxDocFragment
10
+ from .utils import dataclass_fields_asdict
11
+
12
+ if TYPE_CHECKING:
13
+ pass
14
+
15
+
16
+ @runtime_checkable
17
+ class HasVariableGroups(typing.Protocol):
18
+
19
+ @property
20
+ def variable_groups(self) -> NamedItemList["VariableGroup"]:
21
+ ...
22
+
23
+
24
+ @dataclass
25
+ class VariableGroup(IdentifiableElement):
26
+
27
+ @staticmethod
28
+ def from_et(et_element: ElementTree.Element,
29
+ doc_frags: List[OdxDocFragment]) -> "VariableGroup":
30
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
31
+
32
+ return VariableGroup(**kwargs)
odxtools/version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '6.6.1'
16
- __version_tuple__ = version_tuple = (6, 6, 1)
15
+ __version__ = version = '9.3.0'
16
+ __version_tuple__ = version_tuple = (9, 3, 0)
@@ -1,10 +1,11 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import datetime
3
3
  import inspect
4
+ import mimetypes
4
5
  import os
5
6
  import time
6
7
  import zipfile
7
- from typing import Any, Dict, List, Optional, Tuple
8
+ from typing import Any, Dict, Optional
8
9
 
9
10
  import jinja2
10
11
 
@@ -60,7 +61,6 @@ __templates_dir = os.path.sep.join([os.path.dirname(__module_filename), "templat
60
61
  def write_pdx_file(
61
62
  output_file_name: str,
62
63
  database: Database,
63
- auxiliary_content_specifiers: Optional[List[Tuple[str, bytes]]] = None,
64
64
  templates_dir: str = __templates_dir,
65
65
  ) -> bool:
66
66
  """
@@ -68,9 +68,6 @@ def write_pdx_file(
68
68
  """
69
69
  global odxdatabase
70
70
 
71
- if auxiliary_content_specifiers is None:
72
- auxiliary_content_specifiers = []
73
-
74
71
  odxdatabase = database
75
72
 
76
73
  file_index = []
@@ -96,12 +93,18 @@ def write_pdx_file(
96
93
  # are written based on the database)
97
94
  continue
98
95
 
99
- template_file_mime_type = "text/plain"
96
+ template_file_mime_type = None
100
97
  if template_file_name.endswith(".odx-cs"):
101
98
  template_file_mime_type = "application/x-asam.odx.odx-cs"
102
99
  elif template_file_name.endswith(".odx-d"):
103
100
  template_file_mime_type = "application/x-asam.odx.odx-d"
104
101
 
102
+ guessed_mime_type, guessed_encoding = mimetypes.guess_type(template_file_name)
103
+ if template_file_mime_type is None and guessed_mime_type is not None:
104
+ template_file_mime_type = guessed_mime_type
105
+ else:
106
+ template_file_mime_type = "application/octet-stream"
107
+
105
108
  in_path = [root]
106
109
  in_path.append(template_file_name)
107
110
  in_file_name = os.path.sep.join(in_path)
@@ -115,22 +118,29 @@ def write_pdx_file(
115
118
  out_file.write(open(in_file_name, "rb").read())
116
119
 
117
120
  # write the auxiliary files
118
- for output_file_name, data in auxiliary_content_specifiers:
121
+ for output_file_name, data_file in database.auxiliary_files.items():
119
122
  file_cdate = datetime.datetime.fromtimestamp(time.time())
120
123
  creation_date = file_cdate.strftime("%Y-%m-%dT%H:%M:%S")
121
124
 
122
- mime_type = "text/plain"
123
- if template_file_name.endswith(".odx-cs"):
125
+ mime_type = None
126
+ if output_file_name.endswith(".odx-cs"):
124
127
  mime_type = "application/x-asam.odx.odx-cs"
125
- elif template_file_name.endswith(".odx-d"):
128
+ elif output_file_name.endswith(".odx-d"):
126
129
  mime_type = "application/x-asam.odx.odx-d"
127
130
 
131
+ guessed_mime_type, guessed_encoding = mimetypes.guess_type(output_file_name)
132
+ if mime_type is None and guessed_mime_type is not None:
133
+ mime_type = guessed_mime_type
134
+ else:
135
+ mime_type = "application/octet-stream"
136
+
128
137
  zf_name = os.path.basename(output_file_name)
129
138
  with zf.open(zf_name, "w") as out_file:
130
139
  file_index.append((zf_name, creation_date, mime_type))
131
- out_file.write(data) # type: ignore
140
+ out_file.write(data_file.read())
132
141
 
133
142
  jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_dir))
143
+ jinja_env.globals["getattr"] = getattr
134
144
  jinja_env.globals["hasattr"] = hasattr
135
145
  jinja_env.globals["odxraise"] = jinja2_odxraise_helper
136
146
  jinja_env.globals["make_xml_attrib"] = make_xml_attrib
@@ -187,7 +197,7 @@ def write_pdx_file(
187
197
 
188
198
  # write the index.xml file
189
199
  vars["file_index"] = file_index
190
- index_tpl = jinja_env.get_template("index.xml.xml.jinja2")
200
+ index_tpl = jinja_env.get_template("index.xml.jinja2")
191
201
  text = index_tpl.render(**vars)
192
202
  zf.writestr("index.xml", text)
193
203
 
odxtools/xdoc.py CHANGED
@@ -1,15 +1,13 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
3
+ from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import NamedElement
7
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
+ from .snrefcontext import SnRefContext
8
9
  from .utils import dataclass_fields_asdict
9
10
 
10
- if TYPE_CHECKING:
11
- from .diaglayer import DiagLayer
12
-
13
11
 
14
12
  @dataclass
15
13
  class XDoc(NamedElement):
@@ -45,5 +43,5 @@ class XDoc(NamedElement):
45
43
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
46
44
  pass
47
45
 
48
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
46
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
49
47
  pass