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,12 +1,15 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import re
3
3
  import textwrap
4
- from typing import Any, Callable, Dict, List, Optional, Union
4
+ from typing import List, Optional, Tuple, Union
5
5
 
6
6
  import markdownify
7
- from tabulate import tabulate # TODO: switch to rich tables
7
+ from rich import print as rich_print
8
+ from rich.padding import Padding as RichPadding
9
+ from rich.table import Table as RichTable
8
10
 
9
- from ..diaglayer import DiagLayer
11
+ from ..description import Description
12
+ from ..diaglayers.diaglayer import DiagLayer
10
13
  from ..diagservice import DiagService
11
14
  from ..parameters.codedconstparameter import CodedConstParameter
12
15
  from ..parameters.nrcconstparameter import NrcConstParameter
@@ -17,9 +20,9 @@ from ..parameters.valueparameter import ValueParameter
17
20
  from ..singleecujob import SingleEcuJob
18
21
 
19
22
 
20
- def format_desc(desc: str, indent: int = 0) -> str:
23
+ def format_desc(description: Description, indent: int = 0) -> str:
21
24
  # Collapse whitespaces
22
- desc = re.sub(r"\s+", " ", desc)
25
+ desc = re.sub(r"\s+", " ", str(description))
23
26
  # Covert XHTML to Markdown
24
27
  desc = markdownify.markdownify(desc)
25
28
  # Collapse blank lines
@@ -35,147 +38,179 @@ def print_diagnostic_service(service: DiagService,
35
38
  print_pre_condition_states: bool = False,
36
39
  print_state_transitions: bool = False,
37
40
  print_audiences: bool = False,
38
- allow_unknown_bit_lengths: bool = False,
39
- print_fn: Callable = print) -> None:
41
+ allow_unknown_bit_lengths: bool = False) -> None:
40
42
 
41
- print_fn(f" Service '{service.short_name}':")
43
+ rich_print(f" Service '{service.short_name}':")
42
44
 
43
45
  if service.description:
44
46
  desc = format_desc(service.description, indent=3)
45
- print_fn(f" Description: " + desc)
47
+ rich_print(f" Description: " + desc)
46
48
 
47
49
  if print_pre_condition_states and len(service.pre_condition_states) > 0:
48
50
  pre_condition_states_short_names = [
49
51
  pre_condition_state.short_name for pre_condition_state in service.pre_condition_states
50
52
  ]
51
- print_fn(f" Pre-Condition States: {', '.join(pre_condition_states_short_names)}")
53
+ rich_print(f" Pre-Condition States: {', '.join(pre_condition_states_short_names)}")
52
54
 
53
55
  if print_state_transitions and len(service.state_transitions) > 0:
54
56
  state_transitions = [
55
57
  f"{state_transition.source_snref} -> {state_transition.target_snref}"
56
58
  for state_transition in service.state_transitions
57
59
  ]
58
- print_fn(f" State Transitions: {', '.join(state_transitions)}")
60
+ rich_print(f" State Transitions: {', '.join(state_transitions)}")
59
61
 
60
62
  if print_audiences and service.audience:
61
63
  enabled_audiences_short_names = [
62
64
  enabled_audience.short_name for enabled_audience in service.audience.enabled_audiences
63
65
  ]
64
- print_fn(f" Enabled Audiences: {', '.join(enabled_audiences_short_names)}")
66
+ rich_print(f" Enabled Audiences: {', '.join(enabled_audiences_short_names)}")
65
67
 
66
68
  if print_params:
67
- print_service_parameters(
68
- service, allow_unknown_bit_lengths=allow_unknown_bit_lengths, print_fn=print_fn)
69
+ print_service_parameters(service, allow_unknown_bit_lengths=allow_unknown_bit_lengths)
69
70
 
70
71
 
71
72
  def print_service_parameters(service: DiagService,
72
- allow_unknown_bit_lengths: bool = False,
73
- print_fn: Callable = print) -> None:
74
- # prints parameter details of request, positive response and negative response of diagnostic service
73
+ *,
74
+ allow_unknown_bit_lengths: bool = False) -> None:
75
+ # prints parameter details of request, positive response and
76
+ # negative response of diagnostic service
75
77
 
76
78
  # Request
77
79
  if service.request:
78
- print_fn(f" Request '{service.request.short_name}':")
80
+ rich_print(f" Request '{service.request.short_name}':")
79
81
  const_prefix = service.request.coded_const_prefix()
80
- print_fn(
82
+ rich_print(
81
83
  f" Identifying Prefix: 0x{const_prefix.hex().upper()} ({bytes(const_prefix)!r})")
82
- print_fn(f" Parameters:")
83
- table = extract_parameter_tabulation_data(list(service.request.parameters))
84
- table_str = textwrap.indent(tabulate(table, headers='keys', tablefmt='presto'), " ")
85
- print_fn()
86
- print_fn(table_str)
87
- print_fn()
84
+ rich_print(f" Parameters:")
85
+ param_table = extract_parameter_tabulation_data(service.request.parameters)
86
+ rich_print(RichPadding(param_table, pad=(0, 0, 0, 4)))
87
+ rich_print()
88
88
  else:
89
- print_fn(f" No Request!")
89
+ rich_print(f" No Request!")
90
90
 
91
91
  # Positive Responses
92
92
  if not service.positive_responses:
93
- print_fn(f" No positive responses")
93
+ rich_print(f" No positive responses")
94
94
 
95
95
  for resp in service.positive_responses:
96
- print_fn(f" Positive Response '{resp.short_name}':")
97
- print_fn(f" Parameters:\n")
96
+ rich_print(f" Positive Response '{resp.short_name}':")
97
+ rich_print(f" Parameters:\n")
98
98
  table = extract_parameter_tabulation_data(list(resp.parameters))
99
- table_str = textwrap.indent(tabulate(table, headers='keys', tablefmt='presto'), " ")
100
- print_fn(table_str)
101
- print_fn()
99
+ rich_print(RichPadding(table, pad=(0, 0, 0, 4)))
100
+ rich_print()
102
101
 
103
102
  # Negative Response
104
103
  if not service.negative_responses:
105
- print_fn(f" No negative responses")
104
+ rich_print(f" No negative responses")
106
105
 
107
106
  for resp in service.negative_responses:
108
- print_fn(f" Negative Response '{resp.short_name}':")
109
- print_fn(f" Parameters:\n")
107
+ rich_print(f" Negative Response '{resp.short_name}':")
108
+ rich_print(f" Parameters:\n")
110
109
  table = extract_parameter_tabulation_data(list(resp.parameters))
111
- table_str = textwrap.indent(tabulate(table, headers='keys', tablefmt='presto'), " ")
112
- print_fn(table_str)
113
- print_fn()
110
+ rich_print(RichPadding(table, pad=(0, 0, 0, 4)))
111
+ rich_print()
114
112
 
115
- print_fn("\n")
113
+ rich_print("\n")
116
114
 
117
115
 
118
- def extract_service_tabulation_data(services: List[DiagService]) -> Dict[str, Any]:
119
- # extracts data of diagnostic services into Dictionary which can be printed by tabulate module
120
- # TODO: consider indentation
116
+ def extract_service_tabulation_data(services: List[DiagService],
117
+ *,
118
+ additional_columns: Optional[List[Tuple[str, List[str]]]] = None
119
+ ) -> RichTable:
120
+ """Extracts data of diagnostic services into Dictionary which can
121
+ be printed by tabulate module
122
+ """
121
123
 
122
- name = []
123
- semantic = []
124
- request: List[Optional[str]] = []
124
+ # Create Rich table
125
+ table = RichTable(
126
+ title="", show_header=True, header_style="bold cyan", border_style="blue", show_lines=True)
127
+
128
+ name_column: List[str] = []
129
+ semantic_column: List[str] = []
130
+ request_column: List[str] = []
125
131
 
126
132
  for service in services:
127
- name.append(service.short_name)
128
- semantic.append(service.semantic)
133
+ name_column.append(service.short_name)
134
+ semantic_column.append(service.semantic or "")
129
135
 
130
136
  if service.request:
131
137
  prefix = service.request.coded_const_prefix()
132
- request.append(f"0x{str(prefix.hex().upper())[:32]}...") if len(
133
- prefix) > 32 else request.append(f"0x{str(prefix.hex().upper())}")
138
+ request_column.append(f"0x{str(prefix.hex().upper())[:32]}...") if len(
139
+ prefix) > 32 else request_column.append(f"0x{str(prefix.hex().upper())}")
134
140
  else:
135
- request.append(None)
136
-
137
- return {'Name': name, 'Semantic': semantic, 'Hex-Request': request}
138
-
139
-
140
- def extract_parameter_tabulation_data(parameters: List[Parameter]) -> Dict[str, Any]:
141
- # extracts data of parameters of diagnostic services into Dictionary which can be printed by tabulate module
142
- # TODO: consider indentation
143
-
144
- name = []
145
- byte = []
146
- bit_length: List[Optional[int]] = []
147
- semantic = []
148
- param_type = []
149
- value: List[Optional[str]] = []
150
- value_type: List[Optional[str]] = []
151
- data_type: List[Optional[str]] = []
152
- dop: List[Optional[str]] = []
141
+ request_column.append("")
142
+
143
+ table.add_column("Name", style="green")
144
+ table.add_column("Semantic", justify="left", style="white")
145
+ table.add_column("Request", justify="left", style="white")
146
+ if additional_columns is not None:
147
+ for ac_title, _ in additional_columns:
148
+ table.add_column(ac_title, justify="left", style="white")
149
+
150
+ rows = zip(name_column, semantic_column, request_column,
151
+ *[ac[1] for ac in additional_columns])
152
+ for row in rows:
153
+ table.add_row(*map(str, row))
154
+
155
+ return table
156
+
157
+
158
+ def extract_parameter_tabulation_data(parameters: List[Parameter]) -> RichTable:
159
+ # extracts data of parameters of diagnostic services into
160
+ # a RichTable object that can be printed
161
+
162
+ # Create Rich table
163
+ table = RichTable(
164
+ title="", show_header=True, header_style="bold cyan", border_style="blue", show_lines=True)
165
+
166
+ # Add columns with appropriate styling
167
+ table.add_column("Name", style="green")
168
+ table.add_column("Byte Position", justify="right", style="yellow")
169
+ table.add_column("Bit Length", justify="right", style="yellow")
170
+ table.add_column("Semantic", justify="left", style="white")
171
+ table.add_column("Parameter Type", justify="left", style="white")
172
+ table.add_column("Data Type", justify="left", style="white")
173
+ table.add_column("Value", justify="left", style="yellow")
174
+ table.add_column("Value Type", justify="left", style="white")
175
+ table.add_column("Linked DOP", justify="left", style="white")
176
+
177
+ name_column: List[str] = []
178
+ byte_column: List[str] = []
179
+ bit_length_column: List[str] = []
180
+ semantic_column: List[str] = []
181
+ param_type_column: List[str] = []
182
+ value_column: List[str] = []
183
+ value_type_column: List[str] = []
184
+ data_type_column: List[str] = []
185
+ dop_column: List[str] = []
153
186
 
154
187
  for param in parameters:
155
- name.append(param.short_name)
156
- byte.append(param.byte_position)
157
- semantic.append(param.semantic)
158
- param_type.append(param.parameter_type)
188
+ name_column.append(param.short_name)
189
+ byte_column.append("" if param.byte_position is None else str(param.byte_position))
190
+ semantic_column.append(param.semantic or "")
191
+ param_type_column.append(param.parameter_type)
192
+ length = 0
159
193
  if param.get_static_bit_length() is not None:
160
- bit_length.append(param.get_static_bit_length())
161
- length = (param.get_static_bit_length() or 0) // 4
194
+ n = param.get_static_bit_length()
195
+ bit_length_column.append("" if n is None else str(n))
196
+ length = (n or 0) // 4
162
197
  else:
163
- bit_length.append(None)
198
+ bit_length_column.append("")
164
199
  if isinstance(param, CodedConstParameter):
165
200
  if isinstance(param.coded_value, int):
166
- value.append(f"0x{param.coded_value:0{length}X}")
201
+ value_column.append(f"0x{param.coded_value:0{length}X}")
167
202
  elif isinstance(param.coded_value, bytes) or isinstance(param.coded_value, bytearray):
168
- value.append(f"0x{param.coded_value.hex().upper()}")
203
+ value_column.append(f"0x{param.coded_value.hex().upper()}")
169
204
  else:
170
- value.append(f"{param.coded_value!r}")
171
- data_type.append(param.diag_coded_type.base_data_type.name)
172
- value_type.append('coded value')
173
- dop.append(None)
205
+ value_column.append(f"{param.coded_value!r}")
206
+ data_type_column.append(param.diag_coded_type.base_data_type.name)
207
+ value_type_column.append('coded value')
208
+ dop_column.append("")
174
209
  elif isinstance(param, NrcConstParameter):
175
- data_type.append(param.diag_coded_type.base_data_type.name)
176
- value.append(str(param.coded_values))
177
- value_type.append('coded values')
178
- dop.append(None)
210
+ data_type_column.append(param.diag_coded_type.base_data_type.name)
211
+ value_column.append(str(param.coded_values))
212
+ value_type_column.append('coded values')
213
+ dop_column.append("")
179
214
  elif isinstance(param, (PhysicalConstantParameter, SystemParameter, ValueParameter)):
180
215
  # this is a hack to make this routine work for parameters
181
216
  # which reference DOPs of a type that a is not yet
@@ -184,71 +219,71 @@ def extract_parameter_tabulation_data(parameters: List[Parameter]) -> Dict[str,
184
219
  param_dop = getattr(param, "_dop", None)
185
220
 
186
221
  if param_dop is not None:
187
- dop.append(param_dop.short_name)
222
+ dop_column.append(param_dop.short_name)
188
223
 
189
224
  if param_dop is not None and (phys_type := getattr(param, "physical_type",
190
225
  None)) is not None:
191
- data_type.append(phys_type.base_data_type.name)
226
+ data_type_column.append(phys_type.base_data_type.name)
192
227
  else:
193
- data_type.append(None)
228
+ data_type_column.append("")
194
229
  if isinstance(param, PhysicalConstantParameter):
195
230
  if isinstance(param.physical_constant_value, bytes) or isinstance(
196
231
  param.physical_constant_value, bytearray):
197
- value.append(f"0x{param.physical_constant_value.hex().upper()}")
232
+ value_column.append(f"0x{param.physical_constant_value.hex().upper()}")
198
233
  else:
199
- value.append(f"{param.physical_constant_value!r}")
200
- value_type.append('constant value')
234
+ value_column.append(f"{param.physical_constant_value!r}")
235
+ value_type_column.append('constant value')
201
236
  elif isinstance(param, ValueParameter) and param.physical_default_value is not None:
202
237
  if isinstance(param.physical_default_value, bytes) or isinstance(
203
238
  param.physical_default_value, bytearray):
204
- value.append(f"0x{param.physical_default_value.hex().upper()}")
239
+ value_column.append(f"0x{param.physical_default_value.hex().upper()}")
205
240
  else:
206
- value.append(f"{param.physical_default_value!r}")
207
- value_type.append('default value')
241
+ value_column.append(f"{param.physical_default_value!r}")
242
+ value_type_column.append('default value')
208
243
  else:
209
- value.append(None)
210
- value_type.append(None)
244
+ value_column.append("")
245
+ value_type_column.append("")
211
246
  else:
212
- value.append(None)
213
- data_type.append(None)
214
- value_type.append(None)
215
- dop.append(None)
216
-
217
- return {
218
- 'Name': name,
219
- 'Byte Position': byte,
220
- 'Bit Length': bit_length,
221
- 'Semantic': semantic,
222
- 'Parameter Type': param_type,
223
- 'Data Type': data_type,
224
- 'Value': value,
225
- 'Value Type': value_type,
226
- 'Linked DOP': dop
227
- }
228
-
229
-
230
- def print_dl_metrics(variants: List[DiagLayer], print_fn: Callable = print) -> None:
231
-
232
- name = []
233
- type = []
234
- num_services = []
235
- num_dops = []
236
- num_comparams = []
247
+ value_column.append("")
248
+ data_type_column.append("")
249
+ value_type_column.append("")
250
+ dop_column.append("")
251
+
252
+ # Add all rows at once by zipping dictionary values
253
+ rows = zip(name_column, byte_column, bit_length_column, semantic_column, param_type_column,
254
+ data_type_column, value_column, value_type_column, dop_column)
255
+ for row in rows:
256
+ table.add_row(*map(str, row))
257
+
258
+ return table
259
+
260
+
261
+ def print_dl_metrics(variants: List[DiagLayer]) -> None:
262
+ """
263
+ Print diagnostic layer metrics using Rich tables.
264
+ Args:
265
+ variants: List of diagnostic layer variants to analyze
266
+ """
267
+ # Create Rich table
268
+ table = RichTable(
269
+ title="", show_header=True, header_style="bold cyan", border_style="blue", show_lines=True)
270
+
271
+ # Add columns with appropriate styling
272
+ table.add_column("Name", style="green")
273
+ table.add_column("Variant Type", style="magenta")
274
+ table.add_column("Number of Services", justify="right", style="yellow")
275
+ table.add_column("Number of DOPs", justify="right", style="yellow")
276
+ table.add_column("Number of communication parameters", justify="right", style="yellow")
277
+
278
+ # Process each variant
237
279
  for variant in variants:
238
280
  assert isinstance(variant, DiagLayer)
239
281
  all_services: List[Union[DiagService, SingleEcuJob]] = sorted(
240
282
  variant.services, key=lambda x: x.short_name)
241
- name.append(variant.short_name)
242
- type.append(variant.variant_type.value)
243
- num_services.append(len(all_services))
244
- num_dops.append(len(variant.diag_data_dictionary_spec.data_object_props))
245
- num_comparams.append(len(variant.comparams))
246
-
247
- table = {
248
- 'Name': name,
249
- 'Variant Type': type,
250
- 'Number of Services': num_services,
251
- 'Number of DOPs': num_dops,
252
- 'Number of communication parameters': num_comparams
253
- }
254
- print_fn(tabulate(table, headers='keys', tablefmt='presto'))
283
+ ddds = variant.diag_data_dictionary_spec
284
+
285
+ # Add row to table
286
+ table.add_row(variant.short_name, variant.variant_type.value, str(len(all_services)),
287
+ str(len(ddds.data_object_props)),
288
+ str(len(getattr(variant, "comparams_refs", []))))
289
+ rich_print(table)