Skip to content

Commit 9e986a6

Browse files
authored
Merge pull request #388 from andlaus/implement_fringe_features
Implement some fringe features
2 parents 808a2fa + 90b7091 commit 9e986a6

13 files changed

+245
-13
lines changed

examples/mksomersaultmodifiedpdx.py

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ def find_named_object(item_list: List[T], name: str) -> T:
193193
neg_response_refs=[
194194
OdxLinkRef.from_id(somersaultecu.somersault_negative_responses["general"].odx_id),
195195
],
196+
pos_response_suppressible=None,
196197
sdgs=[],
197198
)
198199

examples/somersaultecu.py

+10
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,7 @@ class SomersaultSID(IntEnum):
14711471
sdgs=[],
14721472
),
14731473
],
1474+
table_diag_comm_connectors=[],
14741475
sdgs=[],
14751476
)
14761477
}
@@ -1825,6 +1826,7 @@ class SomersaultSID(IntEnum):
18251826
neg_response_refs=[
18261827
OdxLinkRef.from_id(somersault_negative_responses["general"].odx_id),
18271828
],
1829+
pos_response_suppressible=None,
18281830
functional_class_refs=[
18291831
OdxLinkRef.from_id(somersault_functional_classes["session"].odx_id),
18301832
],
@@ -1860,6 +1862,7 @@ class SomersaultSID(IntEnum):
18601862
neg_response_refs=[
18611863
OdxLinkRef.from_id(somersault_negative_responses["general"].odx_id),
18621864
],
1865+
pos_response_suppressible=None,
18631866
functional_class_refs=[
18641867
OdxLinkRef.from_id(somersault_functional_classes["session"].odx_id)
18651868
],
@@ -1907,6 +1910,7 @@ class SomersaultSID(IntEnum):
19071910
neg_response_refs=[
19081911
OdxLinkRef.from_id(somersault_negative_responses["tester_nok"].odx_id),
19091912
],
1913+
pos_response_suppressible=None,
19101914
sdgs=[],
19111915
),
19121916
"set_operation_params":
@@ -1940,6 +1944,7 @@ class SomersaultSID(IntEnum):
19401944
neg_response_refs=[
19411945
OdxLinkRef.from_id(somersault_negative_responses["general"].odx_id),
19421946
],
1947+
pos_response_suppressible=None,
19431948
sdgs=[],
19441949
),
19451950
"forward_flips":
@@ -1989,6 +1994,7 @@ class SomersaultSID(IntEnum):
19891994
# OdxLinkRef.from_id(somersault_negative_responses["too_dizzy"].odx_id),
19901995
# OdxLinkRef.from_id(somersault_negative_responses["not_sober"].odx_id),
19911996
],
1997+
pos_response_suppressible=None,
19921998
functional_class_refs=[
19931999
OdxLinkRef.from_id(somersault_functional_classes["flip"].odx_id)
19942000
],
@@ -2035,6 +2041,7 @@ class SomersaultSID(IntEnum):
20352041
neg_response_refs=[
20362042
OdxLinkRef.from_id(somersault_negative_responses["flips_not_done"].odx_id),
20372043
],
2044+
pos_response_suppressible=None,
20382045
functional_class_refs=[
20392046
OdxLinkRef.from_id(somersault_functional_classes["flip"].odx_id)
20402047
],
@@ -2081,6 +2088,7 @@ class SomersaultSID(IntEnum):
20812088
neg_response_refs=[
20822089
OdxLinkRef.from_id(somersault_negative_responses["general"].odx_id),
20832090
],
2091+
pos_response_suppressible=None,
20842092
sdgs=[],
20852093
),
20862094
"schroedinger":
@@ -2109,6 +2117,7 @@ class SomersaultSID(IntEnum):
21092117
semantic="ROUTINE",
21102118
pos_response_refs=[],
21112119
neg_response_refs=[],
2120+
pos_response_suppressible=None,
21122121
functional_class_refs=[],
21132122
sdgs=[],
21142123
),
@@ -2615,6 +2624,7 @@ class SomersaultSID(IntEnum):
26152624
neg_response_refs=[
26162625
OdxLinkRef.from_id(somersault_assiduous_negative_responses["fell_over"].odx_id),
26172626
],
2627+
pos_response_suppressible=None,
26182628
comparam_refs=[],
26192629
is_cyclic_raw=None,
26202630
is_multiple_raw=None,

odxtools/description.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,27 @@
66
from .odxlink import OdxDocFragment
77

88

9+
@dataclass
10+
class ExternalDoc:
11+
description: Optional[str]
12+
href: str
13+
14+
@staticmethod
15+
def from_et(et_element: Optional[ElementTree.Element],
16+
doc_frags: List[OdxDocFragment]) -> Optional["ExternalDoc"]:
17+
if et_element is None:
18+
return None
19+
20+
description = et_element.text
21+
href = odxrequire(et_element.get("HREF"))
22+
23+
return ExternalDoc(description=description, href=href)
24+
25+
926
@dataclass
1027
class Description:
1128
text: str
12-
external_docs: List[str]
29+
external_docs: List[ExternalDoc]
1330
text_identifier: Optional[str]
1431

1532
@staticmethod
@@ -35,7 +52,7 @@ def from_et(et_element: Optional[ElementTree.Element],
3552

3653
external_docs = \
3754
[
38-
odxrequire(ed.get("HREF")) for ed in et_element.iterfind("EXTERNAL-DOCS/EXTERNAL-DOC")
55+
odxrequire(ExternalDoc.from_et(ed, doc_frags)) for ed in et_element.iterfind("EXTERNAL-DOCS/EXTERNAL-DOC")
3956
]
4057
return Description(text=text, text_identifier=text_identifier, external_docs=external_docs)
4158

odxtools/diagservice.py

+70-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,71 @@ class TransMode(Enum):
3131
SEND_OR_RECEIVE = "SEND-OR-RECEIVE"
3232

3333

34+
# note that the spec has a typo here: it calls the corresponding
35+
# XML tag POS-RESPONSE-SUPPRESSABLE...
36+
@dataclass
37+
class PosResponseSuppressible:
38+
bit_mask: int
39+
40+
coded_const_snref: Optional[str]
41+
coded_const_snpathref: Optional[str]
42+
43+
value_snref: Optional[str]
44+
value_snpathref: Optional[str]
45+
46+
phys_const_snref: Optional[str]
47+
phys_const_snpathref: Optional[str]
48+
49+
table_key_snref: Optional[str]
50+
table_key_snpathref: Optional[str]
51+
52+
@staticmethod
53+
def from_et(et_element: ElementTree.Element,
54+
doc_frags: List[OdxDocFragment]) -> "PosResponseSuppressible":
55+
56+
bit_mask = int(odxrequire(et_element.findtext("BITMASK")))
57+
58+
coded_const_snref = None
59+
if (cc_snref_elem := et_element.find("CODED-CONST-SNREF")) is not None:
60+
coded_const_snref = cc_snref_elem.attrib["SHORT-NAME"]
61+
coded_const_snpathref = None
62+
if (cc_snpathref_elem := et_element.find("CODED-CONST-SNPATHREF")) is not None:
63+
coded_const_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
64+
65+
value_snref = None
66+
if (cc_snref_elem := et_element.find("VALUE-SNREF")) is not None:
67+
value_snref = cc_snref_elem.attrib["SHORT-NAME"]
68+
value_snpathref = None
69+
if (cc_snpathref_elem := et_element.find("VALUE-SNPATHREF")) is not None:
70+
value_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
71+
72+
phys_const_snref = None
73+
if (cc_snref_elem := et_element.find("PHYS-CONST-SNREF")) is not None:
74+
phys_const_snref = cc_snref_elem.attrib["SHORT-NAME"]
75+
phys_const_snpathref = None
76+
if (cc_snpathref_elem := et_element.find("PHYS-CONST-SNPATHREF")) is not None:
77+
phys_const_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
78+
79+
table_key_snref = None
80+
if (cc_snref_elem := et_element.find("TABLE-KEY-SNREF")) is not None:
81+
table_key_snref = cc_snref_elem.attrib["SHORT-NAME"]
82+
table_key_snpathref = None
83+
if (cc_snpathref_elem := et_element.find("TABLE-KEY-SNPATHREF")) is not None:
84+
table_key_snpathref = cc_snpathref_elem.attrib["SHORT-NAME-PATH"]
85+
86+
return PosResponseSuppressible(
87+
bit_mask=bit_mask,
88+
coded_const_snref=coded_const_snref,
89+
coded_const_snpathref=coded_const_snpathref,
90+
value_snref=value_snref,
91+
value_snpathref=value_snpathref,
92+
phys_const_snref=phys_const_snref,
93+
phys_const_snpathref=phys_const_snpathref,
94+
table_key_snref=table_key_snref,
95+
table_key_snpathref=table_key_snpathref,
96+
)
97+
98+
3499
@dataclass
35100
class DiagService(DiagComm):
36101
"""Representation of a diagnostic service description.
@@ -42,9 +107,7 @@ class DiagService(DiagComm):
42107
pos_response_refs: List[OdxLinkRef]
43108
neg_response_refs: List[OdxLinkRef]
44109

45-
# note that the spec has a typo here: it calls the corresponding
46-
# XML tag POS-RESPONSE-SUPPRESSABLE...
47-
# TODO: pos_response_suppressible: Optional[PosResponseSuppressible]
110+
pos_response_suppressible: Optional[PosResponseSuppressible]
48111

49112
is_cyclic_raw: Optional[bool]
50113
is_multiple_raw: Optional[bool]
@@ -73,7 +136,9 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
73136
for el in et_element.iterfind("NEG-RESPONSE-REFS/NEG-RESPONSE-REF")
74137
]
75138

76-
# TODO: POS-RESPONSE-SUPPRESSABLE
139+
pos_response_suppressible = None
140+
if (prs_elem := et_element.find("POS-RESPONSE-SUPPRESSABLE")) is not None:
141+
pos_response_suppressible = PosResponseSuppressible.from_et(prs_elem, doc_frags)
77142

78143
is_cyclic_raw = odxstr_to_bool(et_element.get("IS-CYCLIC"))
79144
is_multiple_raw = odxstr_to_bool(et_element.get("IS-MULTIPLE"))
@@ -99,6 +164,7 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
99164
request_ref=request_ref,
100165
pos_response_refs=pos_response_refs,
101166
neg_response_refs=neg_response_refs,
167+
pos_response_suppressible=pos_response_suppressible,
102168
is_cyclic_raw=is_cyclic_raw,
103169
is_multiple_raw=is_multiple_raw,
104170
addressing_raw=addressing_raw,

odxtools/statetransition.py

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: MIT
22
from dataclasses import dataclass
3-
from typing import Any, Dict, List
3+
from typing import Any, Dict, List, Optional
44
from xml.etree import ElementTree
55

66
from .element import IdentifiableElement
@@ -11,14 +11,28 @@
1111
from .utils import dataclass_fields_asdict
1212

1313

14+
@dataclass
15+
class ExternalAccessMethod(IdentifiableElement):
16+
method: str
17+
18+
@staticmethod
19+
def from_et(et_element: ElementTree.Element,
20+
doc_frags: List[OdxDocFragment]) -> "ExternalAccessMethod":
21+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
22+
23+
method = odxrequire(et_element.findtext("METHOD"))
24+
25+
return ExternalAccessMethod(method=method, **kwargs)
26+
27+
1428
@dataclass
1529
class StateTransition(IdentifiableElement):
1630
"""
1731
Corresponds to STATE-TRANSITION.
1832
"""
1933
source_snref: str
2034
target_snref: str
21-
# external_access_method: Optional[ExternalAccessMethod] # TODO
35+
external_access_method: Optional[ExternalAccessMethod]
2236

2337
@property
2438
def source_state(self) -> State:
@@ -40,7 +54,14 @@ def from_et(et_element: ElementTree.Element,
4054
target_snref_elem = odxrequire(et_element.find("TARGET-SNREF"))
4155
target_snref = odxrequire(target_snref_elem.attrib["SHORT-NAME"])
4256

43-
return StateTransition(source_snref=source_snref, target_snref=target_snref, **kwargs)
57+
external_access_method = None
58+
if (eam_elem := et_element.find("EXTERNAL-ACCESS-METHOD")) is not None:
59+
external_access_method = ExternalAccessMethod.from_et(eam_elem, doc_frags)
60+
return StateTransition(
61+
source_snref=source_snref,
62+
target_snref=target_snref,
63+
external_access_method=external_access_method,
64+
**kwargs)
4465

4566
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
4667
return {self.odx_id: self}

odxtools/table.py

+55-3
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,54 @@
55

66
from .admindata import AdminData
77
from .dataobjectproperty import DataObjectProperty
8+
from .diagcomm import DiagComm
89
from .element import IdentifiableElement
9-
from .exceptions import odxassert
10+
from .exceptions import odxassert, odxrequire
1011
from .nameditemlist import NamedItemList
11-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
12+
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
1213
from .snrefcontext import SnRefContext
1314
from .specialdatagroup import SpecialDataGroup
1415
from .tablerow import TableRow
1516
from .utils import dataclass_fields_asdict
1617

1718

19+
@dataclass
20+
class TableDiagCommConnector:
21+
semantic: str
22+
23+
diag_comm_ref: Optional[OdxLinkRef]
24+
diag_comm_snref: Optional[str]
25+
26+
@property
27+
def diag_comm(self) -> DiagComm:
28+
return self._diag_comm
29+
30+
@staticmethod
31+
def from_et(et_element: ElementTree.Element,
32+
doc_frags: List[OdxDocFragment]) -> "TableDiagCommConnector":
33+
34+
semantic = odxrequire(et_element.findtext("SEMANTIC"))
35+
diag_comm_ref = OdxLinkRef.from_et(et_element.find("DIAG-COMM-REF"), doc_frags)
36+
diag_comm_snref = None
37+
if (dc_snref_elem := et_element.find("DIAG-COMM-SNREF")) is not None:
38+
diag_comm_snref = odxrequire(dc_snref_elem.get("SHORT-NAME"))
39+
40+
return TableDiagCommConnector(
41+
semantic=semantic, diag_comm_ref=diag_comm_ref, diag_comm_snref=diag_comm_snref)
42+
43+
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
44+
return {}
45+
46+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
47+
if self.diag_comm_ref is not None:
48+
self._diag_comm = odxlinks.resolve(self.diag_comm_ref, DiagComm)
49+
50+
def _resolve_snrefs(self, context: SnRefContext) -> None:
51+
if self.diag_comm_snref is not None:
52+
dl = odxrequire(context.diag_layer)
53+
self._diag_comm = resolve_snref(self.diag_comm_snref, dl.diag_comms, DiagComm)
54+
55+
1856
@dataclass
1957
class Table(IdentifiableElement):
2058
"""This class represents a TABLE."""
@@ -24,7 +62,7 @@ class Table(IdentifiableElement):
2462
admin_data: Optional[AdminData]
2563
key_dop_ref: Optional[OdxLinkRef]
2664
table_rows_raw: List[Union[TableRow, OdxLinkRef]]
27-
# TODO: table_diag_comm_connectors
65+
table_diag_comm_connectors: List[TableDiagCommConnector]
2866
sdgs: List[SpecialDataGroup]
2967

3068
@staticmethod
@@ -47,6 +85,10 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
4785
elif sub_elem.tag == "TABLE-ROW-REF":
4886
table_rows_raw.append(OdxLinkRef.from_et(sub_elem, doc_frags))
4987

88+
table_diag_comm_connectors = [
89+
TableDiagCommConnector.from_et(dcc_elem, doc_frags) for dcc_elem in et_element.iterfind(
90+
"TABLE-DIAG-COMM-CONNECTORS/TABLE-DIAG-COMM-CONNECTOR")
91+
]
5092
sdgs = [
5193
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
5294
]
@@ -58,6 +100,7 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
58100
admin_data=admin_data,
59101
key_dop_ref=key_dop_ref,
60102
table_rows_raw=table_rows_raw,
103+
table_diag_comm_connectors=table_diag_comm_connectors,
61104
sdgs=sdgs,
62105
**kwargs)
63106

@@ -78,6 +121,9 @@ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
78121
if isinstance(table_row_wrapper, TableRow):
79122
result.update(table_row_wrapper._build_odxlinks())
80123

124+
for dcc in self.table_diag_comm_connectors:
125+
result.update(dcc._build_odxlinks())
126+
81127
return result
82128

83129
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
@@ -98,7 +144,13 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
98144

99145
self._table_rows = NamedItemList(table_rows)
100146

147+
for dcc in self.table_diag_comm_connectors:
148+
dcc._resolve_odxlinks(odxlinks)
149+
101150
def _resolve_snrefs(self, context: SnRefContext) -> None:
102151
for table_row_wrapper in self.table_rows_raw:
103152
if isinstance(table_row_wrapper, TableRow):
104153
table_row_wrapper._resolve_snrefs(context)
154+
155+
for dcc in self.table_diag_comm_connectors:
156+
dcc._resolve_snrefs(context)

0 commit comments

Comments
 (0)