Skip to content

Commit 8410ced

Browse files
authored
Merge pull request #384 from andlaus/more_enums
More enums
2 parents 1445384 + da958c8 commit 8410ced

21 files changed

+121
-82
lines changed

examples/somersaultecu.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from odxtools.functionalclass import FunctionalClass
4444
from odxtools.modification import Modification
4545
from odxtools.nameditemlist import NamedItemList
46-
from odxtools.odxlink import OdxDocFragment, OdxLinkId, OdxLinkRef
46+
from odxtools.odxlink import DocType, OdxDocFragment, OdxLinkId, OdxLinkRef
4747
from odxtools.odxtypes import DataType
4848
from odxtools.parameters.codedconstparameter import CodedConstParameter
4949
from odxtools.parameters.matchingrequestparameter import MatchingRequestParameter
@@ -90,12 +90,12 @@ class SomersaultSID(IntEnum):
9090
dlc_short_name = "somersault"
9191

9292
# document fragment for everything except the communication parameters
93-
doc_frags = [OdxDocFragment(dlc_short_name, "CONTAINER")]
93+
doc_frags = [OdxDocFragment(dlc_short_name, DocType.CONTAINER)]
9494

9595
# document fragments for communication parameters
96-
cp_dwcan_doc_frags = [OdxDocFragment("ISO_11898_2_DWCAN", "COMPARAM-SUBSET")]
97-
cp_iso15765_2_doc_frags = [OdxDocFragment("ISO_15765_2", "COMPARAM-SUBSET")]
98-
cp_iso15765_3_doc_frags = [OdxDocFragment("ISO_15765_3", "COMPARAM-SUBSET")]
96+
cp_dwcan_doc_frags = [OdxDocFragment("ISO_11898_2_DWCAN", DocType.COMPARAM_SUBSET)]
97+
cp_iso15765_2_doc_frags = [OdxDocFragment("ISO_15765_2", DocType.COMPARAM_SUBSET)]
98+
cp_iso15765_3_doc_frags = [OdxDocFragment("ISO_15765_3", DocType.COMPARAM_SUBSET)]
9999

100100
##################
101101
# Base variant of Somersault ECU
@@ -2358,8 +2358,9 @@ class SomersaultSID(IntEnum):
23582358
additional_audiences=NamedItemList(),
23592359
sdgs=[],
23602360
parent_refs=[],
2361-
comparam_spec_ref=OdxLinkRef("CPS_ISO_15765_3_on_ISO_15765_2",
2362-
[OdxDocFragment("ISO_15765_3_on_ISO_15765_2", "COMPARAM-SPEC")]),
2361+
comparam_spec_ref=OdxLinkRef("CPS_ISO_15765_3_on_ISO_15765_2", [
2362+
OdxDocFragment("ISO_15765_3_on_ISO_15765_2", DocType.COMPARAM_SPEC)
2363+
]),
23632364
comparam_refs=somersault_comparam_refs,
23642365
libraries=NamedItemList(),
23652366
prot_stack_snref=None,

odxtools/comparamspec.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from .nameditemlist import NamedItemList
77
from .odxcategory import OdxCategory
8-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8+
from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
99
from .protstack import ProtStack
1010
from .snrefcontext import SnRefContext
1111
from .utils import dataclass_fields_asdict
@@ -16,12 +16,13 @@
1616

1717
@dataclass
1818
class ComparamSpec(OdxCategory):
19+
1920
prot_stacks: NamedItemList[ProtStack]
2021

2122
@staticmethod
2223
def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ComparamSpec":
2324

24-
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="COMPARAM-SPEC")
25+
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type=DocType.COMPARAM_SPEC)
2526
doc_frags = cat.odx_id.doc_fragments
2627
kwargs = dataclass_fields_asdict(cat)
2728

odxtools/comparamsubset.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .dataobjectproperty import DataObjectProperty
99
from .nameditemlist import NamedItemList
1010
from .odxcategory import OdxCategory
11-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
11+
from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
1212
from .snrefcontext import SnRefContext
1313
from .unitspec import UnitSpec
1414
from .utils import dataclass_fields_asdict
@@ -19,19 +19,17 @@
1919

2020
@dataclass
2121
class ComparamSubset(OdxCategory):
22-
# mandatory in ODX 2.2, but non-existent in ODX 2.0
23-
category: Optional[str]
24-
2522
comparams: NamedItemList[Comparam]
2623
complex_comparams: NamedItemList[ComplexComparam]
2724
data_object_props: NamedItemList[DataObjectProperty]
2825
unit_spec: Optional[UnitSpec]
26+
category: Optional[str] # mandatory in ODX 2.2, but non-existent in ODX 2.0
2927

3028
@staticmethod
3129
def from_et(et_element: ElementTree.Element,
3230
doc_frags: List[OdxDocFragment]) -> "ComparamSubset":
3331

34-
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="COMPARAM-SUBSET")
32+
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type=DocType.COMPARAM_SUBSET)
3533
doc_frags = cat.odx_id.doc_fragments
3634
kwargs = dataclass_fields_asdict(cat)
3735

odxtools/diaglayercontainer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from .diaglayers.protocol import Protocol
1313
from .nameditemlist import NamedItemList
1414
from .odxcategory import OdxCategory
15-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
15+
from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
1616
from .snrefcontext import SnRefContext
1717
from .utils import dataclass_fields_asdict
1818

@@ -48,7 +48,7 @@ def __post_init__(self) -> None:
4848
def from_et(et_element: ElementTree.Element,
4949
doc_frags: List[OdxDocFragment]) -> "DiagLayerContainer":
5050

51-
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type="CONTAINER")
51+
cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type=DocType.CONTAINER)
5252
doc_frags = cat.odx_id.doc_fragments
5353
kwargs = dataclass_fields_asdict(cat)
5454

odxtools/diaglayers/diaglayerraw.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from ..functionalclass import FunctionalClass
1616
from ..library import Library
1717
from ..nameditemlist import NamedItemList
18-
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
18+
from ..odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
1919
from ..request import Request
2020
from ..response import Response
2121
from ..singleecujob import SingleEcuJob
@@ -81,7 +81,7 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
8181

8282
# extend the applicable ODX "document fragments" for the diag layer objects
8383
doc_frags = copy(doc_frags)
84-
doc_frags.append(OdxDocFragment(short_name, "LAYER"))
84+
doc_frags.append(OdxDocFragment(short_name, DocType.LAYER))
8585
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
8686

8787
admin_data = None

odxtools/minmaxlengthtype.py

+20-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: MIT
22
from dataclasses import dataclass
3-
from typing import List, Optional
3+
from enum import Enum
4+
from typing import List, Optional, cast
45
from xml.etree import ElementTree
56

67
from typing_extensions import override
@@ -15,11 +16,17 @@
1516
from .utils import dataclass_fields_asdict
1617

1718

19+
class Termination(Enum):
20+
END_OF_PDU = "END-OF-PDU"
21+
ZERO = "ZERO"
22+
HEX_FF = "HEX-FF"
23+
24+
1825
@dataclass
1926
class MinMaxLengthType(DiagCodedType):
2027
min_length: int
2128
max_length: Optional[int]
22-
termination: str
29+
termination: Termination
2330

2431
@property
2532
def dct_type(self) -> DctType:
@@ -35,7 +42,13 @@ def from_et(et_element: ElementTree.Element,
3542
max_length = None
3643
if et_element.find("MAX-LENGTH") is not None:
3744
max_length = int(odxrequire(et_element.findtext("MAX-LENGTH")))
38-
termination = odxrequire(et_element.get("TERMINATION"))
45+
46+
termination_str = odxrequire(et_element.get("TERMINATION"))
47+
try:
48+
termination = Termination(termination_str)
49+
except ValueError:
50+
termination = cast(Termination, None)
51+
odxraise(f"Encountered unknown termination type '{termination_str}'")
3952

4053
return MinMaxLengthType(
4154
min_length=min_length, max_length=max_length, termination=termination, **kwargs)
@@ -49,23 +62,18 @@ def __post_init__(self) -> None:
4962
DataType.A_UNICODE2STRING,
5063
DataType.A_UTF8STRING,
5164
], f"A min-max length type cannot have the base data type {self.base_data_type}.")
52-
odxassert(self.termination in [
53-
"ZERO",
54-
"HEX-FF",
55-
"END-OF-PDU",
56-
], f"A min-max length type cannot have the termination {self.termination}")
5765

5866
def __termination_sequence(self) -> bytes:
5967
"""Returns the termination byte sequence if it isn't defined."""
6068
# The termination sequence is actually not specified by ASAM
6169
# for A_BYTEFIELD but I assume it is only one byte.
6270
termination_sequence = b''
63-
if self.termination == "ZERO":
71+
if self.termination == Termination.ZERO:
6472
if self.base_data_type not in [DataType.A_UNICODE2STRING]:
6573
termination_sequence = bytes([0x0])
6674
else:
6775
termination_sequence = bytes([0x0, 0x0])
68-
elif self.termination == "HEX-FF":
76+
elif self.termination == Termination.HEX_FF:
6977
if self.base_data_type not in [DataType.A_UNICODE2STRING]:
7078
termination_sequence = bytes([0xFF])
7179
else:
@@ -121,7 +129,7 @@ def encode_into_pdu(self, internal_value: AtomicOdxType, encode_state: EncodeSta
121129
# encountered within the encoded value.
122130

123131
odxassert(
124-
self.termination != "END-OF-PDU" or encode_state.is_end_of_pdu,
132+
self.termination != Termination.END_OF_PDU or encode_state.is_end_of_pdu,
125133
"Encountered a MIN-MAX-LENGTH type with END-OF-PDU termination "
126134
"which is not located at the end of the PDU")
127135
if encode_state.is_end_of_pdu or data_length == self.max_length:
@@ -153,7 +161,7 @@ def decode_from_pdu(self, decode_state: DecodeState) -> AtomicOdxType:
153161
if self.max_length is not None:
154162
max_terminator_pos = min(max_terminator_pos, orig_cursor_pos + self.max_length)
155163

156-
if self.termination != "END-OF-PDU":
164+
if self.termination != Termination.END_OF_PDU:
157165
# The parameter either ends after the maximum length, at
158166
# the end of the PDU or if a termination sequence is
159167
# found.

odxtools/odxcategory.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .element import IdentifiableElement
99
from .exceptions import odxrequire
1010
from .nameditemlist import NamedItemList
11-
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
11+
from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
1212
from .snrefcontext import SnRefContext
1313
from .specialdatagroup import SpecialDataGroup
1414
from .utils import dataclass_fields_asdict
@@ -32,7 +32,7 @@ def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) ->
3232

3333
@staticmethod
3434
def category_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
35-
doc_type: str) -> "OdxCategory":
35+
doc_type: DocType) -> "OdxCategory":
3636

3737
short_name = odxrequire(et_element.findtext("SHORT-NAME"))
3838
# create the current ODX "document fragment" (description of the

odxtools/odxlink.py

+27-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
# SPDX-License-Identifier: MIT
22
import warnings
33
from dataclasses import dataclass
4+
from enum import Enum
45
from typing import Any, Dict, Iterable, List, Optional, Type, TypeVar, overload
56
from xml.etree import ElementTree
67

78
from .exceptions import OdxWarning, odxassert, odxraise, odxrequire
89
from .nameditemlist import OdxNamed, TNamed
910

1011

12+
class DocType(Enum):
13+
FLASH = "FLASH"
14+
CONTAINER = "CONTAINER"
15+
LAYER = "LAYER"
16+
MULTIPLE_ECU_JOB_SPEC = "MULTIPLE-ECU-JOB-SPEC"
17+
COMPARAM_SPEC = "COMPARAM-SPEC"
18+
VEHICLE_INFO_SPEC = "VEHICLE-INFO-SPEC"
19+
COMPARAM_SUBSET = "COMPARAM-SUBSET"
20+
ECU_CONFIG = "ECU-CONFIG"
21+
FUNCTION_DICTIONARY_SPEC = "FUNCTION-DICTIONARY-SPEC"
22+
23+
1124
@dataclass(frozen=True)
1225
class OdxDocFragment:
1326
doc_name: str
14-
doc_type: str
27+
doc_type: DocType
1528

1629

1730
@dataclass(frozen=True)
@@ -109,18 +122,25 @@ def from_et(et: Optional[ElementTree.Element],
109122
odxraise(f"Tag {et.tag} is not a ODXLINK reference")
110123
return None
111124

112-
doc_ref = et.attrib.get("DOCREF")
113-
doc_type = et.attrib.get("DOCTYPE")
125+
docref = et.attrib.get("DOCREF")
126+
doctype_attr = et.attrib.get("DOCTYPE")
114127

115-
odxassert((doc_ref is not None and doc_type is not None) or
116-
(doc_ref is None and doc_type is None),
128+
odxassert((docref is not None and doctype_attr is not None) or
129+
(docref is None and doctype_attr is None),
117130
"DOCREF and DOCTYPE must both either be specified or omitted")
118131

132+
doctype = None
133+
if doctype_attr is not None:
134+
try:
135+
doctype = DocType(doctype_attr)
136+
except ValueError:
137+
odxraise(f"Encountered unknown document type '{doctype_attr}'")
138+
119139
# if the target document fragment is specified by the
120140
# reference, use it, else use the document fragment containing
121141
# the reference.
122-
if doc_ref is not None:
123-
doc_frags = [OdxDocFragment(doc_ref, odxrequire(doc_type))]
142+
if docref is not None:
143+
doc_frags = [OdxDocFragment(docref, odxrequire(doctype))]
124144
else:
125145
doc_frags = source_doc_frags
126146

odxtools/parameters/tableentryparameter.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# SPDX-License-Identifier: MIT
22
from dataclasses import dataclass
3-
from typing import TYPE_CHECKING, List, Optional
3+
from enum import Enum
4+
from typing import TYPE_CHECKING, List, Optional, cast
45
from xml.etree import ElementTree
56

67
from typing_extensions import override
78

89
from ..decodestate import DecodeState
910
from ..encodestate import EncodeState
10-
from ..exceptions import odxrequire
11+
from ..exceptions import odxraise, odxrequire
1112
from ..odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkRef
1213
from ..odxtypes import ParameterValue
1314
from ..utils import dataclass_fields_asdict
@@ -17,9 +18,14 @@
1718
from ..tablerow import TableRow
1819

1920

21+
class RowFragment(Enum):
22+
KEY = "KEY"
23+
STRUCT = "STRUCT"
24+
25+
2026
@dataclass
2127
class TableEntryParameter(Parameter):
22-
target: str
28+
target: RowFragment
2329
table_row_ref: OdxLinkRef
2430

2531
@staticmethod
@@ -29,7 +35,12 @@ def from_et(et_element: ElementTree.Element,
2935

3036
kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
3137

32-
target = odxrequire(et_element.findtext("TARGET"))
38+
target_str = odxrequire(et_element.findtext("TARGET"))
39+
try:
40+
target = RowFragment(target_str)
41+
except ValueError:
42+
odxraise(f"Encountered unknown target '{target_str}'")
43+
target = cast(RowFragment, None)
3344
table_row_ref = odxrequire(OdxLinkRef.from_et(et_element.find("TABLE-ROW-REF"), doc_frags))
3445

3546
return TableEntryParameter(target=target, table_row_ref=table_row_ref, **kwargs)

odxtools/templates/macros/printDOP.xml.jinja2

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
{{-make_xml_attrib("BASE-TYPE-ENCODING", dct.base_type_encoding and dct.base_type_encoding.value)}}
1616
{{-make_bool_xml_attrib("IS-HIGHLOW-BYTE-ORDER", dct.is_highlow_byte_order_raw)}}
1717
{%- if dct.termination is defined %}
18-
{{-make_xml_attrib("TERMINATION", dct.termination)}}
18+
{{-make_xml_attrib("TERMINATION", dct.termination.value)}}
1919
{%- endif %}
2020
{#- #} xsi:type="{{dct.dct_type}}">
2121
{%- if dct.dct_type in ("STANDARD-LENGTH-TYPE", "LEADING-LENGTH-INFO-TYPE") %}

odxtools/templates/macros/printProtocol.xml.jinja2

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
{%- set dlr = protocol.protocol_raw %}
1414

1515
{%- set cps_docfrag = dlr.comparam_spec_ref.ref_docs[-1] %}
16-
<COMPARAM-SPEC-REF ID-REF="{{dlr.comparam_spec_ref.ref_id}}" DOCREF="{{cps_docfrag.doc_name}}" DOCTYPE="{{cps_docfrag.doc_type}}" />
16+
<COMPARAM-SPEC-REF ID-REF="{{dlr.comparam_spec_ref.ref_id}}" DOCREF="{{cps_docfrag.doc_name}}" DOCTYPE="{{cps_docfrag.doc_type.value}}" />
1717

1818
{%- if dlr.prot_stack_snref is not none %}
1919
<PROT-STACK-SNREF SHORT-NAME="{{ dlr.prot_stack_snref }}" />

tests/test_compu_methods.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
from odxtools.compumethods.scaleratfunccompumethod import ScaleRatFuncCompuMethod
2222
from odxtools.compumethods.tabintpcompumethod import TabIntpCompuMethod
2323
from odxtools.exceptions import DecodeError, EncodeError, OdxError
24-
from odxtools.odxlink import OdxDocFragment
24+
from odxtools.odxlink import DocType, OdxDocFragment
2525
from odxtools.odxtypes import DataType
2626
from odxtools.progcode import ProgCode
2727
from odxtools.writepdxfile import (get_parent_container_name, jinja2_odxraise_helper,
2828
make_bool_xml_attrib, make_xml_attrib)
2929

30-
doc_frags = [OdxDocFragment("UnitTest", "WinneThePoh")]
30+
doc_frags = [OdxDocFragment("UnitTest", DocType.CONTAINER)]
3131

3232

3333
class TestLinearCompuMethod(unittest.TestCase):

0 commit comments

Comments
 (0)