odxtools 7.1.1__py3-none-any.whl → 7.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.
- odxtools/__init__.py +6 -4
- odxtools/additionalaudience.py +3 -5
- odxtools/admindata.py +5 -7
- odxtools/audience.py +3 -5
- odxtools/basecomparam.py +3 -5
- odxtools/basicstructure.py +19 -23
- odxtools/cli/_parser_utils.py +1 -1
- odxtools/cli/_print_utils.py +3 -2
- odxtools/cli/compare.py +1 -1
- odxtools/companydata.py +5 -7
- odxtools/companydocinfo.py +7 -8
- odxtools/companyrevisioninfo.py +3 -5
- odxtools/companyspecificinfo.py +8 -9
- odxtools/comparam.py +4 -6
- odxtools/comparaminstance.py +6 -8
- odxtools/comparamspec.py +14 -13
- odxtools/comparamsubset.py +17 -16
- odxtools/complexcomparam.py +5 -7
- odxtools/compumethods/compuconst.py +31 -0
- odxtools/compumethods/compudefaultvalue.py +27 -0
- odxtools/compumethods/compuinternaltophys.py +39 -0
- odxtools/compumethods/compuinversevalue.py +7 -0
- odxtools/compumethods/compumethod.py +67 -12
- odxtools/compumethods/compuphystointernal.py +39 -0
- odxtools/compumethods/compuscale.py +15 -26
- odxtools/compumethods/createanycompumethod.py +14 -160
- odxtools/compumethods/identicalcompumethod.py +31 -6
- odxtools/compumethods/linearcompumethod.py +69 -189
- odxtools/compumethods/linearsegment.py +191 -0
- odxtools/compumethods/scalelinearcompumethod.py +132 -26
- odxtools/compumethods/tabintpcompumethod.py +119 -99
- odxtools/compumethods/texttablecompumethod.py +107 -43
- odxtools/createanydiagcodedtype.py +10 -67
- odxtools/database.py +84 -72
- odxtools/dataobjectproperty.py +10 -19
- odxtools/decodestate.py +8 -2
- odxtools/description.py +47 -0
- odxtools/determinenumberofitems.py +4 -5
- odxtools/diagcodedtype.py +29 -12
- odxtools/diagcomm.py +10 -6
- odxtools/diagdatadictionaryspec.py +20 -21
- odxtools/diaglayer.py +39 -9
- odxtools/diaglayercontainer.py +17 -11
- odxtools/diaglayerraw.py +20 -21
- odxtools/diagnostictroublecode.py +8 -9
- odxtools/diagservice.py +42 -27
- odxtools/docrevision.py +5 -7
- odxtools/dopbase.py +7 -8
- odxtools/dtcdop.py +44 -22
- odxtools/dynamicendmarkerfield.py +22 -9
- odxtools/dynamiclengthfield.py +5 -11
- odxtools/element.py +4 -3
- odxtools/encodestate.py +14 -2
- odxtools/endofpdufield.py +0 -2
- odxtools/environmentdatadescription.py +137 -19
- odxtools/exceptions.py +11 -2
- odxtools/field.py +9 -9
- odxtools/functionalclass.py +3 -5
- odxtools/inputparam.py +3 -5
- odxtools/leadinglengthinfotype.py +15 -2
- odxtools/loadfile.py +64 -0
- odxtools/minmaxlengthtype.py +20 -2
- odxtools/modification.py +3 -5
- odxtools/multiplexer.py +98 -69
- odxtools/multiplexercase.py +10 -11
- odxtools/multiplexerdefaultcase.py +11 -12
- odxtools/multiplexerswitchkey.py +4 -5
- odxtools/negoutputparam.py +3 -5
- odxtools/odxlink.py +12 -26
- odxtools/odxtypes.py +1 -1
- odxtools/outputparam.py +3 -5
- odxtools/parameterinfo.py +5 -5
- odxtools/parameters/codedconstparameter.py +2 -14
- odxtools/parameters/lengthkeyparameter.py +3 -17
- odxtools/parameters/nrcconstparameter.py +29 -50
- odxtools/parameters/parameter.py +22 -22
- odxtools/parameters/parameterwithdop.py +6 -8
- odxtools/parameters/physicalconstantparameter.py +5 -8
- odxtools/parameters/reservedparameter.py +4 -3
- odxtools/parameters/systemparameter.py +1 -1
- odxtools/parameters/tablekeyparameter.py +6 -9
- odxtools/parameters/tablestructparameter.py +6 -8
- odxtools/parameters/valueparameter.py +5 -8
- odxtools/paramlengthinfotype.py +19 -6
- odxtools/parentref.py +15 -1
- odxtools/physicaldimension.py +3 -5
- odxtools/progcode.py +18 -7
- odxtools/protstack.py +3 -5
- odxtools/relateddoc.py +7 -9
- odxtools/request.py +8 -0
- odxtools/response.py +8 -0
- odxtools/scaleconstr.py +3 -3
- odxtools/singleecujob.py +12 -10
- odxtools/snrefcontext.py +29 -0
- odxtools/specialdata.py +3 -5
- odxtools/specialdatagroup.py +5 -7
- odxtools/specialdatagroupcaption.py +3 -6
- odxtools/standardlengthtype.py +27 -2
- odxtools/state.py +3 -5
- odxtools/statechart.py +9 -11
- odxtools/statetransition.py +4 -9
- odxtools/staticfield.py +4 -8
- odxtools/table.py +7 -8
- odxtools/tablerow.py +7 -6
- odxtools/teammember.py +3 -5
- odxtools/templates/comparam-spec.odx-c.xml.jinja2 +2 -5
- odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +2 -5
- odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -5
- odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
- odxtools/templates/macros/printCompuMethod.xml.jinja2 +153 -0
- odxtools/templates/macros/printDOP.xml.jinja2 +10 -132
- odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
- odxtools/templates/macros/printElementId.xml.jinja2 +3 -3
- odxtools/templates/macros/printMux.xml.jinja2 +3 -2
- odxtools/templates/macros/printTable.xml.jinja2 +2 -3
- odxtools/unit.py +3 -5
- odxtools/unitgroup.py +3 -5
- odxtools/unitspec.py +9 -10
- odxtools/utils.py +1 -26
- odxtools/version.py +2 -2
- odxtools/{write_pdx_file.py → writepdxfile.py} +19 -10
- odxtools/xdoc.py +3 -5
- {odxtools-7.1.1.dist-info → odxtools-7.3.0.dist-info}/METADATA +1 -1
- odxtools-7.3.0.dist-info/RECORD +192 -0
- {odxtools-7.1.1.dist-info → odxtools-7.3.0.dist-info}/WHEEL +1 -1
- odxtools/createcompanydatas.py +0 -17
- odxtools/createsdgs.py +0 -19
- odxtools/load_file.py +0 -13
- odxtools/load_odx_d_file.py +0 -6
- odxtools/load_pdx_file.py +0 -8
- odxtools-7.1.1.dist-info/RECORD +0 -186
- /odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +0 -0
- {odxtools-7.1.1.dist-info → odxtools-7.3.0.dist-info}/LICENSE +0 -0
- {odxtools-7.1.1.dist-info → odxtools-7.3.0.dist-info}/entry_points.txt +0 -0
- {odxtools-7.1.1.dist-info → odxtools-7.3.0.dist-info}/top_level.txt +0 -0
odxtools/minmaxlengthtype.py
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Optional
|
3
|
+
from typing import List, Optional
|
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 DecodeError, EncodeError, odxassert, odxraise
|
11
|
+
from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
12
|
+
from .odxlink import OdxDocFragment
|
11
13
|
from .odxtypes import AtomicOdxType, DataType
|
14
|
+
from .utils import dataclass_fields_asdict
|
12
15
|
|
13
16
|
|
14
17
|
@dataclass
|
@@ -17,6 +20,21 @@ class MinMaxLengthType(DiagCodedType):
|
|
17
20
|
max_length: Optional[int]
|
18
21
|
termination: str
|
19
22
|
|
23
|
+
@staticmethod
|
24
|
+
@override
|
25
|
+
def from_et(et_element: ElementTree.Element,
|
26
|
+
doc_frags: List[OdxDocFragment]) -> "MinMaxLengthType":
|
27
|
+
kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
|
28
|
+
|
29
|
+
min_length = int(odxrequire(et_element.findtext("MIN-LENGTH")))
|
30
|
+
max_length = None
|
31
|
+
if et_element.find("MAX-LENGTH") is not None:
|
32
|
+
max_length = int(odxrequire(et_element.findtext("MAX-LENGTH")))
|
33
|
+
termination = odxrequire(et_element.get("TERMINATION"))
|
34
|
+
|
35
|
+
return MinMaxLengthType(
|
36
|
+
min_length=min_length, max_length=max_length, termination=termination, **kwargs)
|
37
|
+
|
20
38
|
def __post_init__(self) -> None:
|
21
39
|
odxassert(self.max_length is None or self.min_length <= self.max_length)
|
22
40
|
odxassert(
|
odxtools/modification.py
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
7
|
-
|
8
|
-
if TYPE_CHECKING:
|
9
|
-
from .diaglayer import DiagLayer
|
7
|
+
from .snrefcontext import SnRefContext
|
10
8
|
|
11
9
|
|
12
10
|
@dataclass
|
@@ -27,5 +25,5 @@ class Modification:
|
|
27
25
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
28
26
|
pass
|
29
27
|
|
30
|
-
def _resolve_snrefs(self,
|
28
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
31
29
|
pass
|
odxtools/multiplexer.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional, Tuple, Union, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -8,17 +8,15 @@ from typing_extensions import override
|
|
8
8
|
from .complexdop import ComplexDop
|
9
9
|
from .decodestate import DecodeState
|
10
10
|
from .encodestate import EncodeState
|
11
|
-
from .exceptions import DecodeError, EncodeError, odxraise, odxrequire
|
11
|
+
from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
12
12
|
from .multiplexercase import MultiplexerCase
|
13
13
|
from .multiplexerdefaultcase import MultiplexerDefaultCase
|
14
14
|
from .multiplexerswitchkey import MultiplexerSwitchKey
|
15
15
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
16
16
|
from .odxtypes import AtomicOdxType, ParameterValue, odxstr_to_bool
|
17
|
+
from .snrefcontext import SnRefContext
|
17
18
|
from .utils import dataclass_fields_asdict
|
18
19
|
|
19
|
-
if TYPE_CHECKING:
|
20
|
-
from .diaglayer import DiagLayer
|
21
|
-
|
22
20
|
|
23
21
|
@dataclass
|
24
22
|
class Multiplexer(ComplexDop):
|
@@ -81,92 +79,123 @@ class Multiplexer(ComplexDop):
|
|
81
79
|
def encode_into_pdu(self, physical_value: ParameterValue, encode_state: EncodeState) -> None:
|
82
80
|
|
83
81
|
if encode_state.cursor_bit_position != 0:
|
84
|
-
raise EncodeError(f"Multiplexer must be aligned, i.e. bit_position=0, but "
|
82
|
+
raise EncodeError(f"Multiplexer parameters must be aligned, i.e. bit_position=0, but "
|
85
83
|
f"{self.short_name} was passed the bit position "
|
86
84
|
f"{encode_state.cursor_bit_position}")
|
87
85
|
|
88
|
-
if not isinstance(physical_value, dict) or len(physical_value) != 1:
|
89
|
-
raise EncodeError("""Multiplexer should be defined as a dict
|
90
|
-
with only one key equal to the desired case""")
|
91
|
-
|
92
86
|
orig_origin = encode_state.origin_byte_position
|
93
|
-
orig_cursor = encode_state.cursor_byte_position
|
94
|
-
|
95
87
|
encode_state.origin_byte_position = encode_state.cursor_byte_position
|
96
88
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
89
|
+
if isinstance(physical_value, (list, tuple)) and len(physical_value) == 2:
|
90
|
+
case_spec, case_value = physical_value
|
91
|
+
elif isinstance(physical_value, dict) and len(physical_value) == 1:
|
92
|
+
case_spec, case_value = next(iter(physical_value.items()))
|
93
|
+
else:
|
94
|
+
raise EncodeError(
|
95
|
+
f"Values of multiplexer parameters must be defined as a "
|
96
|
+
f"(case_name, content_value) tuple instead of as '{physical_value!r}'")
|
97
|
+
|
98
|
+
mux_case: Union[MultiplexerCase, MultiplexerDefaultCase]
|
99
|
+
if isinstance(case_spec, str):
|
100
|
+
applicable_cases = [x for x in self.cases if x.short_name == case_spec]
|
101
|
+
if len(applicable_cases) == 0:
|
102
|
+
raise EncodeError(
|
103
|
+
f"Multiplexer {self.short_name} does not know any case called {case_spec}")
|
104
|
+
|
105
|
+
odxassert(len(applicable_cases) == 1)
|
106
|
+
mux_case = applicable_cases[0]
|
107
|
+
key_value, _ = self._get_case_limits(mux_case)
|
108
|
+
elif isinstance(case_spec, int):
|
109
|
+
applicable_cases = []
|
110
|
+
for x in self.cases:
|
111
|
+
lower, upper = cast(Tuple[int, int], self._get_case_limits(x))
|
112
|
+
if lower <= case_spec and case_spec <= upper:
|
113
|
+
applicable_cases.append(x)
|
114
|
+
|
115
|
+
if len(applicable_cases) == 0:
|
116
|
+
if self.default_case is None:
|
117
|
+
raise EncodeError(
|
118
|
+
f"Multiplexer {self.short_name} does not know any case called {case_spec}")
|
119
|
+
mux_case = self.default_case
|
120
|
+
key_value = case_spec
|
121
|
+
else:
|
122
|
+
mux_case = applicable_cases[0]
|
123
|
+
key_value = case_spec
|
124
|
+
elif isinstance(case_spec, MultiplexerCase):
|
125
|
+
mux_case = case_spec
|
126
|
+
key_value, _ = self._get_case_limits(mux_case)
|
127
|
+
elif case_spec is None:
|
128
|
+
if self.default_case is None:
|
129
|
+
raise EncodeError(f"Multiplexer {self.short_name} does not define a default case")
|
130
|
+
key_value = 0
|
131
|
+
else:
|
132
|
+
raise EncodeError(f"Illegal case specification '{case_spec}' for "
|
133
|
+
f"multiplexer {self.short_name}")
|
134
|
+
|
135
|
+
# the byte position of the switch key is relative to
|
136
|
+
# the multiplexer's position
|
137
|
+
encode_state.cursor_byte_position = encode_state.origin_byte_position + self.switch_key.byte_position
|
138
|
+
encode_state.cursor_bit_position = self.switch_key.bit_position or 0
|
139
|
+
self.switch_key.dop.encode_into_pdu(physical_value=key_value, encode_state=encode_state)
|
140
|
+
encode_state.cursor_bit_position = 0
|
141
|
+
|
142
|
+
if mux_case.structure is not None:
|
143
|
+
# the byte position of the content is specified by the
|
144
|
+
# BYTE-POSITION attribute of the multiplexer
|
145
|
+
encode_state.cursor_byte_position = encode_state.origin_byte_position + self.byte_position
|
146
|
+
mux_case.structure.encode_into_pdu(physical_value=case_value, encode_state=encode_state)
|
147
|
+
|
148
|
+
encode_state.origin_byte_position = orig_origin
|
128
149
|
|
129
150
|
@override
|
130
151
|
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
131
|
-
|
132
|
-
# multiplexers are structures and thus the origin position
|
133
|
-
# must be moved to the start of the multiplexer
|
134
152
|
orig_origin = decode_state.origin_byte_position
|
135
|
-
orig_cursor = decode_state.cursor_byte_position
|
136
|
-
if self.byte_position is not None:
|
137
|
-
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
|
138
153
|
decode_state.origin_byte_position = decode_state.cursor_byte_position
|
139
154
|
|
155
|
+
# Decode the switch key. Its BYTE-POSITION is relative to the
|
156
|
+
# that of the multiplexer.
|
157
|
+
if self.switch_key.byte_position is not None:
|
158
|
+
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.switch_key.byte_position
|
159
|
+
decode_state.cursor_bit_position = self.switch_key.bit_position or 0
|
140
160
|
key_value = self.switch_key.dop.decode_from_pdu(decode_state)
|
161
|
+
decode_state.cursor_bit_position = 0
|
141
162
|
|
142
163
|
if not isinstance(key_value, int):
|
143
164
|
odxraise(f"Multiplexer keys must be integers (is '{type(key_value).__name__}'"
|
144
165
|
f" for multiplexer '{self.short_name}')")
|
145
166
|
|
146
|
-
|
147
|
-
|
148
|
-
|
167
|
+
# "If a matching CASE is found, the referenced STRUCTURE is
|
168
|
+
# analyzed at the BYTE-POSITION (child element of MUX)
|
169
|
+
# relatively to the byte position of the MUX."
|
170
|
+
decode_state.cursor_byte_position = decode_state.origin_byte_position + self.byte_position
|
171
|
+
|
172
|
+
applicable_case: Optional[Union[MultiplexerCase, MultiplexerDefaultCase]] = None
|
173
|
+
for mux_case in self.cases:
|
149
174
|
lower, upper = self._get_case_limits(mux_case)
|
150
175
|
if lower <= key_value and key_value <= upper: # type: ignore[operator]
|
151
|
-
|
152
|
-
case_value = mux_case._structure.decode_from_pdu(decode_state)
|
176
|
+
applicable_case = mux_case
|
153
177
|
break
|
154
178
|
|
155
|
-
if
|
156
|
-
|
157
|
-
|
179
|
+
if applicable_case is None:
|
180
|
+
applicable_case = self.default_case
|
181
|
+
|
182
|
+
if applicable_case is None:
|
183
|
+
odxraise(
|
184
|
+
f"Cannot find an applicable case for value {key_value} in "
|
185
|
+
f"multiplexer {self.short_name}", DecodeError)
|
186
|
+
decode_state.origin_byte_position = orig_origin
|
187
|
+
return (None, None)
|
158
188
|
|
159
|
-
if
|
160
|
-
|
161
|
-
|
189
|
+
if applicable_case.structure is not None:
|
190
|
+
case_value = applicable_case.structure.decode_from_pdu(decode_state)
|
191
|
+
else:
|
192
|
+
case_value = {}
|
162
193
|
|
163
|
-
|
194
|
+
result = (applicable_case.short_name, case_value)
|
164
195
|
|
165
|
-
# go back to the original origin
|
166
196
|
decode_state.origin_byte_position = orig_origin
|
167
|
-
decode_state.cursor_byte_position = max(orig_cursor, decode_state.cursor_byte_position)
|
168
197
|
|
169
|
-
return
|
198
|
+
return result
|
170
199
|
|
171
200
|
@override
|
172
201
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
@@ -191,12 +220,12 @@ class Multiplexer(ComplexDop):
|
|
191
220
|
odxlinks, key_physical_type=self.switch_key.dop.physical_type.base_data_type)
|
192
221
|
|
193
222
|
@override
|
194
|
-
def _resolve_snrefs(self,
|
195
|
-
super()._resolve_snrefs(
|
223
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
224
|
+
super()._resolve_snrefs(context)
|
196
225
|
|
197
|
-
self.switch_key._resolve_snrefs(
|
226
|
+
self.switch_key._resolve_snrefs(context)
|
198
227
|
if self.default_case is not None:
|
199
|
-
self.default_case._resolve_snrefs(
|
228
|
+
self.default_case._resolve_snrefs(context)
|
200
229
|
|
201
230
|
for mux_case in self.cases:
|
202
|
-
mux_case._resolve_snrefs(
|
231
|
+
mux_case._resolve_snrefs(context)
|
odxtools/multiplexercase.py
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from .basicstructure import BasicStructure
|
7
6
|
from .compumethods.limit import Limit
|
8
7
|
from .element import NamedElement
|
9
8
|
from .exceptions import odxrequire
|
10
9
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
11
10
|
from .odxtypes import AtomicOdxType, DataType
|
11
|
+
from .snrefcontext import SnRefContext
|
12
|
+
from .structure import Structure
|
12
13
|
from .utils import dataclass_fields_asdict
|
13
14
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from .diaglayer import DiagLayer
|
16
|
-
|
17
15
|
|
18
16
|
@dataclass
|
19
17
|
class MultiplexerCase(NamedElement):
|
@@ -25,7 +23,7 @@ class MultiplexerCase(NamedElement):
|
|
25
23
|
upper_limit: Limit
|
26
24
|
|
27
25
|
def __post_init__(self) -> None:
|
28
|
-
self._structure:
|
26
|
+
self._structure: Optional[Structure]
|
29
27
|
|
30
28
|
@staticmethod
|
31
29
|
def from_et(et_element: ElementTree.Element,
|
@@ -64,21 +62,22 @@ class MultiplexerCase(NamedElement):
|
|
64
62
|
|
65
63
|
def _mux_case_resolve_odxlinks(self, odxlinks: OdxLinkDatabase, *,
|
66
64
|
key_physical_type: DataType) -> None:
|
65
|
+
self._structure = None
|
67
66
|
if self.structure_ref:
|
68
|
-
self._structure = odxlinks.resolve(self.structure_ref)
|
67
|
+
self._structure = odxlinks.resolve(self.structure_ref, Structure)
|
69
68
|
|
70
69
|
self.lower_limit.set_value_type(key_physical_type)
|
71
70
|
self.upper_limit.set_value_type(key_physical_type)
|
72
71
|
|
73
|
-
def _resolve_snrefs(self,
|
72
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
74
73
|
if self.structure_snref:
|
75
|
-
ddds = diag_layer.diag_data_dictionary_spec
|
76
|
-
self._structure = resolve_snref(self.structure_snref, ddds.structures,
|
74
|
+
ddds = odxrequire(context.diag_layer).diag_data_dictionary_spec
|
75
|
+
self._structure = resolve_snref(self.structure_snref, ddds.structures, Structure)
|
77
76
|
|
78
77
|
def applies(self, value: AtomicOdxType) -> bool:
|
79
78
|
return self.lower_limit.complies_to_lower(value) \
|
80
79
|
and self.upper_limit.complies_to_upper(value)
|
81
80
|
|
82
81
|
@property
|
83
|
-
def structure(self) ->
|
82
|
+
def structure(self) -> Optional[Structure]:
|
84
83
|
return self._structure
|
@@ -1,17 +1,15 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from .basicstructure import BasicStructure
|
7
6
|
from .element import NamedElement
|
8
7
|
from .exceptions import odxrequire
|
9
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
9
|
+
from .snrefcontext import SnRefContext
|
10
|
+
from .structure import Structure
|
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 MultiplexerDefaultCase(NamedElement):
|
@@ -20,12 +18,12 @@ class MultiplexerDefaultCase(NamedElement):
|
|
20
18
|
structure_snref: Optional[str]
|
21
19
|
|
22
20
|
def __post_init__(self) -> None:
|
23
|
-
self._structure:
|
21
|
+
self._structure: Optional[Structure]
|
24
22
|
|
25
23
|
@staticmethod
|
26
24
|
def from_et(et_element: ElementTree.Element,
|
27
25
|
doc_frags: List[OdxDocFragment]) -> "MultiplexerDefaultCase":
|
28
|
-
"""Reads a
|
26
|
+
"""Reads a default case for a multiplexer."""
|
29
27
|
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
|
30
28
|
|
31
29
|
structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), doc_frags)
|
@@ -40,14 +38,15 @@ class MultiplexerDefaultCase(NamedElement):
|
|
40
38
|
return {}
|
41
39
|
|
42
40
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
41
|
+
self._structure = None
|
43
42
|
if self.structure_ref is not None:
|
44
|
-
self._structure = odxlinks.resolve(self.structure_ref)
|
43
|
+
self._structure = odxlinks.resolve(self.structure_ref, Structure)
|
45
44
|
|
46
|
-
def _resolve_snrefs(self,
|
45
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
47
46
|
if self.structure_snref:
|
48
|
-
ddds = diag_layer.diag_data_dictionary_spec
|
49
|
-
self._structure = resolve_snref(self.structure_snref, ddds.structures,
|
47
|
+
ddds = odxrequire(context.diag_layer).diag_data_dictionary_spec
|
48
|
+
self._structure = resolve_snref(self.structure_snref, ddds.structures, Structure)
|
50
49
|
|
51
50
|
@property
|
52
|
-
def structure(self) ->
|
51
|
+
def structure(self) -> Optional[Structure]:
|
53
52
|
return self._structure
|
odxtools/multiplexerswitchkey.py
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
1
2
|
from dataclasses import dataclass
|
2
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
3
4
|
from xml.etree import ElementTree
|
4
5
|
|
5
6
|
from .dataobjectproperty import DataObjectProperty
|
6
7
|
from .exceptions import odxrequire
|
7
8
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
8
|
-
|
9
|
-
if TYPE_CHECKING:
|
10
|
-
from .diaglayer import DiagLayer
|
9
|
+
from .snrefcontext import SnRefContext
|
11
10
|
|
12
11
|
|
13
12
|
@dataclass
|
@@ -39,7 +38,7 @@ class MultiplexerSwitchKey:
|
|
39
38
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
40
39
|
self._dop = odxlinks.resolve(self.dop_ref, DataObjectProperty)
|
41
40
|
|
42
|
-
def _resolve_snrefs(self,
|
41
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
43
42
|
pass
|
44
43
|
|
45
44
|
@property
|
odxtools/negoutputparam.py
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .dopbase import DopBase
|
7
7
|
from .element import NamedElement
|
8
8
|
from .exceptions import odxrequire
|
9
9
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
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 NegOutputParam(NamedElement):
|
@@ -35,7 +33,7 @@ class NegOutputParam(NamedElement):
|
|
35
33
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
36
34
|
self._dop = odxlinks.resolve(self.dop_base_ref)
|
37
35
|
|
38
|
-
def _resolve_snrefs(self,
|
36
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
39
37
|
pass
|
40
38
|
|
41
39
|
@property
|
odxtools/odxlink.py
CHANGED
@@ -26,7 +26,6 @@ class OdxDocFragment:
|
|
26
26
|
return self.doc_name == other.doc_name
|
27
27
|
|
28
28
|
def __hash__(self) -> int:
|
29
|
-
# only the document name is relevant for the hash value
|
30
29
|
return hash(self.doc_name) + hash(self.doc_type)
|
31
30
|
|
32
31
|
|
@@ -59,10 +58,12 @@ class OdxLinkId:
|
|
59
58
|
if not isinstance(other, OdxLinkId):
|
60
59
|
return False
|
61
60
|
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
# if the local ID is different, the whole id is different
|
62
|
+
if self.local_id != other.local_id:
|
63
|
+
return False
|
64
|
+
|
65
|
+
# the document fragments must be identical for the IDs to be identical
|
66
|
+
return self.doc_fragments == other.doc_fragments
|
66
67
|
|
67
68
|
def __str__(self) -> str:
|
68
69
|
return f"OdxLinkId('{self.local_id}')"
|
@@ -147,19 +148,6 @@ class OdxLinkRef:
|
|
147
148
|
def __str__(self) -> str:
|
148
149
|
return f"OdxLinkRef('{self.ref_id}')"
|
149
150
|
|
150
|
-
def __contains__(self, odx_id: OdxLinkId) -> bool:
|
151
|
-
"""
|
152
|
-
Returns true iff a given OdxLinkId object is referenced.
|
153
|
-
"""
|
154
|
-
|
155
|
-
# we must reference at to at least of the ID's document
|
156
|
-
# fragments
|
157
|
-
if not any(ref_doc in odx_id.doc_fragments for ref_doc in self.ref_docs):
|
158
|
-
return False
|
159
|
-
|
160
|
-
# the local ID of the reference and the object ID must match
|
161
|
-
return odx_id.local_id == self.ref_id
|
162
|
-
|
163
151
|
|
164
152
|
T = TypeVar("T")
|
165
153
|
|
@@ -172,7 +160,7 @@ class OdxLinkDatabase:
|
|
172
160
|
"""
|
173
161
|
|
174
162
|
def __init__(self) -> None:
|
175
|
-
self._db: Dict[OdxDocFragment, Dict[
|
163
|
+
self._db: Dict[OdxDocFragment, Dict[str, Any]] = {}
|
176
164
|
|
177
165
|
@overload
|
178
166
|
def resolve(self, ref: OdxLinkRef, expected_type: None = None) -> Any:
|
@@ -189,7 +177,6 @@ class OdxLinkDatabase:
|
|
189
177
|
If the database does not contain any object which is referred to, a
|
190
178
|
KeyError exception is raised.
|
191
179
|
"""
|
192
|
-
odx_id = OdxLinkId(ref.ref_id, ref.ref_docs)
|
193
180
|
for ref_frag in reversed(ref.ref_docs):
|
194
181
|
doc_frag_db = self._db.get(ref_frag)
|
195
182
|
if doc_frag_db is None:
|
@@ -204,8 +191,9 @@ class OdxLinkDatabase:
|
|
204
191
|
)
|
205
192
|
continue
|
206
193
|
|
207
|
-
|
208
|
-
|
194
|
+
# locate an object exhibiting with the referenced local ID
|
195
|
+
# in the ID database for the document fragment
|
196
|
+
if (obj := doc_frag_db.get(ref.ref_id)) is not None:
|
209
197
|
if expected_type is not None:
|
210
198
|
odxassert(isinstance(obj, expected_type))
|
211
199
|
|
@@ -234,7 +222,6 @@ class OdxLinkDatabase:
|
|
234
222
|
is returned.
|
235
223
|
"""
|
236
224
|
|
237
|
-
odx_id = OdxLinkId(ref.ref_id, ref.ref_docs)
|
238
225
|
for ref_frag in reversed(ref.ref_docs):
|
239
226
|
doc_frag_db = self._db.get(ref_frag)
|
240
227
|
if doc_frag_db is None:
|
@@ -249,8 +236,7 @@ class OdxLinkDatabase:
|
|
249
236
|
)
|
250
237
|
continue
|
251
238
|
|
252
|
-
obj
|
253
|
-
if obj is not None:
|
239
|
+
if (obj := doc_frag_db.get(ref.ref_id)) is not None:
|
254
240
|
if expected_type is not None:
|
255
241
|
odxassert(isinstance(obj, expected_type))
|
256
242
|
|
@@ -272,7 +258,7 @@ class OdxLinkDatabase:
|
|
272
258
|
if doc_frag not in self._db:
|
273
259
|
self._db[doc_frag] = {}
|
274
260
|
|
275
|
-
self._db[doc_frag][odx_id] = obj
|
261
|
+
self._db[doc_frag][odx_id.local_id] = obj
|
276
262
|
|
277
263
|
|
278
264
|
@overload
|
odxtools/odxtypes.py
CHANGED
@@ -235,7 +235,7 @@ class DataType(Enum):
|
|
235
235
|
expected_type = self.python_type
|
236
236
|
if isinstance(value, expected_type):
|
237
237
|
return True
|
238
|
-
elif expected_type
|
238
|
+
elif expected_type is float and isinstance(value, (int, float)):
|
239
239
|
return True
|
240
240
|
elif self == DataType.A_BYTEFIELD and isinstance(value, (bytearray, bytes)):
|
241
241
|
return True
|
odxtools/outputparam.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import
|
3
|
+
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from deprecation import deprecated
|
@@ -9,11 +9,9 @@ from .dopbase import DopBase
|
|
9
9
|
from .element import IdentifiableElement
|
10
10
|
from .exceptions import odxrequire
|
11
11
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
12
|
+
from .snrefcontext import SnRefContext
|
12
13
|
from .utils import dataclass_fields_asdict
|
13
14
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from .diaglayer import DiagLayer
|
16
|
-
|
17
15
|
|
18
16
|
@dataclass
|
19
17
|
class OutputParam(IdentifiableElement):
|
@@ -37,7 +35,7 @@ class OutputParam(IdentifiableElement):
|
|
37
35
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
38
36
|
self._dop_base = odxlinks.resolve(self.dop_base_ref, DopBase)
|
39
37
|
|
40
|
-
def _resolve_snrefs(self,
|
38
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
41
39
|
pass
|
42
40
|
|
43
41
|
@property
|
odxtools/parameterinfo.py
CHANGED
@@ -108,8 +108,8 @@ def parameter_info(param_list: Iterable[Parameter], quoted_names: bool = False)
|
|
108
108
|
of.write(f"multiplexer; choices:\n")
|
109
109
|
for mux_case in dop.cases:
|
110
110
|
of.write(f" ({repr(mux_case.short_name)}, {{\n")
|
111
|
-
|
112
|
-
textwrap.indent(parameter_info(
|
111
|
+
if (struc := mux_case.structure) is not None:
|
112
|
+
of.write(textwrap.indent(parameter_info(struc.parameters, True), " "))
|
113
113
|
of.write(f" }})\n")
|
114
114
|
continue
|
115
115
|
|
@@ -128,7 +128,7 @@ def parameter_info(param_list: Iterable[Parameter], quoted_names: bool = False)
|
|
128
128
|
|
129
129
|
if isinstance(cm, TexttableCompuMethod):
|
130
130
|
of.write(f": enum; choices:\n")
|
131
|
-
for scale in cm.
|
131
|
+
for scale in odxrequire(cm.compu_internal_to_phys).compu_scales:
|
132
132
|
val_str = ""
|
133
133
|
if scale.lower_limit is not None:
|
134
134
|
val_str = f"({repr(scale.lower_limit.value)})"
|
@@ -166,8 +166,8 @@ def parameter_info(param_list: Iterable[Parameter], quoted_names: bool = False)
|
|
166
166
|
else:
|
167
167
|
of.write(f": <unknown type>")
|
168
168
|
|
169
|
-
ll = cm.physical_lower_limit
|
170
|
-
ul = cm.physical_upper_limit
|
169
|
+
ll = cm.segment.physical_lower_limit
|
170
|
+
ul = cm.segment.physical_upper_limit
|
171
171
|
if ll is None or ll.interval_type == IntervalType.INFINITE:
|
172
172
|
ll_str = "(-inf"
|
173
173
|
else:
|