odxtools 10.0.0__py3-none-any.whl → 10.1.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/additionalaudience.py +5 -5
- odxtools/admindata.py +10 -9
- odxtools/audience.py +15 -15
- odxtools/basecomparam.py +7 -6
- odxtools/basevariantpattern.py +7 -7
- odxtools/basicstructure.py +9 -9
- odxtools/cli/_print_utils.py +1 -1
- odxtools/cli/browse.py +1 -1
- odxtools/cli/list.py +1 -1
- odxtools/commrelation.py +14 -13
- odxtools/companydata.py +11 -11
- odxtools/companydocinfo.py +11 -13
- odxtools/companyrevisioninfo.py +7 -7
- odxtools/companyspecificinfo.py +9 -11
- odxtools/comparam.py +6 -5
- odxtools/comparaminstance.py +10 -10
- odxtools/comparamspec.py +8 -9
- odxtools/comparamsubset.py +14 -22
- odxtools/complexcomparam.py +10 -10
- odxtools/complexdop.py +1 -1
- odxtools/compositecodec.py +3 -3
- odxtools/compumethods/compucodecompumethod.py +4 -4
- odxtools/compumethods/compuconst.py +3 -3
- odxtools/compumethods/compudefaultvalue.py +2 -2
- odxtools/compumethods/compuinternaltophys.py +11 -10
- odxtools/compumethods/compumethod.py +8 -7
- odxtools/compumethods/compuphystointernal.py +11 -10
- odxtools/compumethods/compurationalcoeffs.py +6 -6
- odxtools/compumethods/compuscale.py +14 -14
- odxtools/compumethods/createanycompumethod.py +12 -12
- odxtools/compumethods/identicalcompumethod.py +4 -4
- odxtools/compumethods/limit.py +8 -8
- odxtools/compumethods/linearcompumethod.py +4 -4
- odxtools/compumethods/linearsegment.py +8 -8
- odxtools/compumethods/ratfunccompumethod.py +4 -4
- odxtools/compumethods/ratfuncsegment.py +8 -8
- odxtools/compumethods/scalelinearcompumethod.py +5 -5
- odxtools/compumethods/scaleratfunccompumethod.py +4 -4
- odxtools/compumethods/tabintpcompumethod.py +12 -12
- odxtools/compumethods/texttablecompumethod.py +4 -4
- odxtools/createanycomparam.py +4 -4
- odxtools/createanydiagcodedtype.py +7 -7
- odxtools/database.py +28 -26
- odxtools/dataobjectproperty.py +15 -16
- odxtools/description.py +7 -7
- odxtools/determinenumberofitems.py +6 -5
- odxtools/diagcodedtype.py +6 -6
- odxtools/diagcomm.py +26 -27
- odxtools/diagdatadictionaryspec.py +34 -34
- odxtools/diaglayercontainer.py +32 -31
- odxtools/diaglayers/basevariant.py +5 -4
- odxtools/diaglayers/basevariantraw.py +18 -19
- odxtools/diaglayers/diaglayer.py +5 -4
- odxtools/diaglayers/diaglayerraw.py +39 -48
- odxtools/diaglayers/ecushareddata.py +6 -6
- odxtools/diaglayers/ecushareddataraw.py +11 -12
- odxtools/diaglayers/ecuvariant.py +5 -4
- odxtools/diaglayers/ecuvariantraw.py +17 -18
- odxtools/diaglayers/functionalgroup.py +5 -5
- odxtools/diaglayers/functionalgroupraw.py +13 -14
- odxtools/diaglayers/hierarchyelement.py +9 -9
- odxtools/diaglayers/hierarchyelementraw.py +8 -9
- odxtools/diaglayers/protocol.py +4 -4
- odxtools/diaglayers/protocolraw.py +10 -11
- odxtools/diagnostictroublecode.py +12 -14
- odxtools/diagservice.py +19 -18
- odxtools/diagvariable.py +19 -20
- odxtools/docrevision.py +14 -13
- odxtools/dopbase.py +10 -11
- odxtools/dtcconnector.py +6 -5
- odxtools/dtcdop.py +15 -15
- odxtools/dynamicendmarkerfield.py +6 -6
- odxtools/dynamiclengthfield.py +6 -6
- odxtools/dyndefinedspec.py +7 -7
- odxtools/dynenddopref.py +7 -7
- odxtools/dyniddefmodeinfo.py +17 -17
- odxtools/ecuvariantpattern.py +6 -7
- odxtools/element.py +12 -12
- odxtools/endofpdufield.py +6 -7
- odxtools/envdataconnector.py +6 -6
- odxtools/environmentdata.py +7 -8
- odxtools/environmentdatadescription.py +13 -12
- odxtools/externalaccessmethod.py +4 -5
- odxtools/externaldoc.py +4 -4
- odxtools/field.py +12 -11
- odxtools/functionalclass.py +7 -7
- odxtools/inputparam.py +9 -8
- odxtools/internalconstr.py +10 -10
- odxtools/leadinglengthinfotype.py +5 -6
- odxtools/library.py +7 -6
- odxtools/linkeddtcdop.py +7 -6
- odxtools/matchingbasevariantparameter.py +5 -5
- odxtools/matchingparameter.py +6 -6
- odxtools/message.py +1 -1
- odxtools/minmaxlengthtype.py +6 -7
- odxtools/modification.py +5 -4
- odxtools/multiplexer.py +48 -12
- odxtools/multiplexercase.py +10 -10
- odxtools/multiplexerdefaultcase.py +8 -7
- odxtools/multiplexerswitchkey.py +6 -6
- odxtools/nameditemlist.py +1 -1
- odxtools/negoutputparam.py +6 -6
- odxtools/odxcategory.py +12 -24
- odxtools/odxdoccontext.py +16 -0
- odxtools/odxlink.py +11 -12
- odxtools/odxtypes.py +3 -3
- odxtools/outputparam.py +7 -6
- odxtools/parameters/codedconstparameter.py +6 -6
- odxtools/parameters/createanyparameter.py +15 -15
- odxtools/parameters/dynamicparameter.py +4 -5
- odxtools/parameters/lengthkeyparameter.py +6 -6
- odxtools/parameters/matchingrequestparameter.py +4 -4
- odxtools/parameters/nrcconstparameter.py +8 -8
- odxtools/parameters/parameter.py +12 -13
- odxtools/parameters/parameterwithdop.py +9 -9
- odxtools/parameters/physicalconstantparameter.py +5 -4
- odxtools/parameters/reservedparameter.py +4 -5
- odxtools/parameters/systemparameter.py +4 -5
- odxtools/parameters/tableentryparameter.py +6 -6
- odxtools/parameters/tablekeyparameter.py +12 -12
- odxtools/parameters/tablestructparameter.py +9 -9
- odxtools/parameters/valueparameter.py +6 -6
- odxtools/paramlengthinfotype.py +6 -7
- odxtools/parentref.py +12 -10
- odxtools/physicaldimension.py +12 -12
- odxtools/physicaltype.py +5 -5
- odxtools/posresponsesuppressible.py +11 -11
- odxtools/preconditionstateref.py +8 -8
- odxtools/progcode.py +9 -8
- odxtools/protstack.py +8 -7
- odxtools/relateddiagcommref.py +5 -5
- odxtools/relateddoc.py +8 -7
- odxtools/request.py +12 -13
- odxtools/response.py +12 -13
- odxtools/scaleconstr.py +8 -8
- odxtools/singleecujob.py +14 -13
- odxtools/snrefcontext.py +1 -1
- odxtools/specialdata.py +6 -5
- odxtools/specialdatagroup.py +13 -13
- odxtools/specialdatagroupcaption.py +5 -4
- odxtools/standardlengthtype.py +5 -13
- odxtools/state.py +5 -4
- odxtools/statechart.py +10 -9
- odxtools/statemachine.py +2 -2
- odxtools/statetransition.py +7 -7
- odxtools/statetransitionref.py +11 -11
- odxtools/staticfield.py +5 -4
- odxtools/structure.py +5 -5
- odxtools/subcomponent.py +18 -16
- odxtools/subcomponentparamconnector.py +8 -7
- odxtools/subcomponentpattern.py +7 -7
- odxtools/swvariable.py +6 -6
- odxtools/table.py +20 -21
- odxtools/tablediagcommconnector.py +7 -6
- odxtools/tablerow.py +57 -36
- odxtools/tablerowconnector.py +6 -6
- odxtools/teammember.py +14 -13
- odxtools/templates/macros/printParentRef.xml.jinja2 +3 -1
- odxtools/text.py +4 -4
- odxtools/unit.py +9 -8
- odxtools/unitgroup.py +9 -8
- odxtools/unitspec.py +15 -16
- odxtools/variablegroup.py +4 -5
- odxtools/variantpattern.py +3 -4
- odxtools/version.py +2 -2
- odxtools/writepdxfile.py +0 -19
- odxtools/xdoc.py +11 -10
- {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/METADATA +1 -1
- odxtools-10.1.0.dist-info/RECORD +265 -0
- {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/WHEEL +1 -1
- odxtools-10.0.0.dist-info/RECORD +0 -264
- {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/entry_points.txt +0 -0
- {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/licenses/LICENSE +0 -0
- {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/top_level.txt +0 -0
odxtools/library.py
CHANGED
@@ -5,12 +5,13 @@ from xml.etree import ElementTree
|
|
5
5
|
|
6
6
|
from .element import IdentifiableElement
|
7
7
|
from .exceptions import odxraise, odxrequire
|
8
|
-
from .
|
8
|
+
from .odxdoccontext import OdxDocContext
|
9
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId
|
9
10
|
from .snrefcontext import SnRefContext
|
10
11
|
from .utils import dataclass_fields_asdict
|
11
12
|
|
12
13
|
|
13
|
-
@dataclass
|
14
|
+
@dataclass(kw_only=True)
|
14
15
|
class Library(IdentifiableElement):
|
15
16
|
"""
|
16
17
|
A library defines a shared library used for single ECU jobs etc.
|
@@ -19,19 +20,19 @@ class Library(IdentifiableElement):
|
|
19
20
|
"""
|
20
21
|
|
21
22
|
code_file: str
|
22
|
-
encryption: str | None
|
23
|
+
encryption: str | None = None
|
23
24
|
syntax: str
|
24
25
|
revision: str
|
25
|
-
entrypoint: str | None
|
26
|
+
entrypoint: str | None = None
|
26
27
|
|
27
28
|
@property
|
28
29
|
def code(self) -> bytes:
|
29
30
|
return self._code
|
30
31
|
|
31
32
|
@staticmethod
|
32
|
-
def from_et(et_element: ElementTree.Element,
|
33
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Library":
|
33
34
|
|
34
|
-
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element,
|
35
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
|
35
36
|
|
36
37
|
code_file = odxrequire(et_element.findtext("CODE-FILE"))
|
37
38
|
encryption = et_element.findtext("ENCRYPTION")
|
odxtools/linkeddtcdop.py
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
from dataclasses import dataclass
|
2
|
+
from dataclasses import dataclass, field
|
3
3
|
from typing import TYPE_CHECKING, Any
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .diagnostictroublecode import DiagnosticTroubleCode
|
7
7
|
from .exceptions import odxrequire
|
8
8
|
from .nameditemlist import NamedItemList
|
9
|
-
from .
|
9
|
+
from .odxdoccontext import OdxDocContext
|
10
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
10
11
|
from .snrefcontext import SnRefContext
|
11
12
|
|
12
13
|
if TYPE_CHECKING:
|
13
14
|
from .dtcdop import DtcDop
|
14
15
|
|
15
16
|
|
16
|
-
@dataclass
|
17
|
+
@dataclass(kw_only=True)
|
17
18
|
class LinkedDtcDop:
|
18
|
-
not_inherited_dtc_snrefs: list[str]
|
19
|
+
not_inherited_dtc_snrefs: list[str] = field(default_factory=list)
|
19
20
|
dtc_dop_ref: OdxLinkRef
|
20
21
|
|
21
22
|
@property
|
@@ -31,14 +32,14 @@ class LinkedDtcDop:
|
|
31
32
|
return self._dtc_dop.short_name
|
32
33
|
|
33
34
|
@staticmethod
|
34
|
-
def from_et(et_element: ElementTree.Element,
|
35
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "LinkedDtcDop":
|
35
36
|
not_inherited_dtc_snrefs = [
|
36
37
|
odxrequire(el.get("SHORT-NAME"))
|
37
38
|
for el in et_element.iterfind("NOT-INHERITED-DTC-SNREFS/"
|
38
39
|
"NOT-INHERITED-DTC-SNREF")
|
39
40
|
]
|
40
41
|
|
41
|
-
dtc_dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DTC-DOP-REF"),
|
42
|
+
dtc_dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DTC-DOP-REF"), context))
|
42
43
|
|
43
44
|
return LinkedDtcDop(
|
44
45
|
not_inherited_dtc_snrefs=not_inherited_dtc_snrefs, dtc_dop_ref=dtc_dop_ref)
|
@@ -3,12 +3,12 @@ from dataclasses import dataclass
|
|
3
3
|
from xml.etree import ElementTree
|
4
4
|
|
5
5
|
from .matchingparameter import MatchingParameter
|
6
|
-
from .
|
6
|
+
from .odxdoccontext import OdxDocContext
|
7
7
|
from .odxtypes import odxstr_to_bool
|
8
8
|
from .utils import dataclass_fields_asdict
|
9
9
|
|
10
10
|
|
11
|
-
@dataclass
|
11
|
+
@dataclass(kw_only=True)
|
12
12
|
class MatchingBaseVariantParameter(MatchingParameter):
|
13
13
|
"""A description of a parameter used for base variant matching.
|
14
14
|
|
@@ -17,7 +17,7 @@ class MatchingBaseVariantParameter(MatchingParameter):
|
|
17
17
|
additional subtag `USE-PHYSICAL-ADDRESSING`.
|
18
18
|
"""
|
19
19
|
|
20
|
-
use_physical_addressing_raw: bool | None
|
20
|
+
use_physical_addressing_raw: bool | None = None
|
21
21
|
|
22
22
|
@property
|
23
23
|
def use_physical_addressing(self) -> bool:
|
@@ -25,9 +25,9 @@ class MatchingBaseVariantParameter(MatchingParameter):
|
|
25
25
|
|
26
26
|
@staticmethod
|
27
27
|
def from_et(et_element: ElementTree.Element,
|
28
|
-
|
28
|
+
context: OdxDocContext) -> "MatchingBaseVariantParameter":
|
29
29
|
|
30
|
-
kwargs = dataclass_fields_asdict(MatchingParameter.from_et(et_element,
|
30
|
+
kwargs = dataclass_fields_asdict(MatchingParameter.from_et(et_element, context))
|
31
31
|
|
32
32
|
use_physical_addressing_raw = odxstr_to_bool(et_element.findtext("USE-PHYSICAL-ADDRESSING"))
|
33
33
|
|
odxtools/matchingparameter.py
CHANGED
@@ -7,12 +7,13 @@ from .diaglayers.diaglayer import DiagLayer
|
|
7
7
|
from .diagnostictroublecode import DiagnosticTroubleCode
|
8
8
|
from .diagservice import DiagService
|
9
9
|
from .exceptions import odxraise, odxrequire
|
10
|
-
from .
|
10
|
+
from .odxdoccontext import OdxDocContext
|
11
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId, resolve_snref
|
11
12
|
from .odxtypes import BytesTypes, ParameterValue, ParameterValueDict
|
12
13
|
from .snrefcontext import SnRefContext
|
13
14
|
|
14
15
|
|
15
|
-
@dataclass
|
16
|
+
@dataclass(kw_only=True)
|
16
17
|
class MatchingParameter:
|
17
18
|
"""According to ISO 22901, a MatchingParameter contains a string
|
18
19
|
value identifying the active ECU or base variant. Moreover, it
|
@@ -34,12 +35,11 @@ class MatchingParameter:
|
|
34
35
|
# or negative response. What it probably actually wants to say is
|
35
36
|
# that any response that can possibly be received shall exhibit
|
36
37
|
# the referenced parameter.
|
37
|
-
out_param_if_snref: str | None
|
38
|
-
out_param_if_snpathref: str | None
|
38
|
+
out_param_if_snref: str | None = None
|
39
|
+
out_param_if_snpathref: str | None = None
|
39
40
|
|
40
41
|
@staticmethod
|
41
|
-
def from_et(et_element: ElementTree.Element,
|
42
|
-
doc_frags: list[OdxDocFragment]) -> "MatchingParameter":
|
42
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "MatchingParameter":
|
43
43
|
|
44
44
|
expected_value = odxrequire(et_element.findtext("EXPECTED-VALUE"))
|
45
45
|
diag_comm_snref = odxrequire(
|
odxtools/message.py
CHANGED
odxtools/minmaxlengthtype.py
CHANGED
@@ -10,15 +10,15 @@ from .diagcodedtype import DctType, DiagCodedType
|
|
10
10
|
from .encodestate import EncodeState
|
11
11
|
from .encoding import get_string_encoding
|
12
12
|
from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
13
|
-
from .
|
13
|
+
from .odxdoccontext import OdxDocContext
|
14
14
|
from .odxtypes import AtomicOdxType, BytesTypes, DataType
|
15
15
|
from .termination import Termination
|
16
16
|
from .utils import dataclass_fields_asdict
|
17
17
|
|
18
18
|
|
19
|
-
@dataclass
|
19
|
+
@dataclass(kw_only=True)
|
20
20
|
class MinMaxLengthType(DiagCodedType):
|
21
|
-
max_length: int | None
|
21
|
+
max_length: int | None = None
|
22
22
|
min_length: int
|
23
23
|
termination: Termination
|
24
24
|
|
@@ -28,9 +28,8 @@ class MinMaxLengthType(DiagCodedType):
|
|
28
28
|
|
29
29
|
@staticmethod
|
30
30
|
@override
|
31
|
-
def from_et(et_element: ElementTree.Element,
|
32
|
-
|
33
|
-
kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
|
31
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "MinMaxLengthType":
|
32
|
+
kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, context))
|
34
33
|
|
35
34
|
max_length = None
|
36
35
|
if et_element.find("MAX-LENGTH") is not None:
|
@@ -77,7 +76,7 @@ class MinMaxLengthType(DiagCodedType):
|
|
77
76
|
@override
|
78
77
|
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
79
78
|
|
80
|
-
if not isinstance(internal_value, str
|
79
|
+
if not isinstance(internal_value, (str, BytesTypes)):
|
81
80
|
odxraise("MinMaxLengthType is currently only implemented for strings and byte arrays",
|
82
81
|
EncodeError)
|
83
82
|
|
odxtools/modification.py
CHANGED
@@ -4,17 +4,18 @@ from typing import Any
|
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .exceptions import odxrequire
|
7
|
-
from .
|
7
|
+
from .odxdoccontext import OdxDocContext
|
8
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId
|
8
9
|
from .snrefcontext import SnRefContext
|
9
10
|
|
10
11
|
|
11
|
-
@dataclass
|
12
|
+
@dataclass(kw_only=True)
|
12
13
|
class Modification:
|
13
14
|
change: str
|
14
|
-
reason: str | None
|
15
|
+
reason: str | None = None
|
15
16
|
|
16
17
|
@staticmethod
|
17
|
-
def from_et(et_element: ElementTree.Element,
|
18
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Modification":
|
18
19
|
change = odxrequire(et_element.findtext("CHANGE"))
|
19
20
|
reason = et_element.findtext("REASON")
|
20
21
|
|
odxtools/multiplexer.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
from dataclasses import dataclass
|
2
|
+
from dataclasses import dataclass, field
|
3
3
|
from typing import Any, cast
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
@@ -13,13 +13,14 @@ from .multiplexercase import MultiplexerCase
|
|
13
13
|
from .multiplexerdefaultcase import MultiplexerDefaultCase
|
14
14
|
from .multiplexerswitchkey import MultiplexerSwitchKey
|
15
15
|
from .nameditemlist import NamedItemList
|
16
|
-
from .
|
16
|
+
from .odxdoccontext import OdxDocContext
|
17
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId
|
17
18
|
from .odxtypes import AtomicOdxType, ParameterValue, odxstr_to_bool
|
18
19
|
from .snrefcontext import SnRefContext
|
19
20
|
from .utils import dataclass_fields_asdict
|
20
21
|
|
21
22
|
|
22
|
-
@dataclass
|
23
|
+
@dataclass(kw_only=True)
|
23
24
|
class Multiplexer(ComplexDop):
|
24
25
|
"""This class represents a Multiplexer (MUX)
|
25
26
|
|
@@ -30,9 +31,9 @@ class Multiplexer(ComplexDop):
|
|
30
31
|
|
31
32
|
byte_position: int
|
32
33
|
switch_key: MultiplexerSwitchKey
|
33
|
-
default_case: MultiplexerDefaultCase | None
|
34
|
-
cases: NamedItemList[MultiplexerCase]
|
35
|
-
is_visible_raw: bool | None
|
34
|
+
default_case: MultiplexerDefaultCase | None = None
|
35
|
+
cases: NamedItemList[MultiplexerCase] = field(default_factory=NamedItemList)
|
36
|
+
is_visible_raw: bool | None = None
|
36
37
|
|
37
38
|
@property
|
38
39
|
def is_visible(self) -> bool:
|
@@ -40,20 +41,20 @@ class Multiplexer(ComplexDop):
|
|
40
41
|
|
41
42
|
@staticmethod
|
42
43
|
@override
|
43
|
-
def from_et(et_element: ElementTree.Element,
|
44
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Multiplexer":
|
44
45
|
"""Reads a Multiplexer from Diag Layer."""
|
45
|
-
kwargs = dataclass_fields_asdict(ComplexDop.from_et(et_element,
|
46
|
+
kwargs = dataclass_fields_asdict(ComplexDop.from_et(et_element, context))
|
46
47
|
|
47
48
|
byte_position = int(et_element.findtext("BYTE-POSITION", "0"))
|
48
49
|
switch_key = MultiplexerSwitchKey.from_et(
|
49
|
-
odxrequire(et_element.find("SWITCH-KEY")),
|
50
|
+
odxrequire(et_element.find("SWITCH-KEY")), context)
|
50
51
|
|
51
52
|
default_case = None
|
52
53
|
if (dc_elem := et_element.find("DEFAULT-CASE")) is not None:
|
53
|
-
default_case = MultiplexerDefaultCase.from_et(dc_elem,
|
54
|
+
default_case = MultiplexerDefaultCase.from_et(dc_elem, context)
|
54
55
|
|
55
56
|
cases = NamedItemList(
|
56
|
-
[MultiplexerCase.from_et(el,
|
57
|
+
[MultiplexerCase.from_et(el, context) for el in et_element.iterfind("CASES/CASE")])
|
57
58
|
|
58
59
|
is_visible_raw = odxstr_to_bool(et_element.get("IS-VISIBLE"))
|
59
60
|
|
@@ -118,7 +119,7 @@ class Multiplexer(ComplexDop):
|
|
118
119
|
orig_origin = encode_state.origin_byte_position
|
119
120
|
encode_state.origin_byte_position = encode_state.cursor_byte_position
|
120
121
|
|
121
|
-
if isinstance(physical_value, list
|
122
|
+
if isinstance(physical_value, (list, tuple)) and len(physical_value) == 2:
|
122
123
|
case_spec, case_value = physical_value
|
123
124
|
elif isinstance(physical_value, dict) and len(physical_value) == 1:
|
124
125
|
case_spec, case_value = next(iter(physical_value.items()))
|
@@ -235,3 +236,38 @@ class Multiplexer(ComplexDop):
|
|
235
236
|
decode_state.origin_byte_position = orig_origin
|
236
237
|
|
237
238
|
return result
|
239
|
+
|
240
|
+
@override
|
241
|
+
def get_static_bit_length(self) -> int | None:
|
242
|
+
"""
|
243
|
+
Returns the static bit length of the multiplexer structure, if determinable.
|
244
|
+
|
245
|
+
If all cases (including the default, if present) have the same static bit length,
|
246
|
+
the codec length is considered static and is returned.
|
247
|
+
Otherwise, returns None to indicate that the size is dynamic.
|
248
|
+
"""
|
249
|
+
reference_case = self.default_case if self.default_case else self.cases[0]
|
250
|
+
|
251
|
+
case_bit_length: int | None
|
252
|
+
if reference_case.structure is None:
|
253
|
+
case_bit_length = 0
|
254
|
+
else:
|
255
|
+
case_bit_length = reference_case.structure.get_static_bit_length()
|
256
|
+
if case_bit_length is None:
|
257
|
+
return None
|
258
|
+
case_size: int | None
|
259
|
+
for mux_case in self.cases:
|
260
|
+
if mux_case.structure is None:
|
261
|
+
case_size = 0
|
262
|
+
else:
|
263
|
+
case_size = mux_case.structure.get_static_bit_length()
|
264
|
+
if case_size != case_bit_length:
|
265
|
+
return None # Found a case with a different or unknown size
|
266
|
+
|
267
|
+
switch_key_size = self.switch_key.dop.get_static_bit_length()
|
268
|
+
if switch_key_size is None:
|
269
|
+
return None
|
270
|
+
|
271
|
+
return max(
|
272
|
+
switch_key_size + self.switch_key.byte_position * 8 +
|
273
|
+
(self.switch_key.bit_position or 0), case_bit_length + self.byte_position * 8)
|
odxtools/multiplexercase.py
CHANGED
@@ -6,19 +6,20 @@ from xml.etree import ElementTree
|
|
6
6
|
from .compumethods.limit import Limit
|
7
7
|
from .element import NamedElement
|
8
8
|
from .exceptions import odxrequire
|
9
|
-
from .
|
9
|
+
from .odxdoccontext import OdxDocContext
|
10
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
10
11
|
from .odxtypes import AtomicOdxType, DataType
|
11
12
|
from .snrefcontext import SnRefContext
|
12
13
|
from .structure import Structure
|
13
14
|
from .utils import dataclass_fields_asdict
|
14
15
|
|
15
16
|
|
16
|
-
@dataclass
|
17
|
+
@dataclass(kw_only=True)
|
17
18
|
class MultiplexerCase(NamedElement):
|
18
19
|
"""This class represents a case which represents a range of keys of a multiplexer."""
|
19
20
|
|
20
|
-
structure_ref: OdxLinkRef | None
|
21
|
-
structure_snref: str | None
|
21
|
+
structure_ref: OdxLinkRef | None = None
|
22
|
+
structure_snref: str | None = None
|
22
23
|
lower_limit: Limit
|
23
24
|
upper_limit: Limit
|
24
25
|
|
@@ -27,23 +28,22 @@ class MultiplexerCase(NamedElement):
|
|
27
28
|
return self._structure
|
28
29
|
|
29
30
|
@staticmethod
|
30
|
-
def from_et(et_element: ElementTree.Element,
|
31
|
-
doc_frags: list[OdxDocFragment]) -> "MultiplexerCase":
|
31
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "MultiplexerCase":
|
32
32
|
"""Reads a case for a Multiplexer."""
|
33
|
-
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element,
|
34
|
-
structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"),
|
33
|
+
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, context))
|
34
|
+
structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), context)
|
35
35
|
structure_snref = None
|
36
36
|
if (structure_snref_elem := et_element.find("STRUCTURE-SNREF")) is not None:
|
37
37
|
structure_snref = odxrequire(structure_snref_elem.get("SHORT-NAME"))
|
38
38
|
|
39
39
|
lower_limit = Limit.limit_from_et(
|
40
40
|
odxrequire(et_element.find("LOWER-LIMIT")),
|
41
|
-
|
41
|
+
context,
|
42
42
|
value_type=None,
|
43
43
|
)
|
44
44
|
upper_limit = Limit.limit_from_et(
|
45
45
|
odxrequire(et_element.find("UPPER-LIMIT")),
|
46
|
-
|
46
|
+
context,
|
47
47
|
value_type=None,
|
48
48
|
)
|
49
49
|
|
@@ -5,17 +5,18 @@ from xml.etree import ElementTree
|
|
5
5
|
|
6
6
|
from .element import NamedElement
|
7
7
|
from .exceptions import odxrequire
|
8
|
-
from .
|
8
|
+
from .odxdoccontext import OdxDocContext
|
9
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
9
10
|
from .snrefcontext import SnRefContext
|
10
11
|
from .structure import Structure
|
11
12
|
from .utils import dataclass_fields_asdict
|
12
13
|
|
13
14
|
|
14
|
-
@dataclass
|
15
|
+
@dataclass(kw_only=True)
|
15
16
|
class MultiplexerDefaultCase(NamedElement):
|
16
17
|
"""This class represents a Default Case, which is selected when there are no cases defined in the Multiplexer."""
|
17
|
-
structure_ref: OdxLinkRef | None
|
18
|
-
structure_snref: str | None
|
18
|
+
structure_ref: OdxLinkRef | None = None
|
19
|
+
structure_snref: str | None = None
|
19
20
|
|
20
21
|
@property
|
21
22
|
def structure(self) -> Structure | None:
|
@@ -23,11 +24,11 @@ class MultiplexerDefaultCase(NamedElement):
|
|
23
24
|
|
24
25
|
@staticmethod
|
25
26
|
def from_et(et_element: ElementTree.Element,
|
26
|
-
|
27
|
+
context: OdxDocContext) -> "MultiplexerDefaultCase":
|
27
28
|
"""Reads a default case for a multiplexer."""
|
28
|
-
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element,
|
29
|
+
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, context))
|
29
30
|
|
30
|
-
structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"),
|
31
|
+
structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), context)
|
31
32
|
structure_snref = None
|
32
33
|
if (structure_snref_elem := et_element.find("STRUCTURE-SNREF")) is not None:
|
33
34
|
structure_snref = odxrequire(structure_snref_elem.get("SHORT-NAME"))
|
odxtools/multiplexerswitchkey.py
CHANGED
@@ -5,17 +5,18 @@ from xml.etree import ElementTree
|
|
5
5
|
|
6
6
|
from .dataobjectproperty import DataObjectProperty
|
7
7
|
from .exceptions import odxrequire
|
8
|
-
from .
|
8
|
+
from .odxdoccontext import OdxDocContext
|
9
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
9
10
|
from .snrefcontext import SnRefContext
|
10
11
|
|
11
12
|
|
12
|
-
@dataclass
|
13
|
+
@dataclass(kw_only=True)
|
13
14
|
class MultiplexerSwitchKey:
|
14
15
|
"""
|
15
16
|
The object that determines the case to be used by a multiplexer
|
16
17
|
"""
|
17
18
|
byte_position: int
|
18
|
-
bit_position: int | None
|
19
|
+
bit_position: int | None = None
|
19
20
|
dop_ref: OdxLinkRef
|
20
21
|
|
21
22
|
@property
|
@@ -23,12 +24,11 @@ class MultiplexerSwitchKey:
|
|
23
24
|
return self._dop
|
24
25
|
|
25
26
|
@staticmethod
|
26
|
-
def from_et(et_element: ElementTree.Element,
|
27
|
-
doc_frags: list[OdxDocFragment]) -> "MultiplexerSwitchKey":
|
27
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "MultiplexerSwitchKey":
|
28
28
|
byte_position = int(odxrequire(et_element.findtext("BYTE-POSITION")))
|
29
29
|
bit_position_str = et_element.findtext("BIT-POSITION")
|
30
30
|
bit_position = int(bit_position_str) if bit_position_str is not None else None
|
31
|
-
dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"),
|
31
|
+
dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), context))
|
32
32
|
|
33
33
|
return MultiplexerSwitchKey(
|
34
34
|
byte_position=byte_position,
|
odxtools/nameditemlist.py
CHANGED
@@ -142,7 +142,7 @@ class ItemAttributeList(list[T]):
|
|
142
142
|
...
|
143
143
|
|
144
144
|
def __getitem__(self, key: SupportsIndex | str | slice) -> T | list[T]:
|
145
|
-
if isinstance(key, SupportsIndex
|
145
|
+
if isinstance(key, (SupportsIndex, slice)):
|
146
146
|
return super().__getitem__(key)
|
147
147
|
else:
|
148
148
|
return self._item_dict[key]
|
odxtools/negoutputparam.py
CHANGED
@@ -6,12 +6,13 @@ from xml.etree import ElementTree
|
|
6
6
|
from .dopbase import DopBase
|
7
7
|
from .element import NamedElement
|
8
8
|
from .exceptions import odxrequire
|
9
|
-
from .
|
9
|
+
from .odxdoccontext import OdxDocContext
|
10
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
10
11
|
from .snrefcontext import SnRefContext
|
11
12
|
from .utils import dataclass_fields_asdict
|
12
13
|
|
13
14
|
|
14
|
-
@dataclass
|
15
|
+
@dataclass(kw_only=True)
|
15
16
|
class NegOutputParam(NamedElement):
|
16
17
|
dop_base_ref: OdxLinkRef
|
17
18
|
|
@@ -21,11 +22,10 @@ class NegOutputParam(NamedElement):
|
|
21
22
|
return self._dop
|
22
23
|
|
23
24
|
@staticmethod
|
24
|
-
def from_et(et_element: ElementTree.Element,
|
25
|
-
doc_frags: list[OdxDocFragment]) -> "NegOutputParam":
|
25
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "NegOutputParam":
|
26
26
|
|
27
|
-
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element,
|
28
|
-
dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"),
|
27
|
+
kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, context))
|
28
|
+
dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), context))
|
29
29
|
|
30
30
|
return NegOutputParam(dop_base_ref=dop_base_ref, **kwargs)
|
31
31
|
|
odxtools/odxcategory.py
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
|
-
from dataclasses import dataclass
|
2
|
+
from dataclasses import dataclass, field
|
3
3
|
from typing import TYPE_CHECKING, Any
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from .admindata import AdminData
|
7
7
|
from .companydata import CompanyData
|
8
8
|
from .element import IdentifiableElement
|
9
|
-
from .exceptions import odxrequire
|
10
9
|
from .nameditemlist import NamedItemList
|
11
|
-
from .
|
10
|
+
from .odxdoccontext import OdxDocContext
|
11
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId
|
12
12
|
from .snrefcontext import SnRefContext
|
13
13
|
from .specialdatagroup import SpecialDataGroup
|
14
14
|
from .utils import dataclass_fields_asdict
|
@@ -17,37 +17,25 @@ if TYPE_CHECKING:
|
|
17
17
|
from .database import Database
|
18
18
|
|
19
19
|
|
20
|
-
@dataclass
|
20
|
+
@dataclass(kw_only=True)
|
21
21
|
class OdxCategory(IdentifiableElement):
|
22
22
|
"""This is the base class for all top-level container classes in ODX"""
|
23
23
|
|
24
|
-
admin_data: AdminData | None
|
25
|
-
company_datas: NamedItemList[CompanyData]
|
26
|
-
sdgs: list[SpecialDataGroup]
|
24
|
+
admin_data: AdminData | None = None
|
25
|
+
company_datas: NamedItemList[CompanyData] = field(default_factory=NamedItemList)
|
26
|
+
sdgs: list[SpecialDataGroup] = field(default_factory=list)
|
27
27
|
|
28
28
|
@staticmethod
|
29
|
-
def from_et(et_element: ElementTree.Element,
|
30
|
-
raise Exception("Calling `._from_et()` is not allowed for OdxCategory. "
|
31
|
-
"Use `OdxCategory.category_from_et()`!")
|
29
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "OdxCategory":
|
32
30
|
|
33
|
-
|
34
|
-
def category_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
|
35
|
-
doc_type: DocType) -> "OdxCategory":
|
36
|
-
|
37
|
-
short_name = odxrequire(et_element.findtext("SHORT-NAME"))
|
38
|
-
# create the current ODX "document fragment" (description of the
|
39
|
-
# current document for references and IDs)
|
40
|
-
doc_frags = [OdxDocFragment(short_name, doc_type)]
|
41
|
-
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
31
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
|
42
32
|
|
43
|
-
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"),
|
33
|
+
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
|
44
34
|
company_datas = NamedItemList([
|
45
|
-
CompanyData.from_et(cde,
|
35
|
+
CompanyData.from_et(cde, context)
|
46
36
|
for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA")
|
47
37
|
])
|
48
|
-
sdgs = [
|
49
|
-
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
50
|
-
]
|
38
|
+
sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
|
51
39
|
|
52
40
|
return OdxCategory(admin_data=admin_data, company_datas=company_datas, sdgs=sdgs, **kwargs)
|
53
41
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from packaging.version import Version
|
5
|
+
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from odxtools.odxlink import OdxDocFragment
|
8
|
+
|
9
|
+
|
10
|
+
@dataclass(slots=True, frozen=True)
|
11
|
+
class OdxDocContext:
|
12
|
+
version: Version
|
13
|
+
|
14
|
+
# the doc_fragments are either tuple(doc_frag(category),)
|
15
|
+
# or tuple(doc_frag(category), doc_frag(diag_layer))
|
16
|
+
doc_fragments: tuple["OdxDocFragment"] | tuple["OdxDocFragment", "OdxDocFragment"]
|