odxtools 8.3.4__py3-none-any.whl → 9.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/basicstructure.py +36 -207
- odxtools/cli/_print_utils.py +163 -131
- odxtools/cli/browse.py +94 -79
- odxtools/cli/compare.py +88 -69
- odxtools/cli/list.py +2 -3
- odxtools/codec.py +211 -0
- odxtools/comparamspec.py +16 -54
- odxtools/comparamsubset.py +20 -61
- odxtools/database.py +18 -2
- odxtools/diaglayercontainer.py +14 -40
- odxtools/diaglayers/hierarchyelement.py +0 -10
- odxtools/dopbase.py +5 -3
- odxtools/dtcdop.py +101 -14
- odxtools/inputparam.py +0 -7
- odxtools/leadinglengthinfotype.py +1 -8
- odxtools/message.py +0 -7
- odxtools/minmaxlengthtype.py +4 -4
- odxtools/odxcategory.py +83 -0
- odxtools/outputparam.py +0 -7
- odxtools/parameterinfo.py +12 -12
- odxtools/parameters/lengthkeyparameter.py +1 -2
- odxtools/parameters/parameter.py +6 -4
- odxtools/parameters/tablekeyparameter.py +9 -8
- odxtools/paramlengthinfotype.py +8 -9
- odxtools/request.py +109 -16
- odxtools/response.py +115 -15
- odxtools/specialdatagroup.py +1 -1
- odxtools/templates/comparam-spec.odx-c.xml.jinja2 +4 -21
- odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +4 -22
- odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +4 -25
- odxtools/templates/macros/printDOP.xml.jinja2 +16 -0
- odxtools/templates/macros/printOdxCategory.xml.jinja2 +28 -0
- odxtools/uds.py +0 -8
- odxtools/version.py +2 -2
- {odxtools-8.3.4.dist-info → odxtools-9.1.0.dist-info}/METADATA +7 -8
- {odxtools-8.3.4.dist-info → odxtools-9.1.0.dist-info}/RECORD +40 -37
- {odxtools-8.3.4.dist-info → odxtools-9.1.0.dist-info}/WHEEL +1 -1
- {odxtools-8.3.4.dist-info → odxtools-9.1.0.dist-info}/LICENSE +0 -0
- {odxtools-8.3.4.dist-info → odxtools-9.1.0.dist-info}/entry_points.txt +0 -0
- {odxtools-8.3.4.dist-info → odxtools-9.1.0.dist-info}/top_level.txt +0 -0
odxtools/comparamsubset.py
CHANGED
@@ -1,50 +1,41 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Any, Dict, List, Optional
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from .admindata import AdminData
|
7
|
-
from .companydata import CompanyData
|
8
6
|
from .comparam import Comparam
|
9
7
|
from .complexcomparam import ComplexComparam
|
10
8
|
from .dataobjectproperty import DataObjectProperty
|
11
|
-
from .element import IdentifiableElement
|
12
|
-
from .exceptions import odxrequire
|
13
9
|
from .nameditemlist import NamedItemList
|
10
|
+
from .odxcategory import OdxCategory
|
14
11
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
15
12
|
from .snrefcontext import SnRefContext
|
16
|
-
from .specialdatagroup import SpecialDataGroup
|
17
13
|
from .unitspec import UnitSpec
|
18
14
|
from .utils import dataclass_fields_asdict
|
19
15
|
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from .database import Database
|
18
|
+
|
20
19
|
|
21
20
|
@dataclass
|
22
|
-
class ComparamSubset(
|
23
|
-
# mandatory in ODX 2.2, but non
|
21
|
+
class ComparamSubset(OdxCategory):
|
22
|
+
# mandatory in ODX 2.2, but non-existent in ODX 2.0
|
24
23
|
category: Optional[str]
|
25
|
-
|
24
|
+
|
26
25
|
comparams: NamedItemList[Comparam]
|
27
26
|
complex_comparams: NamedItemList[ComplexComparam]
|
27
|
+
data_object_props: NamedItemList[DataObjectProperty]
|
28
28
|
unit_spec: Optional[UnitSpec]
|
29
|
-
admin_data: Optional[AdminData]
|
30
|
-
company_datas: NamedItemList[CompanyData]
|
31
|
-
sdgs: List[SpecialDataGroup]
|
32
29
|
|
33
30
|
@staticmethod
|
34
31
|
def from_et(et_element: ElementTree.Element,
|
35
32
|
doc_frags: List[OdxDocFragment]) -> "ComparamSubset":
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
doc_frags = [OdxDocFragment(short_name, str(et_element.tag))]
|
41
|
-
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
34
|
+
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="COMPARAM-SUBSET")
|
35
|
+
doc_frags = cat.odx_id.doc_fragments
|
36
|
+
kwargs = dataclass_fields_asdict(cat)
|
42
37
|
|
43
|
-
|
44
|
-
company_datas = NamedItemList([
|
45
|
-
CompanyData.from_et(cde, doc_frags)
|
46
|
-
for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA")
|
47
|
-
])
|
38
|
+
category = et_element.get("CATEGORY")
|
48
39
|
|
49
40
|
data_object_props = NamedItemList([
|
50
41
|
DataObjectProperty.from_et(el, doc_frags)
|
@@ -61,25 +52,16 @@ class ComparamSubset(IdentifiableElement):
|
|
61
52
|
else:
|
62
53
|
unit_spec = None
|
63
54
|
|
64
|
-
sdgs = [
|
65
|
-
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
66
|
-
]
|
67
|
-
|
68
55
|
return ComparamSubset(
|
69
56
|
category=category,
|
70
|
-
admin_data=admin_data,
|
71
|
-
company_datas=company_datas,
|
72
57
|
data_object_props=data_object_props,
|
73
58
|
comparams=comparams,
|
74
59
|
complex_comparams=complex_comparams,
|
75
60
|
unit_spec=unit_spec,
|
76
|
-
sdgs=sdgs,
|
77
61
|
**kwargs)
|
78
62
|
|
79
63
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
80
|
-
odxlinks
|
81
|
-
if self.odx_id is not None:
|
82
|
-
odxlinks[self.odx_id] = self
|
64
|
+
odxlinks = super()._build_odxlinks()
|
83
65
|
|
84
66
|
for dop in self.data_object_props:
|
85
67
|
odxlinks[dop.odx_id] = dop
|
@@ -93,19 +75,11 @@ class ComparamSubset(IdentifiableElement):
|
|
93
75
|
if self.unit_spec:
|
94
76
|
odxlinks.update(self.unit_spec._build_odxlinks())
|
95
77
|
|
96
|
-
if self.admin_data is not None:
|
97
|
-
odxlinks.update(self.admin_data._build_odxlinks())
|
98
|
-
|
99
|
-
if self.company_datas is not None:
|
100
|
-
for cd in self.company_datas:
|
101
|
-
odxlinks.update(cd._build_odxlinks())
|
102
|
-
|
103
|
-
for sdg in self.sdgs:
|
104
|
-
odxlinks.update(sdg._build_odxlinks())
|
105
|
-
|
106
78
|
return odxlinks
|
107
79
|
|
108
80
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
81
|
+
super()._resolve_odxlinks(odxlinks)
|
82
|
+
|
109
83
|
for dop in self.data_object_props:
|
110
84
|
dop._resolve_odxlinks(odxlinks)
|
111
85
|
|
@@ -118,17 +92,12 @@ class ComparamSubset(IdentifiableElement):
|
|
118
92
|
if self.unit_spec:
|
119
93
|
self.unit_spec._resolve_odxlinks(odxlinks)
|
120
94
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
if self.company_datas is not None:
|
125
|
-
for cd in self.company_datas:
|
126
|
-
cd._resolve_odxlinks(odxlinks)
|
127
|
-
|
128
|
-
for sdg in self.sdgs:
|
129
|
-
sdg._resolve_odxlinks(odxlinks)
|
95
|
+
def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None:
|
96
|
+
super()._finalize_init(database, odxlinks)
|
130
97
|
|
131
98
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
99
|
+
super()._resolve_snrefs(context)
|
100
|
+
|
132
101
|
for dop in self.data_object_props:
|
133
102
|
dop._resolve_snrefs(context)
|
134
103
|
|
@@ -140,13 +109,3 @@ class ComparamSubset(IdentifiableElement):
|
|
140
109
|
|
141
110
|
if self.unit_spec:
|
142
111
|
self.unit_spec._resolve_snrefs(context)
|
143
|
-
|
144
|
-
if self.admin_data is not None:
|
145
|
-
self.admin_data._resolve_snrefs(context)
|
146
|
-
|
147
|
-
if self.company_datas is not None:
|
148
|
-
for cd in self.company_datas:
|
149
|
-
cd._resolve_snrefs(context)
|
150
|
-
|
151
|
-
for sdg in self.sdgs:
|
152
|
-
sdg._resolve_snrefs(context)
|
odxtools/database.py
CHANGED
@@ -20,6 +20,7 @@ from .diaglayers.protocol import Protocol
|
|
20
20
|
from .exceptions import odxraise, odxrequire
|
21
21
|
from .nameditemlist import NamedItemList
|
22
22
|
from .odxlink import OdxLinkDatabase, OdxLinkId
|
23
|
+
from .snrefcontext import SnRefContext
|
23
24
|
|
24
25
|
|
25
26
|
class Database:
|
@@ -139,11 +140,26 @@ class Database:
|
|
139
140
|
for dlc in self.diag_layer_containers:
|
140
141
|
dlc._resolve_odxlinks(self._odxlinks)
|
141
142
|
|
142
|
-
#
|
143
|
-
#
|
143
|
+
# resolve short name references for containers which do not do
|
144
|
+
# inheritance (we can call directly call _resolve_snrefs())
|
145
|
+
context = SnRefContext()
|
146
|
+
context.database = self
|
147
|
+
|
148
|
+
# let the diaglayers sort out the inherited objects
|
149
|
+
for subset in self.comparam_subsets:
|
150
|
+
subset._finalize_init(self, self._odxlinks)
|
151
|
+
for spec in self.comparam_specs:
|
152
|
+
spec._finalize_init(self, self._odxlinks)
|
144
153
|
for dlc in self.diag_layer_containers:
|
145
154
|
dlc._finalize_init(self, self._odxlinks)
|
146
155
|
|
156
|
+
for subset in self.comparam_subsets:
|
157
|
+
subset._resolve_snrefs(context)
|
158
|
+
for spec in self.comparam_specs:
|
159
|
+
spec._resolve_snrefs(context)
|
160
|
+
for dlc in self.diag_layer_containers:
|
161
|
+
dlc._resolve_snrefs(context)
|
162
|
+
|
147
163
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
148
164
|
result: Dict[OdxLinkId, Any] = {}
|
149
165
|
|
odxtools/diaglayercontainer.py
CHANGED
@@ -1,22 +1,19 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from itertools import chain
|
4
|
-
from typing import TYPE_CHECKING, Any, Dict, List,
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Union
|
5
5
|
from xml.etree import ElementTree
|
6
6
|
|
7
|
-
from .admindata import AdminData
|
8
|
-
from .companydata import CompanyData
|
9
7
|
from .diaglayers.basevariant import BaseVariant
|
10
8
|
from .diaglayers.diaglayer import DiagLayer
|
11
9
|
from .diaglayers.ecushareddata import EcuSharedData
|
12
10
|
from .diaglayers.ecuvariant import EcuVariant
|
13
11
|
from .diaglayers.functionalgroup import FunctionalGroup
|
14
12
|
from .diaglayers.protocol import Protocol
|
15
|
-
from .element import IdentifiableElement
|
16
|
-
from .exceptions import odxrequire
|
17
13
|
from .nameditemlist import NamedItemList
|
14
|
+
from .odxcategory import OdxCategory
|
18
15
|
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
|
19
|
-
from .
|
16
|
+
from .snrefcontext import SnRefContext
|
20
17
|
from .utils import dataclass_fields_asdict
|
21
18
|
|
22
19
|
if TYPE_CHECKING:
|
@@ -24,15 +21,12 @@ if TYPE_CHECKING:
|
|
24
21
|
|
25
22
|
|
26
23
|
@dataclass
|
27
|
-
class DiagLayerContainer(
|
28
|
-
admin_data: Optional[AdminData]
|
29
|
-
company_datas: NamedItemList[CompanyData]
|
24
|
+
class DiagLayerContainer(OdxCategory):
|
30
25
|
ecu_shared_datas: NamedItemList[EcuSharedData]
|
31
26
|
protocols: NamedItemList[Protocol]
|
32
27
|
functional_groups: NamedItemList[FunctionalGroup]
|
33
28
|
base_variants: NamedItemList[BaseVariant]
|
34
29
|
ecu_variants: NamedItemList[EcuVariant]
|
35
|
-
sdgs: List[SpecialDataGroup]
|
36
30
|
|
37
31
|
@property
|
38
32
|
def ecus(self) -> NamedItemList[EcuVariant]:
|
@@ -54,17 +48,10 @@ class DiagLayerContainer(IdentifiableElement):
|
|
54
48
|
def from_et(et_element: ElementTree.Element,
|
55
49
|
doc_frags: List[OdxDocFragment]) -> "DiagLayerContainer":
|
56
50
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
doc_frags = [OdxDocFragment(short_name, "CONTAINER")]
|
61
|
-
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
|
51
|
+
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="CONTAINER")
|
52
|
+
doc_frags = cat.odx_id.doc_fragments
|
53
|
+
kwargs = dataclass_fields_asdict(cat)
|
62
54
|
|
63
|
-
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
|
64
|
-
company_datas = NamedItemList([
|
65
|
-
CompanyData.from_et(cde, doc_frags)
|
66
|
-
for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA")
|
67
|
-
])
|
68
55
|
ecu_shared_datas = NamedItemList([
|
69
56
|
EcuSharedData.from_et(dl_element, doc_frags)
|
70
57
|
for dl_element in et_element.iterfind("ECU-SHARED-DATAS/ECU-SHARED-DATA")
|
@@ -85,30 +72,17 @@ class DiagLayerContainer(IdentifiableElement):
|
|
85
72
|
EcuVariant.from_et(dl_element, doc_frags)
|
86
73
|
for dl_element in et_element.iterfind("ECU-VARIANTS/ECU-VARIANT")
|
87
74
|
])
|
88
|
-
sdgs = [
|
89
|
-
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
|
90
|
-
]
|
91
75
|
|
92
76
|
return DiagLayerContainer(
|
93
|
-
admin_data=admin_data,
|
94
|
-
company_datas=company_datas,
|
95
77
|
ecu_shared_datas=ecu_shared_datas,
|
96
78
|
protocols=protocols,
|
97
79
|
functional_groups=functional_groups,
|
98
80
|
base_variants=base_variants,
|
99
81
|
ecu_variants=ecu_variants,
|
100
|
-
sdgs=sdgs,
|
101
82
|
**kwargs)
|
102
83
|
|
103
84
|
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
104
|
-
result =
|
105
|
-
|
106
|
-
if self.admin_data is not None:
|
107
|
-
result.update(self.admin_data._build_odxlinks())
|
108
|
-
for cd in self.company_datas:
|
109
|
-
result.update(cd._build_odxlinks())
|
110
|
-
for sdg in self.sdgs:
|
111
|
-
result.update(sdg._build_odxlinks())
|
85
|
+
result = super()._build_odxlinks()
|
112
86
|
|
113
87
|
for ecu_shared_data in self.ecu_shared_datas:
|
114
88
|
result.update(ecu_shared_data._build_odxlinks())
|
@@ -124,12 +98,7 @@ class DiagLayerContainer(IdentifiableElement):
|
|
124
98
|
return result
|
125
99
|
|
126
100
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
127
|
-
|
128
|
-
self.admin_data._resolve_odxlinks(odxlinks)
|
129
|
-
for cd in self.company_datas:
|
130
|
-
cd._resolve_odxlinks(odxlinks)
|
131
|
-
for sdg in self.sdgs:
|
132
|
-
sdg._resolve_odxlinks(odxlinks)
|
101
|
+
super()._resolve_odxlinks(odxlinks)
|
133
102
|
|
134
103
|
for ecu_shared_data in self.ecu_shared_datas:
|
135
104
|
ecu_shared_data._resolve_odxlinks(odxlinks)
|
@@ -143,6 +112,8 @@ class DiagLayerContainer(IdentifiableElement):
|
|
143
112
|
ecu_variant._resolve_odxlinks(odxlinks)
|
144
113
|
|
145
114
|
def _finalize_init(self, database: "Database", odxlinks: OdxLinkDatabase) -> None:
|
115
|
+
super()._finalize_init(database, odxlinks)
|
116
|
+
|
146
117
|
for ecu_shared_data in self.ecu_shared_datas:
|
147
118
|
ecu_shared_data._finalize_init(database, odxlinks)
|
148
119
|
for protocol in self.protocols:
|
@@ -154,6 +125,9 @@ class DiagLayerContainer(IdentifiableElement):
|
|
154
125
|
for ecu_variant in self.ecu_variants:
|
155
126
|
ecu_variant._finalize_init(database, odxlinks)
|
156
127
|
|
128
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
129
|
+
super()._resolve_snrefs(context)
|
130
|
+
|
157
131
|
@property
|
158
132
|
def diag_layers(self) -> NamedItemList[DiagLayer]:
|
159
133
|
return self._diag_layers
|
@@ -8,8 +8,6 @@ from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional
|
|
8
8
|
Union, cast)
|
9
9
|
from xml.etree import ElementTree
|
10
10
|
|
11
|
-
from deprecation import deprecated
|
12
|
-
|
13
11
|
from ..additionalaudience import AdditionalAudience
|
14
12
|
from ..admindata import AdminData
|
15
13
|
from ..comparaminstance import ComparamInstance
|
@@ -724,10 +722,6 @@ class HierarchyElement(DiagLayer):
|
|
724
722
|
|
725
723
|
return int(result)
|
726
724
|
|
727
|
-
@deprecated(details="use get_can_receive_id()") # type: ignore[misc]
|
728
|
-
def get_receive_id(self) -> Optional[int]:
|
729
|
-
return self.get_can_receive_id()
|
730
|
-
|
731
725
|
def get_can_send_id(self, protocol: Optional[Union[str, "Protocol"]] = None) -> Optional[int]:
|
732
726
|
"""CAN ID to which the ECU sends replies to diagnostic messages"""
|
733
727
|
|
@@ -753,10 +747,6 @@ class HierarchyElement(DiagLayer):
|
|
753
747
|
|
754
748
|
return int(result)
|
755
749
|
|
756
|
-
@deprecated(details="use get_can_send_id()") # type: ignore[misc]
|
757
|
-
def get_send_id(self) -> Optional[int]:
|
758
|
-
return self.get_can_send_id()
|
759
|
-
|
760
750
|
def get_can_func_req_id(self,
|
761
751
|
protocol: Optional[Union[str, "Protocol"]] = None) -> Optional[int]:
|
762
752
|
"""CAN Functional Request Id."""
|
odxtools/dopbase.py
CHANGED
@@ -16,10 +16,12 @@ from .utils import dataclass_fields_asdict
|
|
16
16
|
|
17
17
|
@dataclass
|
18
18
|
class DopBase(IdentifiableElement):
|
19
|
-
"""Base class for all
|
19
|
+
"""Base class for all (simple and complex) data object properties.
|
20
|
+
|
21
|
+
Any class that a parameter can reference via a DOP-REF (Simple
|
22
|
+
DOPs, structures, ...) inherits from this class. All DOPs objects
|
23
|
+
implement the `Codec` type protocol.
|
20
24
|
|
21
|
-
Any class that a parameter can reference via a DOP-REF should
|
22
|
-
inherit from this class.
|
23
25
|
"""
|
24
26
|
|
25
27
|
admin_data: Optional[AdminData]
|
odxtools/dtcdop.py
CHANGED
@@ -15,13 +15,59 @@ from .dopbase import DopBase
|
|
15
15
|
from .encodestate import EncodeState
|
16
16
|
from .exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
|
17
17
|
from .nameditemlist import NamedItemList
|
18
|
-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
|
18
|
+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
|
19
19
|
from .odxtypes import ParameterValue, odxstr_to_bool
|
20
20
|
from .physicaltype import PhysicalType
|
21
21
|
from .snrefcontext import SnRefContext
|
22
22
|
from .utils import dataclass_fields_asdict
|
23
23
|
|
24
24
|
|
25
|
+
@dataclass
|
26
|
+
class LinkedDtcDop:
|
27
|
+
not_inherited_dtc_snrefs: List[str]
|
28
|
+
dtc_dop_ref: OdxLinkRef
|
29
|
+
|
30
|
+
@property
|
31
|
+
def dtc_dop(self) -> "DtcDop":
|
32
|
+
return self._dtc_dop
|
33
|
+
|
34
|
+
@property
|
35
|
+
def short_name(self) -> str:
|
36
|
+
return self._dtc_dop.short_name
|
37
|
+
|
38
|
+
@property
|
39
|
+
def not_inherited_dtcs(self) -> NamedItemList[DiagnosticTroubleCode]:
|
40
|
+
return self._not_inherited_dtcs
|
41
|
+
|
42
|
+
@staticmethod
|
43
|
+
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "LinkedDtcDop":
|
44
|
+
not_inherited_dtc_snrefs = [
|
45
|
+
odxrequire(el.get("SHORT-NAME"))
|
46
|
+
for el in et_element.iterfind("NOT-INHERITED-DTC-SNREFS/"
|
47
|
+
"NOT-INHERITED-DTC-SNREF")
|
48
|
+
]
|
49
|
+
|
50
|
+
dtc_dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DTC-DOP-REF"), doc_frags))
|
51
|
+
|
52
|
+
return LinkedDtcDop(
|
53
|
+
not_inherited_dtc_snrefs=not_inherited_dtc_snrefs, dtc_dop_ref=dtc_dop_ref)
|
54
|
+
|
55
|
+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
|
56
|
+
return {}
|
57
|
+
|
58
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
59
|
+
self._dtc_dop = odxlinks.resolve(self.dtc_dop_ref, DtcDop)
|
60
|
+
|
61
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
62
|
+
dtc_dop = self._dtc_dop
|
63
|
+
not_inherited_dtcs = [
|
64
|
+
resolve_snref(ni_snref, dtc_dop.dtcs, DiagnosticTroubleCode)
|
65
|
+
for ni_snref in self.not_inherited_dtc_snrefs
|
66
|
+
]
|
67
|
+
|
68
|
+
self._not_inherited_dtcs = NamedItemList(not_inherited_dtcs)
|
69
|
+
|
70
|
+
|
25
71
|
@dataclass
|
26
72
|
class DtcDop(DopBase):
|
27
73
|
"""A DOP describing a diagnostic trouble code"""
|
@@ -30,9 +76,12 @@ class DtcDop(DopBase):
|
|
30
76
|
physical_type: PhysicalType
|
31
77
|
compu_method: CompuMethod
|
32
78
|
dtcs_raw: List[Union[DiagnosticTroubleCode, OdxLinkRef]]
|
33
|
-
|
79
|
+
linked_dtc_dops_raw: List[LinkedDtcDop]
|
34
80
|
is_visible_raw: Optional[bool]
|
35
81
|
|
82
|
+
def __post_init__(self) -> None:
|
83
|
+
self._init_finished = False
|
84
|
+
|
36
85
|
@staticmethod
|
37
86
|
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "DtcDop":
|
38
87
|
"""Reads a DTC-DOP."""
|
@@ -56,12 +105,10 @@ class DtcDop(DopBase):
|
|
56
105
|
elif dtc_proxy_elem.tag == "DTC-REF":
|
57
106
|
dtcs_raw.append(OdxLinkRef.from_et(dtc_proxy_elem, doc_frags))
|
58
107
|
|
59
|
-
|
60
|
-
|
61
|
-
OdxLinkRef.from_et(dtc_ref_elem, doc_frags)
|
108
|
+
linked_dtc_dops_raw = [
|
109
|
+
LinkedDtcDop.from_et(dtc_ref_elem, doc_frags)
|
62
110
|
for dtc_ref_elem in et_element.iterfind("LINKED-DTC-DOPS/"
|
63
|
-
"LINKED-DTC-DOP
|
64
|
-
"DTC-DOP-REF")
|
111
|
+
"LINKED-DTC-DOP")
|
65
112
|
]
|
66
113
|
is_visible_raw = odxstr_to_bool(et_element.get("IS-VISIBLE"))
|
67
114
|
|
@@ -70,7 +117,7 @@ class DtcDop(DopBase):
|
|
70
117
|
physical_type=physical_type,
|
71
118
|
compu_method=compu_method,
|
72
119
|
dtcs_raw=dtcs_raw,
|
73
|
-
|
120
|
+
linked_dtc_dops_raw=linked_dtc_dops_raw,
|
74
121
|
is_visible_raw=is_visible_raw,
|
75
122
|
**kwargs)
|
76
123
|
|
@@ -79,12 +126,12 @@ class DtcDop(DopBase):
|
|
79
126
|
return self._dtcs
|
80
127
|
|
81
128
|
@property
|
82
|
-
def
|
83
|
-
return self.
|
129
|
+
def linked_dtc_dops(self) -> NamedItemList[LinkedDtcDop]:
|
130
|
+
return self._linked_dtc_dops
|
84
131
|
|
85
132
|
@property
|
86
|
-
def
|
87
|
-
return self.
|
133
|
+
def is_visible(self) -> bool:
|
134
|
+
return self.is_visible_raw is True
|
88
135
|
|
89
136
|
@override
|
90
137
|
def decode_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
|
@@ -185,6 +232,9 @@ class DtcDop(DopBase):
|
|
185
232
|
if isinstance(dtc_proxy, DiagnosticTroubleCode):
|
186
233
|
odxlinks.update(dtc_proxy._build_odxlinks())
|
187
234
|
|
235
|
+
for linked_dtc_dop in self.linked_dtc_dops_raw:
|
236
|
+
odxlinks.update(linked_dtc_dop._build_odxlinks())
|
237
|
+
|
188
238
|
return odxlinks
|
189
239
|
|
190
240
|
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
@@ -201,10 +251,19 @@ class DtcDop(DopBase):
|
|
201
251
|
dtc = odxlinks.resolve(dtc_proxy, DiagnosticTroubleCode)
|
202
252
|
self._dtcs.append(dtc)
|
203
253
|
|
204
|
-
|
205
|
-
|
254
|
+
for linked_dtc_dop in self.linked_dtc_dops_raw:
|
255
|
+
linked_dtc_dop._resolve_odxlinks(odxlinks)
|
206
256
|
|
207
257
|
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
258
|
+
# hack to avoid initializing the DtcDop object multiple
|
259
|
+
# times. This is required, because the linked DTC DOP feature
|
260
|
+
# requires the "parent" DTC DOPs to be fully initialized but
|
261
|
+
# the standard does not define a formal ordering of DTC DOPs.
|
262
|
+
if self._init_finished:
|
263
|
+
return
|
264
|
+
|
265
|
+
self._init_finished = True
|
266
|
+
|
208
267
|
super()._resolve_snrefs(context)
|
209
268
|
|
210
269
|
self.compu_method._resolve_snrefs(context)
|
@@ -212,3 +271,31 @@ class DtcDop(DopBase):
|
|
212
271
|
for dtc_proxy in self.dtcs_raw:
|
213
272
|
if isinstance(dtc_proxy, DiagnosticTroubleCode):
|
214
273
|
dtc_proxy._resolve_snrefs(context)
|
274
|
+
|
275
|
+
for linked_dtc_dop in self.linked_dtc_dops_raw:
|
276
|
+
linked_dtc_dop._resolve_snrefs(context)
|
277
|
+
|
278
|
+
# add the inherited DTCs from linked DTC DOPs. Note that this
|
279
|
+
# requires that there are no cycles in the "link-hierarchy"
|
280
|
+
dtc_short_names = {dtc.short_name for dtc in self._dtcs}
|
281
|
+
for linked_dtc_dop in self.linked_dtc_dops_raw:
|
282
|
+
linked_dtc_dop.dtc_dop._resolve_snrefs(context)
|
283
|
+
|
284
|
+
for dtc in linked_dtc_dop.dtc_dop.dtcs:
|
285
|
+
if dtc.short_name in dtc_short_names:
|
286
|
+
# we already have a DTC with that name. Since we
|
287
|
+
# are not supposed to overwrite the local DTCs, we
|
288
|
+
# skip processing this one. TODO: Are inheritance
|
289
|
+
# conflicts for DTCs allowed?
|
290
|
+
continue
|
291
|
+
|
292
|
+
if dtc.short_name in linked_dtc_dop.not_inherited_dtc_snrefs:
|
293
|
+
# DTC is explicitly not inherited
|
294
|
+
continue
|
295
|
+
|
296
|
+
self._dtcs.append(dtc)
|
297
|
+
dtc_short_names.add(dtc.short_name)
|
298
|
+
|
299
|
+
# at this place, the linked DTC DOPs exhibit .short_name, so
|
300
|
+
# we can create a NamedItemList...
|
301
|
+
self._linked_dtc_dops = NamedItemList(self.linked_dtc_dops_raw)
|
odxtools/inputparam.py
CHANGED
@@ -3,8 +3,6 @@ from dataclasses import dataclass
|
|
3
3
|
from typing import Any, Dict, List, Optional
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
|
-
from deprecation import deprecated
|
7
|
-
|
8
6
|
from .dopbase import DopBase
|
9
7
|
from .element import NamedElement
|
10
8
|
from .exceptions import odxrequire
|
@@ -49,8 +47,3 @@ class InputParam(NamedElement):
|
|
49
47
|
def dop_base(self) -> DopBase:
|
50
48
|
"""The data object property describing this parameter."""
|
51
49
|
return self._dop_base
|
52
|
-
|
53
|
-
@property
|
54
|
-
@deprecated(details="use .dop_base") # type: ignore[misc]
|
55
|
-
def dop(self) -> DopBase:
|
56
|
-
return self._dop_base
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# SPDX-License-Identifier: MIT
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import List
|
3
|
+
from typing import List
|
4
4
|
from xml.etree import ElementTree
|
5
5
|
|
6
6
|
from typing_extensions import override
|
@@ -50,13 +50,6 @@ class LeadingLengthInfoType(DiagCodedType):
|
|
50
50
|
def dct_type(self) -> DctType:
|
51
51
|
return "LEADING-LENGTH-INFO-TYPE"
|
52
52
|
|
53
|
-
def get_static_bit_length(self) -> Optional[int]:
|
54
|
-
# note that self.bit_length is just the length of the length
|
55
|
-
# specifier field. This is then followed by the same number of
|
56
|
-
# bytes as the value of this field, i.e., the length of this
|
57
|
-
# DCT is dynamic!
|
58
|
-
return None
|
59
|
-
|
60
53
|
@override
|
61
54
|
def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeState) -> None:
|
62
55
|
|
odxtools/message.py
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from typing import TYPE_CHECKING, Union
|
4
4
|
|
5
|
-
from deprecation import deprecated
|
6
|
-
|
7
5
|
from .odxtypes import ParameterValue, ParameterValueDict
|
8
6
|
|
9
7
|
if TYPE_CHECKING:
|
@@ -29,8 +27,3 @@ class Message:
|
|
29
27
|
|
30
28
|
def __getitem__(self, key: str) -> ParameterValue:
|
31
29
|
return self.param_dict[key]
|
32
|
-
|
33
|
-
@property
|
34
|
-
@deprecated("use .coding_object") # type: ignore[misc]
|
35
|
-
def structure(self) -> Union["Request", "Response"]:
|
36
|
-
return self.coding_object
|
odxtools/minmaxlengthtype.py
CHANGED
@@ -20,6 +20,10 @@ class MinMaxLengthType(DiagCodedType):
|
|
20
20
|
max_length: Optional[int]
|
21
21
|
termination: str
|
22
22
|
|
23
|
+
@property
|
24
|
+
def dct_type(self) -> DctType:
|
25
|
+
return "MIN-MAX-LENGTH-TYPE"
|
26
|
+
|
23
27
|
@staticmethod
|
24
28
|
@override
|
25
29
|
def from_et(et_element: ElementTree.Element,
|
@@ -50,10 +54,6 @@ class MinMaxLengthType(DiagCodedType):
|
|
50
54
|
"END-OF-PDU",
|
51
55
|
], f"A min-max length type cannot have the termination {self.termination}")
|
52
56
|
|
53
|
-
@property
|
54
|
-
def dct_type(self) -> DctType:
|
55
|
-
return "MIN-MAX-LENGTH-TYPE"
|
56
|
-
|
57
57
|
def __termination_sequence(self) -> bytes:
|
58
58
|
"""Returns the termination byte sequence if it isn't defined."""
|
59
59
|
# The termination sequence is actually not specified by ASAM
|