odxtools 7.1.0__py3-none-any.whl → 7.2.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 (131) hide show
  1. odxtools/__init__.py +6 -4
  2. odxtools/additionalaudience.py +3 -5
  3. odxtools/admindata.py +5 -7
  4. odxtools/audience.py +3 -5
  5. odxtools/basecomparam.py +3 -5
  6. odxtools/basicstructure.py +10 -17
  7. odxtools/cli/_parser_utils.py +1 -1
  8. odxtools/cli/_print_utils.py +3 -2
  9. odxtools/cli/compare.py +1 -1
  10. odxtools/companydata.py +5 -7
  11. odxtools/companydocinfo.py +7 -8
  12. odxtools/companyrevisioninfo.py +3 -5
  13. odxtools/companyspecificinfo.py +8 -9
  14. odxtools/comparam.py +4 -6
  15. odxtools/comparaminstance.py +6 -8
  16. odxtools/comparamspec.py +14 -13
  17. odxtools/comparamsubset.py +17 -16
  18. odxtools/complexcomparam.py +5 -7
  19. odxtools/compumethods/compuconst.py +31 -0
  20. odxtools/compumethods/compudefaultvalue.py +27 -0
  21. odxtools/compumethods/compuinternaltophys.py +39 -0
  22. odxtools/compumethods/compuinversevalue.py +7 -0
  23. odxtools/compumethods/compumethod.py +67 -12
  24. odxtools/compumethods/compuphystointernal.py +39 -0
  25. odxtools/compumethods/compuscale.py +15 -26
  26. odxtools/compumethods/createanycompumethod.py +14 -160
  27. odxtools/compumethods/identicalcompumethod.py +31 -6
  28. odxtools/compumethods/linearcompumethod.py +69 -189
  29. odxtools/compumethods/linearsegment.py +193 -0
  30. odxtools/compumethods/scalelinearcompumethod.py +132 -26
  31. odxtools/compumethods/tabintpcompumethod.py +119 -99
  32. odxtools/compumethods/texttablecompumethod.py +107 -43
  33. odxtools/createanydiagcodedtype.py +10 -67
  34. odxtools/database.py +68 -62
  35. odxtools/dataobjectproperty.py +10 -19
  36. odxtools/description.py +47 -0
  37. odxtools/determinenumberofitems.py +4 -5
  38. odxtools/diagcodedtype.py +29 -12
  39. odxtools/diagcomm.py +10 -6
  40. odxtools/diagdatadictionaryspec.py +20 -21
  41. odxtools/diaglayer.py +34 -5
  42. odxtools/diaglayercontainer.py +17 -11
  43. odxtools/diaglayerraw.py +20 -21
  44. odxtools/diagnostictroublecode.py +7 -8
  45. odxtools/diagservice.py +9 -7
  46. odxtools/docrevision.py +5 -7
  47. odxtools/dopbase.py +7 -8
  48. odxtools/dtcdop.py +5 -8
  49. odxtools/dynamicendmarkerfield.py +22 -9
  50. odxtools/dynamiclengthfield.py +5 -11
  51. odxtools/element.py +4 -3
  52. odxtools/endofpdufield.py +0 -2
  53. odxtools/environmentdatadescription.py +4 -6
  54. odxtools/exceptions.py +1 -1
  55. odxtools/field.py +9 -9
  56. odxtools/functionalclass.py +3 -5
  57. odxtools/inputparam.py +3 -5
  58. odxtools/leadinglengthinfotype.py +15 -2
  59. odxtools/loadfile.py +64 -0
  60. odxtools/minmaxlengthtype.py +20 -2
  61. odxtools/modification.py +3 -5
  62. odxtools/multiplexer.py +7 -14
  63. odxtools/multiplexercase.py +4 -6
  64. odxtools/multiplexerdefaultcase.py +4 -6
  65. odxtools/multiplexerswitchkey.py +4 -5
  66. odxtools/negoutputparam.py +3 -5
  67. odxtools/outputparam.py +3 -5
  68. odxtools/parameterinfo.py +3 -3
  69. odxtools/parameters/codedconstparameter.py +2 -14
  70. odxtools/parameters/lengthkeyparameter.py +3 -17
  71. odxtools/parameters/nrcconstparameter.py +2 -14
  72. odxtools/parameters/parameter.py +22 -22
  73. odxtools/parameters/parameterwithdop.py +6 -8
  74. odxtools/parameters/physicalconstantparameter.py +5 -8
  75. odxtools/parameters/reservedparameter.py +4 -3
  76. odxtools/parameters/tablekeyparameter.py +6 -9
  77. odxtools/parameters/tablestructparameter.py +6 -8
  78. odxtools/parameters/valueparameter.py +5 -8
  79. odxtools/paramlengthinfotype.py +19 -6
  80. odxtools/parentref.py +15 -1
  81. odxtools/physicaldimension.py +3 -5
  82. odxtools/progcode.py +18 -7
  83. odxtools/protstack.py +3 -5
  84. odxtools/py.typed +0 -0
  85. odxtools/relateddoc.py +7 -9
  86. odxtools/request.py +8 -0
  87. odxtools/response.py +8 -0
  88. odxtools/scaleconstr.py +3 -3
  89. odxtools/singleecujob.py +12 -10
  90. odxtools/snrefcontext.py +29 -0
  91. odxtools/specialdata.py +3 -5
  92. odxtools/specialdatagroup.py +5 -7
  93. odxtools/specialdatagroupcaption.py +3 -6
  94. odxtools/standardlengthtype.py +27 -2
  95. odxtools/state.py +3 -5
  96. odxtools/statechart.py +9 -11
  97. odxtools/statetransition.py +4 -9
  98. odxtools/staticfield.py +4 -8
  99. odxtools/table.py +7 -8
  100. odxtools/tablerow.py +7 -6
  101. odxtools/teammember.py +3 -5
  102. odxtools/templates/comparam-spec.odx-c.xml.jinja2 +2 -5
  103. odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +2 -5
  104. odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -5
  105. odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
  106. odxtools/templates/macros/printCompuMethod.xml.jinja2 +153 -0
  107. odxtools/templates/macros/printDOP.xml.jinja2 +10 -132
  108. odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
  109. odxtools/templates/macros/printElementId.xml.jinja2 +3 -3
  110. odxtools/templates/macros/printMux.xml.jinja2 +3 -2
  111. odxtools/templates/macros/printTable.xml.jinja2 +2 -3
  112. odxtools/unit.py +3 -5
  113. odxtools/unitgroup.py +3 -5
  114. odxtools/unitspec.py +9 -10
  115. odxtools/utils.py +1 -26
  116. odxtools/version.py +2 -2
  117. odxtools/{write_pdx_file.py → writepdxfile.py} +19 -10
  118. odxtools/xdoc.py +3 -5
  119. {odxtools-7.1.0.dist-info → odxtools-7.2.0.dist-info}/METADATA +1 -1
  120. odxtools-7.2.0.dist-info/RECORD +192 -0
  121. {odxtools-7.1.0.dist-info → odxtools-7.2.0.dist-info}/WHEEL +1 -1
  122. odxtools/createcompanydatas.py +0 -17
  123. odxtools/createsdgs.py +0 -19
  124. odxtools/load_file.py +0 -13
  125. odxtools/load_odx_d_file.py +0 -6
  126. odxtools/load_pdx_file.py +0 -8
  127. odxtools-7.1.0.dist-info/RECORD +0 -185
  128. /odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +0 -0
  129. {odxtools-7.1.0.dist-info → odxtools-7.2.0.dist-info}/LICENSE +0 -0
  130. {odxtools-7.1.0.dist-info → odxtools-7.2.0.dist-info}/entry_points.txt +0 -0
  131. {odxtools-7.1.0.dist-info → odxtools-7.2.0.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,19 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional
3
+ from typing import Any, Dict, List, Literal, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import final, override
7
7
 
8
- from ..createsdgs import create_sdgs_from_et
9
8
  from ..decodestate import DecodeState
10
9
  from ..element import NamedElement
11
10
  from ..encodestate import EncodeState
12
11
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
13
12
  from ..odxtypes import ParameterValue
13
+ from ..snrefcontext import SnRefContext
14
14
  from ..specialdatagroup import SpecialDataGroup
15
15
  from ..utils import dataclass_fields_asdict
16
16
 
17
- if TYPE_CHECKING:
18
- from ..diaglayer import DiagLayer
19
-
20
17
  ParameterType = Literal[
21
18
  "CODED-CONST",
22
19
  "DYNAMIC",
@@ -55,7 +52,9 @@ class Parameter(NamedElement):
55
52
  kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
56
53
 
57
54
  semantic = et_element.get("SEMANTIC")
58
- sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
55
+ sdgs = [
56
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
57
+ ]
59
58
 
60
59
  byte_position_str = et_element.findtext("BYTE-POSITION")
61
60
  bit_position_str = et_element.findtext("BIT-POSITION")
@@ -82,15 +81,9 @@ class Parameter(NamedElement):
82
81
  for sdg in self.sdgs:
83
82
  sdg._resolve_odxlinks(odxlinks)
84
83
 
85
- @final
86
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
87
- raise RuntimeError("Calling _resolve_snrefs() is not allowed for parameters. "
88
- "Use _parameter_resolve_snrefs() instead.")
89
-
90
- def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
91
- param_list: List["Parameter"]) -> None:
84
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
92
85
  for sdg in self.sdgs:
93
- sdg._resolve_snrefs(diag_layer)
86
+ sdg._resolve_snrefs(context)
94
87
 
95
88
  @property
96
89
  def parameter_type(self) -> ParameterType:
@@ -126,14 +119,15 @@ class Parameter(NamedElement):
126
119
  @final
127
120
  def encode_into_pdu(self, physical_value: Optional[ParameterValue],
128
121
  encode_state: EncodeState) -> None:
129
- """Convert a physical value into its encoded form and place it into the PDU
122
+ """Convert a physical value into its encoded form and place it
123
+ into the PDU
124
+
125
+ Also, adapt the `encode_state` so that it points to where the
126
+ next parameter is located (if the next parameter does not
127
+ explicitly specify a position)
130
128
 
131
- Also, adapt the `encode_state` so that it points to where the next
132
- parameter is located (if the parameter does not explicitly specify a
133
- position)
134
129
  """
135
130
 
136
- orig_cursor = encode_state.cursor_byte_position
137
131
  if self.byte_position is not None:
138
132
  encode_state.cursor_byte_position = encode_state.origin_byte_position + self.byte_position
139
133
 
@@ -141,7 +135,6 @@ class Parameter(NamedElement):
141
135
 
142
136
  self._encode_positioned_into_pdu(physical_value, encode_state)
143
137
 
144
- encode_state.cursor_byte_position = max(encode_state.cursor_byte_position, orig_cursor)
145
138
  encode_state.cursor_bit_position = 0
146
139
 
147
140
  def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
@@ -155,7 +148,15 @@ class Parameter(NamedElement):
155
148
 
156
149
  @final
157
150
  def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
158
- orig_cursor = decode_state.cursor_byte_position
151
+ """Retrieve the raw data for the parameter from the PDU and
152
+ convert it to its physical interpretation
153
+
154
+ Also, adapt the `encode_state` so that it points to where the
155
+ next parameter is located (if the next parameter does not
156
+ explicitly specify a position)
157
+
158
+ """
159
+
159
160
  if self.byte_position is not None:
160
161
  decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
161
162
 
@@ -163,7 +164,6 @@ class Parameter(NamedElement):
163
164
 
164
165
  result = self._decode_positioned_from_pdu(decode_state)
165
166
 
166
- decode_state.cursor_byte_position = max(decode_state.cursor_byte_position, orig_cursor)
167
167
  decode_state.cursor_bit_position = 0
168
168
 
169
169
  return result
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
3
+ from typing import Any, Dict, List, Optional, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -14,12 +14,10 @@ from ..exceptions import odxassert, odxrequire
14
14
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
15
15
  from ..odxtypes import AtomicOdxType, ParameterValue
16
16
  from ..physicaltype import PhysicalType
17
+ from ..snrefcontext import SnRefContext
17
18
  from ..utils import dataclass_fields_asdict
18
19
  from .parameter import Parameter
19
20
 
20
- if TYPE_CHECKING:
21
- from ..diaglayer import DiagLayer
22
-
23
21
 
24
22
  @dataclass
25
23
  class ParameterWithDOP(Parameter):
@@ -58,12 +56,12 @@ class ParameterWithDOP(Parameter):
58
56
  self._dop = odxlinks.resolve(self.dop_ref)
59
57
 
60
58
  @override
61
- def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
62
- param_list: List[Parameter]) -> None:
63
- super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
59
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
60
+ super()._resolve_snrefs(context)
64
61
 
65
62
  if self.dop_snref:
66
- all_dops = diag_layer.diag_data_dictionary_spec.all_data_object_properties
63
+ all_dops = odxrequire(
64
+ context.diag_layer).diag_data_dictionary_spec.all_data_object_properties
67
65
  self._dop = resolve_snref(self.dop_snref, all_dops, DopBase)
68
66
 
69
67
  @property
@@ -1,6 +1,6 @@
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 typing_extensions import override
@@ -11,13 +11,11 @@ from ..encodestate import EncodeState
11
11
  from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
12
12
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
13
13
  from ..odxtypes import ParameterValue
14
+ from ..snrefcontext import SnRefContext
14
15
  from ..utils import dataclass_fields_asdict
15
- from .parameter import Parameter, ParameterType
16
+ from .parameter import ParameterType
16
17
  from .parameterwithdop import ParameterWithDOP
17
18
 
18
- if TYPE_CHECKING:
19
- from ..diaglayer import DiagLayer
20
-
21
19
 
22
20
  @dataclass
23
21
  class PhysicalConstantParameter(ParameterWithDOP):
@@ -50,9 +48,8 @@ class PhysicalConstantParameter(ParameterWithDOP):
50
48
  super()._resolve_odxlinks(odxlinks)
51
49
 
52
50
  @override
53
- def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
54
- param_list: List[Parameter]) -> None:
55
- super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
51
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
52
+ super()._resolve_snrefs(context)
56
53
 
57
54
  dop = odxrequire(self.dop)
58
55
  if not isinstance(dop, DataObjectProperty):
@@ -51,9 +51,10 @@ class ReservedParameter(Parameter):
51
51
  @override
52
52
  def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
53
53
  encode_state: EncodeState) -> None:
54
- raw_data = (0).to_bytes((encode_state.cursor_bit_position + self.bit_length + 7) // 8,
55
- "big")
56
- encode_state.emplace_bytes(raw_data, self.short_name)
54
+ encode_state.cursor_byte_position += (encode_state.cursor_bit_position + self.bit_length +
55
+ 7) // 8
56
+ encode_state.cursor_bit_position = 0
57
+ encode_state.emplace_bytes(b'', self.short_name)
57
58
 
58
59
  @override
59
60
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
@@ -10,11 +10,11 @@ from ..encodestate import EncodeState
10
10
  from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
11
11
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
12
12
  from ..odxtypes import ParameterValue
13
+ from ..snrefcontext import SnRefContext
13
14
  from ..utils import dataclass_fields_asdict
14
15
  from .parameter import Parameter, ParameterType
15
16
 
16
17
  if TYPE_CHECKING:
17
- from ..diaglayer import DiagLayer
18
18
  from ..table import Table
19
19
  from ..tablerow import TableRow
20
20
 
@@ -56,8 +56,8 @@ class TableKeyParameter(Parameter):
56
56
  **kwargs)
57
57
 
58
58
  def __post_init__(self) -> None:
59
- self._table: "Table"
60
- self._table_row: Optional["TableRow"] = None
59
+ self._table: Table
60
+ self._table_row: Optional[TableRow] = None
61
61
  if self.table_ref is None and self.table_snref is None and \
62
62
  self.table_row_ref is None and self.table_row_snref is None:
63
63
  odxraise("Either a table or a table row must be defined.")
@@ -94,12 +94,11 @@ class TableKeyParameter(Parameter):
94
94
  self._table = self._table_row.table
95
95
 
96
96
  @override
97
- def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
98
- param_list: List[Parameter]) -> None:
99
- super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
97
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
98
+ super()._resolve_snrefs(context)
100
99
 
101
100
  if self.table_snref is not None:
102
- tables = diag_layer.diag_data_dictionary_spec.tables
101
+ tables = odxrequire(context.diag_layer).diag_data_dictionary_spec.tables
103
102
  self._table = resolve_snref(self.table_snref, tables, Table)
104
103
  if self.table_row_snref is not None:
105
104
  # make sure that we know the table to which the table row
@@ -165,7 +164,6 @@ class TableKeyParameter(Parameter):
165
164
 
166
165
  encode_state.table_keys[self.short_name] = physical_value
167
166
 
168
- orig_pos = encode_state.cursor_byte_position
169
167
  pos = encode_state.cursor_byte_position
170
168
  if self.byte_position is not None:
171
169
  pos = encode_state.origin_byte_position + self.byte_position
@@ -189,7 +187,6 @@ class TableKeyParameter(Parameter):
189
187
  tmp_val = b'\x00' * ((n + 7) // 8)
190
188
  encode_state.emplace_bytes(tmp_val, obj_used_mask=tmp_val)
191
189
 
192
- encode_state.cursor_byte_position = max(orig_pos, encode_state.cursor_byte_position)
193
190
  encode_state.cursor_bit_position = 0
194
191
 
195
192
  def encode_value_into_pdu(self, encode_state: EncodeState) -> None:
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
3
+ from typing import Any, Dict, List, Optional, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -10,13 +10,11 @@ from ..encodestate import EncodeState
10
10
  from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
11
11
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
12
12
  from ..odxtypes import ParameterValue
13
+ from ..snrefcontext import SnRefContext
13
14
  from ..utils import dataclass_fields_asdict
14
15
  from .parameter import Parameter, ParameterType
15
16
  from .tablekeyparameter import TableKeyParameter
16
17
 
17
- if TYPE_CHECKING:
18
- from ..diaglayer import DiagLayer
19
-
20
18
 
21
19
  @dataclass
22
20
  class TableStructParameter(Parameter):
@@ -60,12 +58,12 @@ class TableStructParameter(Parameter):
60
58
  self._table_key = odxlinks.resolve(self.table_key_ref, TableKeyParameter)
61
59
 
62
60
  @override
63
- def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
64
- param_list: List[Parameter]) -> None:
65
- super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
61
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
62
+ super()._resolve_snrefs(context)
66
63
 
67
64
  if self.table_key_snref is not None:
68
- self._table_key = resolve_snref(self.table_key_snref, param_list, TableKeyParameter)
65
+ self._table_key = resolve_snref(self.table_key_snref, odxrequire(context.parameters),
66
+ TableKeyParameter)
69
67
 
70
68
  @property
71
69
  def table_key(self) -> TableKeyParameter:
@@ -1,6 +1,6 @@
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 typing_extensions import override
@@ -10,13 +10,11 @@ from ..encodestate import EncodeState
10
10
  from ..exceptions import EncodeError, odxraise, odxrequire
11
11
  from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
12
12
  from ..odxtypes import AtomicOdxType, ParameterValue
13
+ from ..snrefcontext import SnRefContext
13
14
  from ..utils import dataclass_fields_asdict
14
- from .parameter import Parameter, ParameterType
15
+ from .parameter import ParameterType
15
16
  from .parameterwithdop import ParameterWithDOP
16
17
 
17
- if TYPE_CHECKING:
18
- from ..diaglayer import DiagLayer
19
-
20
18
 
21
19
  @dataclass
22
20
  class ValueParameter(ParameterWithDOP):
@@ -50,9 +48,8 @@ class ValueParameter(ParameterWithDOP):
50
48
  super()._resolve_odxlinks(odxlinks)
51
49
 
52
50
  @override
53
- def _parameter_resolve_snrefs(self, diag_layer: "DiagLayer", *,
54
- param_list: List[Parameter]) -> None:
55
- super()._parameter_resolve_snrefs(diag_layer, param_list=param_list)
51
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
52
+ super()._resolve_snrefs(context)
56
53
 
57
54
  if self.physical_default_value_raw is not None:
58
55
  dop = odxrequire(self.dop)
@@ -1,18 +1,20 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, cast
3
+ from typing import TYPE_CHECKING, Any, Dict, List, cast
4
+ from xml.etree import ElementTree
4
5
 
5
6
  from typing_extensions import override
6
7
 
7
8
  from .decodestate import DecodeState
8
9
  from .diagcodedtype import DctType, DiagCodedType
9
10
  from .encodestate import EncodeState
10
- from .exceptions import EncodeError, odxraise
11
- from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from .exceptions import EncodeError, odxraise, odxrequire
12
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
12
13
  from .odxtypes import AtomicOdxType, DataType
14
+ from .snrefcontext import SnRefContext
15
+ from .utils import dataclass_fields_asdict
13
16
 
14
17
  if TYPE_CHECKING:
15
- from .diaglayer import DiagLayer
16
18
  from .parameters.lengthkeyparameter import LengthKeyParameter
17
19
 
18
20
 
@@ -21,6 +23,17 @@ class ParamLengthInfoType(DiagCodedType):
21
23
 
22
24
  length_key_ref: OdxLinkRef
23
25
 
26
+ @staticmethod
27
+ @override
28
+ def from_et(et_element: ElementTree.Element,
29
+ doc_frags: List[OdxDocFragment]) -> "ParamLengthInfoType":
30
+ kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
31
+
32
+ length_key_ref = odxrequire(
33
+ OdxLinkRef.from_et(et_element.find("LENGTH-KEY-REF"), doc_frags))
34
+
35
+ return ParamLengthInfoType(length_key_ref=length_key_ref, **kwargs)
36
+
24
37
  @property
25
38
  def dct_type(self) -> DctType:
26
39
  return "PARAM-LENGTH-INFO-TYPE"
@@ -37,9 +50,9 @@ class ParamLengthInfoType(DiagCodedType):
37
50
  else:
38
51
  self._length_key = odxlinks.resolve(self.length_key_ref)
39
52
 
40
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
53
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
41
54
  """Recursively resolve any short-name references"""
42
- super()._resolve_snrefs(diag_layer)
55
+ super()._resolve_snrefs(context)
43
56
 
44
57
  @property
45
58
  def length_key(self) -> "LengthKeyParameter":
odxtools/parentref.py CHANGED
@@ -1,10 +1,13 @@
1
1
  # SPDX-License-Identifier: MIT
2
+ from copy import deepcopy
2
3
  from dataclasses import dataclass
3
4
  from typing import TYPE_CHECKING, Any, Dict, List
4
5
  from xml.etree import ElementTree
5
6
 
6
7
  from .exceptions import odxrequire
7
8
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
+ from .snrefcontext import SnRefContext
10
+ from .utils import dataclass_fields_asdict
8
11
 
9
12
  if TYPE_CHECKING:
10
13
  from .diaglayer import DiagLayer
@@ -76,5 +79,16 @@ class ParentRef:
76
79
  else:
77
80
  self._layer = odxlinks.resolve(self.layer_ref)
78
81
 
79
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
82
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
80
83
  pass
84
+
85
+ def __deepcopy__(self, memo: Dict[int, Any]) -> Any:
86
+ cls = self.__class__
87
+ result = cls.__new__(cls)
88
+ memo[id(self)] = result
89
+
90
+ fields = dataclass_fields_asdict(self)
91
+ for name, value in fields.items():
92
+ setattr(result, name, deepcopy(value))
93
+
94
+ return result
@@ -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 IdentifiableElement
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 PhysicalDimension(IdentifiableElement):
@@ -89,5 +87,5 @@ class PhysicalDimension(IdentifiableElement):
89
87
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
90
88
  pass
91
89
 
92
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
90
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
93
91
  pass
odxtools/progcode.py CHANGED
@@ -1,13 +1,11 @@
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, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .exceptions import odxrequire
6
+ from .exceptions import odxraise, odxrequire
7
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
8
-
9
- if TYPE_CHECKING:
10
- from .diaglayer import DiagLayer
8
+ from .snrefcontext import SnRefContext
11
9
 
12
10
 
13
11
  @dataclass
@@ -20,6 +18,10 @@ class ProgCode:
20
18
  entrypoint: Optional[str]
21
19
  library_refs: List[OdxLinkRef]
22
20
 
21
+ @property
22
+ def code(self) -> bytes:
23
+ return self._code
24
+
23
25
  @staticmethod
24
26
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ProgCode":
25
27
  code_file = odxrequire(et_element.findtext("CODE-FILE"))
@@ -51,5 +53,14 @@ class ProgCode:
51
53
  # Once they are internalized, resolve the `library_refs` references here.
52
54
  pass
53
55
 
54
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
55
- pass
56
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
57
+ aux_file = odxrequire(context.database).auxiliary_files.get(self.code_file)
58
+
59
+ if aux_file is None:
60
+ odxraise(f"Reference to auxiliary file '{self.code_file}' "
61
+ f"could not be resolved")
62
+ self._code: bytes = cast(bytes, None)
63
+ return
64
+
65
+ self._code = aux_file.read()
66
+ aux_file.seek(0)
odxtools/protstack.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .comparamsubset import ComparamSubset
@@ -8,11 +8,9 @@ from .element import IdentifiableElement
8
8
  from .exceptions import odxrequire
9
9
  from .nameditemlist import NamedItemList
10
10
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from .snrefcontext import SnRefContext
11
12
  from .utils import dataclass_fields_asdict
12
13
 
13
- if TYPE_CHECKING:
14
- from .diaglayer import DiagLayer
15
-
16
14
 
17
15
  @dataclass
18
16
  class ProtStack(IdentifiableElement):
@@ -47,7 +45,7 @@ class ProtStack(IdentifiableElement):
47
45
  self._comparam_subsets = NamedItemList[ComparamSubset](
48
46
  [odxlinks.resolve(x, ComparamSubset) for x in self.comparam_subset_refs])
49
47
 
50
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
48
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
51
49
  pass
52
50
 
53
51
  @property
odxtools/py.typed ADDED
File without changes
odxtools/relateddoc.py CHANGED
@@ -1,24 +1,22 @@
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
+ from .description import Description
6
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
7
- from .utils import create_description_from_et
8
+ from .snrefcontext import SnRefContext
8
9
  from .xdoc import XDoc
9
10
 
10
- if TYPE_CHECKING:
11
- from .diaglayer import DiagLayer
12
-
13
11
 
14
12
  @dataclass
15
13
  class RelatedDoc:
16
- description: Optional[str]
14
+ description: Optional[Description]
17
15
  xdoc: Optional[XDoc]
18
16
 
19
17
  @staticmethod
20
18
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "RelatedDoc":
21
- description = create_description_from_et(et_element.find("DESC"))
19
+ description = Description.from_et(et_element.find("DESC"), doc_frags)
22
20
 
23
21
  xdoc: Optional[XDoc] = None
24
22
  if (xdoc_elem := et_element.find("XDOC")) is not None:
@@ -41,6 +39,6 @@ class RelatedDoc:
41
39
  if self.xdoc:
42
40
  self.xdoc._resolve_odxlinks(odxlinks)
43
41
 
44
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
42
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
45
43
  if self.xdoc:
46
- self.xdoc._resolve_snrefs(diag_layer)
44
+ self.xdoc._resolve_snrefs(context)
odxtools/request.py CHANGED
@@ -7,6 +7,7 @@ from .basicstructure import BasicStructure
7
7
  from .encodestate import EncodeState
8
8
  from .odxlink import OdxDocFragment
9
9
  from .odxtypes import ParameterValue
10
+ from .snrefcontext import SnRefContext
10
11
  from .utils import dataclass_fields_asdict
11
12
 
12
13
 
@@ -29,3 +30,10 @@ class Request(BasicStructure):
29
30
  self.encode_into_pdu(physical_value=kwargs, encode_state=encode_state)
30
31
 
31
32
  return encode_state.coded_message
33
+
34
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
35
+ context.request = self
36
+
37
+ super()._resolve_snrefs(context)
38
+
39
+ context.request = None
odxtools/response.py CHANGED
@@ -9,6 +9,7 @@ from .encodestate import EncodeState
9
9
  from .exceptions import odxraise
10
10
  from .odxlink import OdxDocFragment
11
11
  from .odxtypes import ParameterValue
12
+ from .snrefcontext import SnRefContext
12
13
  from .utils import dataclass_fields_asdict
13
14
 
14
15
 
@@ -44,3 +45,10 @@ class Response(BasicStructure):
44
45
  self.encode_into_pdu(physical_value=kwargs, encode_state=encode_state)
45
46
 
46
47
  return encode_state.coded_message
48
+
49
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
50
+ context.response = self
51
+
52
+ super()._resolve_snrefs(context)
53
+
54
+ context.response = None
odxtools/scaleconstr.py CHANGED
@@ -5,10 +5,10 @@ from typing import List, Optional
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .compumethods.limit import Limit
8
+ from .description import Description
8
9
  from .exceptions import odxraise, odxrequire
9
10
  from .odxlink import OdxDocFragment
10
11
  from .odxtypes import DataType
11
- from .utils import create_description_from_et
12
12
 
13
13
 
14
14
  class ValidType(Enum):
@@ -24,7 +24,7 @@ class ScaleConstr:
24
24
  """
25
25
 
26
26
  short_label: Optional[str]
27
- description: Optional[str]
27
+ description: Optional[Description]
28
28
  lower_limit: Optional[Limit]
29
29
  upper_limit: Optional[Limit]
30
30
  validity: ValidType
@@ -34,7 +34,7 @@ class ScaleConstr:
34
34
  def scale_constr_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
35
35
  value_type: DataType) -> "ScaleConstr":
36
36
  short_label = et_element.findtext("SHORT-LABEL")
37
- description = create_description_from_et(et_element.find("DESC"))
37
+ description = Description.from_et(et_element.find("DESC"), doc_frags)
38
38
 
39
39
  lower_limit = Limit.limit_from_et(
40
40
  et_element.find("LOWER-LIMIT"), doc_frags, value_type=value_type)
odxtools/singleecujob.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .diagcomm import DiagComm
@@ -10,11 +10,9 @@ from .negoutputparam import NegOutputParam
10
10
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
11
11
  from .outputparam import OutputParam
12
12
  from .progcode import ProgCode
13
+ from .snrefcontext import SnRefContext
13
14
  from .utils import dataclass_fields_asdict
14
15
 
15
- if TYPE_CHECKING:
16
- from .diaglayer import DiagLayer
17
-
18
16
 
19
17
  @dataclass
20
18
  class SingleEcuJob(DiagComm):
@@ -88,14 +86,18 @@ class SingleEcuJob(DiagComm):
88
86
  for neg_output_param in self.neg_output_params:
89
87
  neg_output_param._resolve_odxlinks(odxlinks)
90
88
 
91
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
92
- super()._resolve_snrefs(diag_layer)
89
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
90
+ context.single_ecu_job = self
91
+
92
+ super()._resolve_snrefs(context)
93
93
 
94
94
  for prog_code in self.prog_codes:
95
- prog_code._resolve_snrefs(diag_layer)
95
+ prog_code._resolve_snrefs(context)
96
96
  for input_param in self.input_params:
97
- input_param._resolve_snrefs(diag_layer)
97
+ input_param._resolve_snrefs(context)
98
98
  for output_param in self.output_params:
99
- output_param._resolve_snrefs(diag_layer)
99
+ output_param._resolve_snrefs(context)
100
100
  for neg_output_param in self.neg_output_params:
101
- neg_output_param._resolve_snrefs(diag_layer)
101
+ neg_output_param._resolve_snrefs(context)
102
+
103
+ context.single_ecu_job = None