Skip to content

Commit 09dbf18

Browse files
authored
Merge pull request #383 from andlaus/table_row_fixes
TableRow: bring it in line with the spec
2 parents 90dc288 + 6891686 commit 09dbf18

File tree

4 files changed

+176
-8
lines changed

4 files changed

+176
-8
lines changed

examples/somersaultecu.py

+32
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,14 @@ class SomersaultSID(IntEnum):
13661366
oid=None,
13671367
short_name="none",
13681368
long_name="No Flips Done Yet",
1369+
audience=None,
1370+
functional_class_refs=[],
1371+
admin_data=None,
1372+
state_transition_refs=[],
1373+
pre_condition_state_refs=[],
1374+
is_executable_raw=None,
1375+
is_mandatory_raw=None,
1376+
is_final_raw=None,
13691377
key_raw="0",
13701378
structure_ref=None,
13711379
structure_snref=None,
@@ -1382,6 +1390,14 @@ class SomersaultSID(IntEnum):
13821390
oid=None,
13831391
short_name="forward_grudging",
13841392
long_name="Forward Flips Grudgingly Done",
1393+
audience=None,
1394+
functional_class_refs=[],
1395+
admin_data=None,
1396+
state_transition_refs=[],
1397+
pre_condition_state_refs=[],
1398+
is_executable_raw=None,
1399+
is_mandatory_raw=None,
1400+
is_final_raw=None,
13851401
key_raw="3",
13861402
structure_ref=OdxLinkRef.from_id(
13871403
somersault_structures["forward_flips_grudgingly_done"].odx_id),
@@ -1400,6 +1416,14 @@ class SomersaultSID(IntEnum):
14001416
short_name="forward_happily",
14011417
long_name="Forward Flips Happily Done",
14021418
description=None,
1419+
audience=None,
1420+
functional_class_refs=[],
1421+
admin_data=None,
1422+
state_transition_refs=[],
1423+
pre_condition_state_refs=[],
1424+
is_executable_raw=None,
1425+
is_mandatory_raw=None,
1426+
is_final_raw=None,
14031427
semantic=None,
14041428
key_raw="5",
14051429
structure_ref=OdxLinkRef.from_id(
@@ -1416,6 +1440,14 @@ class SomersaultSID(IntEnum):
14161440
short_name="backward_grudging",
14171441
long_name="Backward Flips",
14181442
description=None,
1443+
audience=None,
1444+
functional_class_refs=[],
1445+
admin_data=None,
1446+
state_transition_refs=[],
1447+
pre_condition_state_refs=[],
1448+
is_executable_raw=None,
1449+
is_mandatory_raw=None,
1450+
is_final_raw=None,
14191451
semantic=None,
14201452
key_raw="10",
14211453
structure_ref=OdxLinkRef.from_id(

odxtools/tablerow.py

+91-8
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@
33
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
44
from xml.etree import ElementTree
55

6+
from .admindata import AdminData
7+
from .audience import Audience
68
from .basicstructure import BasicStructure
79
from .dataobjectproperty import DataObjectProperty
810
from .dtcdop import DtcDop
911
from .element import IdentifiableElement
1012
from .exceptions import odxassert, odxraise, odxrequire
13+
from .functionalclass import FunctionalClass
14+
from .nameditemlist import NamedItemList
1115
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
12-
from .odxtypes import AtomicOdxType
16+
from .odxtypes import AtomicOdxType, odxstr_to_bool
1317
from .snrefcontext import SnRefContext
1418
from .specialdatagroup import SpecialDataGroup
19+
from .state import State
20+
from .statetransition import StateTransition
1521
from .utils import dataclass_fields_asdict
1622

1723
if TYPE_CHECKING:
@@ -21,18 +27,52 @@
2127
@dataclass
2228
class TableRow(IdentifiableElement):
2329
"""This class represents a TABLE-ROW."""
24-
table_ref: OdxLinkRef
2530
key_raw: str
26-
structure_ref: Optional[OdxLinkRef]
27-
structure_snref: Optional[str]
31+
table_ref: OdxLinkRef
2832

29-
# the referenced DOP must be a simple DOP (i.e.,
30-
# DataObjectProperty or DtcDop, cf section 7.3.6.11 of the spec)!
33+
# The spec mandates that either a structure or a non-complex DOP
34+
# must be referenced here, i.e., exactly one of the four
35+
# attributes below is not None
3136
dop_ref: Optional[OdxLinkRef]
3237
dop_snref: Optional[str]
38+
structure_ref: Optional[OdxLinkRef]
39+
structure_snref: Optional[str]
3340

34-
semantic: Optional[str]
3541
sdgs: List[SpecialDataGroup]
42+
audience: Optional[Audience]
43+
functional_class_refs: List[OdxLinkRef]
44+
state_transition_refs: List[OdxLinkRef]
45+
pre_condition_state_refs: List[OdxLinkRef]
46+
admin_data: Optional[AdminData]
47+
48+
is_executable_raw: Optional[bool]
49+
semantic: Optional[str]
50+
is_mandatory_raw: Optional[bool]
51+
is_final_raw: Optional[bool]
52+
53+
@property
54+
def functional_classes(self) -> NamedItemList[FunctionalClass]:
55+
return self._functional_classes
56+
57+
@property
58+
def state_transitions(self) -> NamedItemList[StateTransition]:
59+
return self._state_transitions
60+
61+
@property
62+
def pre_condition_states(self) -> NamedItemList[State]:
63+
return self._pre_condition_states
64+
65+
@property
66+
def is_executable(self) -> bool:
67+
return self.is_executable_raw in (None, True)
68+
69+
@property
70+
def is_mandatory(self) -> bool:
71+
return self.is_mandatory_raw is True
72+
73+
@property
74+
def is_final(self) -> bool:
75+
return self.is_final_raw is True
3676

3777
def __post_init__(self) -> None:
3878
self._structure: Optional[BasicStructure] = None
@@ -73,15 +113,49 @@ def tablerow_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFrag
73113
SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
74114
]
75115

116+
audience = None
117+
if (audience_elem := et_element.find("AUDIENCE")) is not None:
118+
audience = Audience.from_et(audience_elem, doc_frags)
119+
120+
functional_class_refs = [
121+
odxrequire(OdxLinkRef.from_et(el, doc_frags))
122+
for el in et_element.iterfind("FUNCT-CLASS-REFS/FUNCT-CLASS-REF")
123+
]
124+
125+
state_transition_refs = [
126+
odxrequire(OdxLinkRef.from_et(el, doc_frags))
127+
for el in et_element.iterfind("STATE-TRANSITION-REFS/STATE-TRANSITION-REF")
128+
]
129+
130+
pre_condition_state_refs = [
131+
odxrequire(OdxLinkRef.from_et(el, doc_frags))
132+
for el in et_element.iterfind("PRE-CONDITION-STATE-REFS/PRE-CONDITION-STATE-REF")
133+
]
134+
135+
admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
136+
137+
is_executable_raw = odxstr_to_bool(et_element.attrib.get("IS-EXECUTABLE"))
138+
semantic = et_element.attrib.get("SEMANTIC")
139+
is_mandatory_raw = odxstr_to_bool(et_element.attrib.get("IS-MANDATORY"))
140+
is_final_raw = odxstr_to_bool(et_element.attrib.get("IS-FINAL"))
141+
76142
return TableRow(
77143
table_ref=table_ref,
78-
semantic=semantic,
79144
key_raw=key_raw,
80145
structure_ref=structure_ref,
81146
structure_snref=structure_snref,
82147
dop_ref=dop_ref,
83148
dop_snref=dop_snref,
84149
sdgs=sdgs,
150+
audience=audience,
151+
functional_class_refs=functional_class_refs,
152+
state_transition_refs=state_transition_refs,
153+
pre_condition_state_refs=pre_condition_state_refs,
154+
admin_data=admin_data,
155+
is_executable_raw=is_executable_raw,
156+
semantic=semantic,
157+
is_mandatory_raw=is_mandatory_raw,
158+
is_final_raw=is_final_raw,
85159
**kwargs)
86160

87161
def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
@@ -108,6 +182,15 @@ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
108182
for sdg in self.sdgs:
109183
sdg._resolve_odxlinks(odxlinks)
110184

185+
self._functional_classes = NamedItemList(
186+
[odxlinks.resolve(fc_ref, FunctionalClass) for fc_ref in self.functional_class_refs])
187+
188+
self._state_transitions = NamedItemList(
189+
[odxlinks.resolve(st_ref, StateTransition) for st_ref in self.state_transition_refs])
190+
191+
self._pre_condition_states = NamedItemList(
192+
[odxlinks.resolve(pcs_ref, State) for pcs_ref in self.pre_condition_state_refs])
193+
111194
def _resolve_snrefs(self, context: SnRefContext) -> None:
112195
# convert the raw key into the proper internal
113196
# representation. note that we cannot do this earlier because

odxtools/templates/macros/printTable.xml.jinja2

+29
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
{%- import('macros/printElementId.xml.jinja2') as peid %}
77
{%- import('macros/printSpecialData.xml.jinja2') as psd %}
88
{%- import('macros/printDescription.xml.jinja2') as pd %}
9+
{%- import('macros/printAdminData.xml.jinja2') as pad %}
10+
{%- import('macros/printAudience.xml.jinja2') as paud %}
911

1012
{%- macro printTable(table) %}
1113
<TABLE {{-peid.printElementIdAttribs(table)}}
@@ -31,6 +33,33 @@
3133
<STRUCTURE-REF ID-REF="{{ table_row.structure_ref.ref_id }}" />
3234
{%- endif %}
3335
{{- psd.printSpecialDataGroups(table_row.sdgs)|indent(2, first=True) }}
36+
{%- if table_row.audience is not none %}
37+
{{ paud.printAudience(table_row.audience) | indent(2) }}
38+
{%- endif %}
39+
{%- if table_row.functional_class_refs %}
40+
<FUNCT-CLASS-REFS>
41+
{%- for fc_ref in table_row.functional_class_refs %}
42+
<FUNCT-CLASS-REF ID-REF="{{ fc_ref.ref_id }}" />
43+
{%- endfor %}
44+
</FUNCT-CLASS-REFS>
45+
{%- endif %}
46+
{%- if table_row.state_transition_refs %}
47+
<STATE-TRANSITION-REFS>
48+
{%- for st_ref in table_row.state_transition_refs %}
49+
<STATE-TRANSITION-REF ID-REF="{{ st_ref.ref_id }}" />
50+
{%- endfor %}
51+
</STATE-TRANSITION-REFS>
52+
{%- endif %}
53+
{%- if table_row.pre_condition_state_refs %}
54+
<PRE-CONDITION-STATE-REFS>
55+
{%- for pcs_ref in table_row.pre_condition_state_refs %}
56+
<PRE-CONDITION-STATE-REF ID-REF="{{ pcs_ref.ref_id }}" />
57+
{%- endfor %}
58+
</PRE-CONDITION-STATE-REFS>
59+
{%- endif %}
60+
{%- if table_row.admin_data is not none %}
61+
{{ pad.printAdminData(table_row.admin_data)|indent(2) }}
62+
{%- endif %}
3463
</TABLE-ROW>
3564
{%- else %}
3665
<TABLE-ROW-REF ID-REF="{{ table_row.ref_id }}" />

tests/test_diag_data_dictionary_spec.py

+24
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ def test_initialization(self) -> None:
134134
short_name="average",
135135
long_name="Average",
136136
description=None,
137+
audience=None,
138+
functional_class_refs=[],
139+
admin_data=None,
140+
state_transition_refs=[],
141+
pre_condition_state_refs=[],
142+
is_executable_raw=None,
143+
is_mandatory_raw=None,
144+
is_final_raw=None,
137145
semantic=None,
138146
dop_ref=None,
139147
dop_snref=None,
@@ -149,6 +157,14 @@ def test_initialization(self) -> None:
149157
short_name="good",
150158
long_name="Good",
151159
description=None,
160+
audience=None,
161+
functional_class_refs=[],
162+
admin_data=None,
163+
state_transition_refs=[],
164+
pre_condition_state_refs=[],
165+
is_executable_raw=None,
166+
is_mandatory_raw=None,
167+
is_final_raw=None,
152168
semantic=None,
153169
dop_ref=None,
154170
dop_snref=None,
@@ -164,6 +180,14 @@ def test_initialization(self) -> None:
164180
short_name="best",
165181
long_name="Best",
166182
description=None,
183+
audience=None,
184+
functional_class_refs=[],
185+
admin_data=None,
186+
state_transition_refs=[],
187+
pre_condition_state_refs=[],
188+
is_executable_raw=None,
189+
is_mandatory_raw=None,
190+
is_final_raw=None,
167191
semantic=None,
168192
dop_ref=None,
169193
dop_snref=None,

0 commit comments

Comments
 (0)