odxtools 9.5.0__py3-none-any.whl → 9.6.1__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.
Files changed (102) hide show
  1. odxtools/additionalaudience.py +2 -2
  2. odxtools/admindata.py +3 -0
  3. odxtools/audience.py +9 -13
  4. odxtools/basecomparam.py +1 -2
  5. odxtools/basevariantpattern.py +5 -5
  6. odxtools/basicstructure.py +34 -35
  7. odxtools/commrelation.py +2 -1
  8. odxtools/companydata.py +1 -2
  9. odxtools/companyspecificinfo.py +3 -0
  10. odxtools/comparam.py +16 -8
  11. odxtools/comparaminstance.py +12 -12
  12. odxtools/comparamspec.py +4 -3
  13. odxtools/comparamsubset.py +26 -24
  14. odxtools/compumethods/compuconst.py +4 -4
  15. odxtools/compumethods/limit.py +9 -9
  16. odxtools/compumethods/linearsegment.py +8 -8
  17. odxtools/dataobjectproperty.py +16 -18
  18. odxtools/description.py +4 -2
  19. odxtools/determinenumberofitems.py +4 -4
  20. odxtools/diagcodedtype.py +20 -20
  21. odxtools/diagcomm.py +61 -41
  22. odxtools/diagdatadictionaryspec.py +51 -55
  23. odxtools/diaglayercontainer.py +25 -25
  24. odxtools/diaglayers/diaglayerraw.py +26 -27
  25. odxtools/diagnostictroublecode.py +13 -10
  26. odxtools/diagservice.py +49 -51
  27. odxtools/diagvariable.py +10 -8
  28. odxtools/docrevision.py +5 -5
  29. odxtools/dtcdop.py +17 -17
  30. odxtools/dynamicendmarkerfield.py +8 -8
  31. odxtools/dynamiclengthfield.py +2 -0
  32. odxtools/dyndefinedspec.py +21 -8
  33. odxtools/encodestate.py +1 -2
  34. odxtools/endofpdufield.py +7 -9
  35. odxtools/environmentdatadescription.py +9 -20
  36. odxtools/field.py +21 -21
  37. odxtools/inputparam.py +15 -14
  38. odxtools/leadinglengthinfotype.py +4 -4
  39. odxtools/matchingparameter.py +2 -3
  40. odxtools/minmaxlengthtype.py +7 -7
  41. odxtools/multiplexer.py +38 -39
  42. odxtools/multiplexercase.py +3 -6
  43. odxtools/multiplexerdefaultcase.py +3 -6
  44. odxtools/multiplexerswitchkey.py +4 -4
  45. odxtools/negoutputparam.py +6 -9
  46. odxtools/odxlink.py +21 -5
  47. odxtools/odxtypes.py +4 -4
  48. odxtools/outputparam.py +9 -8
  49. odxtools/parameterinfo.py +1 -1
  50. odxtools/parameters/codedconstparameter.py +28 -27
  51. odxtools/parameters/dynamicparameter.py +9 -9
  52. odxtools/parameters/lengthkeyparameter.py +18 -18
  53. odxtools/parameters/matchingrequestparameter.py +15 -15
  54. odxtools/parameters/nrcconstparameter.py +32 -24
  55. odxtools/parameters/parameter.py +35 -37
  56. odxtools/parameters/parameterwithdop.py +6 -6
  57. odxtools/parameters/physicalconstantparameter.py +19 -20
  58. odxtools/parameters/reservedparameter.py +10 -11
  59. odxtools/parameters/systemparameter.py +10 -11
  60. odxtools/parameters/tableentryparameter.py +19 -20
  61. odxtools/parameters/tablekeyparameter.py +0 -2
  62. odxtools/parameters/tablestructparameter.py +27 -21
  63. odxtools/parameters/valueparameter.py +20 -20
  64. odxtools/parentref.py +6 -7
  65. odxtools/physicaldimension.py +11 -11
  66. odxtools/physicaltype.py +9 -14
  67. odxtools/preconditionstateref.py +85 -0
  68. odxtools/progcode.py +1 -2
  69. odxtools/protstack.py +4 -4
  70. odxtools/relateddoc.py +3 -4
  71. odxtools/scaleconstr.py +0 -1
  72. odxtools/singleecujob.py +8 -4
  73. odxtools/specialdata.py +10 -9
  74. odxtools/specialdatagroup.py +1 -0
  75. odxtools/standardlengthtype.py +10 -10
  76. odxtools/statechart.py +10 -6
  77. odxtools/statemachine.py +186 -0
  78. odxtools/statetransitionref.py +231 -0
  79. odxtools/structure.py +4 -4
  80. odxtools/subcomponent.py +72 -8
  81. odxtools/table.py +23 -13
  82. odxtools/tablerow.py +86 -69
  83. odxtools/teammember.py +4 -4
  84. odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -2
  85. odxtools/templates/macros/printComparam.xml.jinja2 +3 -5
  86. odxtools/templates/macros/printDOP.xml.jinja2 +4 -1
  87. odxtools/templates/macros/printDiagComm.xml.jinja2 +6 -5
  88. odxtools/templates/macros/printParam.xml.jinja2 +5 -5
  89. odxtools/templates/macros/printPreConditionStateRef.xml.jinja2 +18 -0
  90. odxtools/templates/macros/printStateTransitionRef.xml.jinja2 +18 -0
  91. odxtools/templates/macros/printTable.xml.jinja2 +13 -9
  92. odxtools/text.py +35 -0
  93. odxtools/unit.py +1 -3
  94. odxtools/unitgroup.py +6 -8
  95. odxtools/utils.py +0 -4
  96. odxtools/version.py +2 -2
  97. {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/METADATA +3 -2
  98. {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/RECORD +102 -96
  99. {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/WHEEL +1 -1
  100. {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/entry_points.txt +0 -0
  101. {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info/licenses}/LICENSE +0 -0
  102. {odxtools-9.5.0.dist-info → odxtools-9.6.1.dist-info}/top_level.txt +0 -0
@@ -28,11 +28,29 @@ class TableEntryParameter(Parameter):
28
28
  target: RowFragment
29
29
  table_row_ref: OdxLinkRef
30
30
 
31
+ @property
32
+ @override
33
+ def parameter_type(self) -> ParameterType:
34
+ return "TABLE-ENTRY"
35
+
36
+ @property
37
+ @override
38
+ def is_required(self) -> bool:
39
+ raise NotImplementedError("TableEntryParameter.is_required is not implemented yet.")
40
+
41
+ @property
42
+ @override
43
+ def is_settable(self) -> bool:
44
+ raise NotImplementedError("TableEntryParameter.is_settable is not implemented yet.")
45
+
46
+ @property
47
+ def table_row(self) -> "TableRow":
48
+ return self._table_row
49
+
31
50
  @staticmethod
32
51
  @override
33
52
  def from_et(et_element: ElementTree.Element,
34
53
  doc_frags: List[OdxDocFragment]) -> "TableEntryParameter":
35
-
36
54
  kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
37
55
 
38
56
  target_str = odxrequire(et_element.findtext("TARGET"))
@@ -54,30 +72,11 @@ class TableEntryParameter(Parameter):
54
72
  else:
55
73
  self._table_row = odxlinks.resolve(self.table_row_ref)
56
74
 
57
- @property
58
- @override
59
- def parameter_type(self) -> ParameterType:
60
- return "TABLE-ENTRY"
61
-
62
- @property
63
- @override
64
- def is_required(self) -> bool:
65
- raise NotImplementedError("TableEntryParameter.is_required is not implemented yet.")
66
-
67
- @property
68
- @override
69
- def is_settable(self) -> bool:
70
- raise NotImplementedError("TableEntryParameter.is_settable is not implemented yet.")
71
-
72
75
  @override
73
76
  def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
74
77
  encode_state: EncodeState) -> None:
75
78
  raise NotImplementedError("Encoding a TableEntryParameter is not implemented yet.")
76
79
 
77
- @property
78
- def table_row(self) -> "TableRow":
79
- return self._table_row
80
-
81
80
  @override
82
81
  def _decode_positioned_from_pdu(self, decode_state: DecodeState) -> ParameterValue:
83
82
  raise NotImplementedError("Decoding a TableEntryParameter is not implemented yet.")
@@ -38,7 +38,6 @@ class TableKeyParameter(Parameter):
38
38
  @override
39
39
  def from_et(et_element: ElementTree.Element,
40
40
  doc_frags: List[OdxDocFragment]) -> "TableKeyParameter":
41
-
42
41
  kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
43
42
 
44
43
  odx_id = odxrequire(OdxLinkId.from_et(et_element, doc_frags))
@@ -201,7 +200,6 @@ class TableKeyParameter(Parameter):
201
200
  encode_state.cursor_bit_position = 0
202
201
 
203
202
  def encode_value_into_pdu(self, encode_state: EncodeState) -> None:
204
-
205
203
  key_dop = self.table.key_dop
206
204
  if key_dop is None:
207
205
  odxraise(
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional, cast
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -15,13 +15,38 @@ from ..utils import dataclass_fields_asdict
15
15
  from .parameter import Parameter, ParameterType
16
16
  from .tablekeyparameter import TableKeyParameter
17
17
 
18
+ if TYPE_CHECKING:
19
+ from ..table import Table
20
+
18
21
 
19
22
  @dataclass
20
23
  class TableStructParameter(Parameter):
21
-
22
24
  table_key_ref: Optional[OdxLinkRef]
23
25
  table_key_snref: Optional[str]
24
26
 
27
+ @property
28
+ @override
29
+ def parameter_type(self) -> ParameterType:
30
+ return "TABLE-STRUCT"
31
+
32
+ @property
33
+ def table(self) -> "Table":
34
+ return self._table_key.table
35
+
36
+ @property
37
+ def table_key(self) -> TableKeyParameter:
38
+ return self._table_key
39
+
40
+ @property
41
+ @override
42
+ def is_required(self) -> bool:
43
+ return True
44
+
45
+ @property
46
+ @override
47
+ def is_settable(self) -> bool:
48
+ return True
49
+
25
50
  @staticmethod
26
51
  @override
27
52
  def from_et(et_element: ElementTree.Element,
@@ -41,11 +66,6 @@ class TableStructParameter(Parameter):
41
66
  if self.table_key_ref is None and self.table_key_snref is None:
42
67
  odxraise("Either table_key_ref or table_key_snref must be defined.")
43
68
 
44
- @property
45
- @override
46
- def parameter_type(self) -> ParameterType:
47
- return "TABLE-STRUCT"
48
-
49
69
  @override
50
70
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
51
71
  return super()._build_odxlinks()
@@ -65,20 +85,6 @@ class TableStructParameter(Parameter):
65
85
  self._table_key = resolve_snref(self.table_key_snref, odxrequire(context.parameters),
66
86
  TableKeyParameter)
67
87
 
68
- @property
69
- def table_key(self) -> TableKeyParameter:
70
- return self._table_key
71
-
72
- @property
73
- @override
74
- def is_required(self) -> bool:
75
- return True
76
-
77
- @property
78
- @override
79
- def is_settable(self) -> bool:
80
- return True
81
-
82
88
  @override
83
89
  def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
84
90
  encode_state: EncodeState) -> None:
@@ -20,8 +20,24 @@ from .parameterwithdop import ParameterWithDOP
20
20
  class ValueParameter(ParameterWithDOP):
21
21
  physical_default_value_raw: Optional[str]
22
22
 
23
- def __post_init__(self) -> None:
24
- self._physical_default_value: Optional[AtomicOdxType] = None
23
+ @property
24
+ @override
25
+ def parameter_type(self) -> ParameterType:
26
+ return "VALUE"
27
+
28
+ @property
29
+ def physical_default_value(self) -> Optional[AtomicOdxType]:
30
+ return self._physical_default_value
31
+
32
+ @property
33
+ @override
34
+ def is_required(self) -> bool:
35
+ return self._physical_default_value is None
36
+
37
+ @property
38
+ @override
39
+ def is_settable(self) -> bool:
40
+ return True
25
41
 
26
42
  @staticmethod
27
43
  @override
@@ -34,10 +50,8 @@ class ValueParameter(ParameterWithDOP):
34
50
 
35
51
  return ValueParameter(physical_default_value_raw=physical_default_value_raw, **kwargs)
36
52
 
37
- @property
38
- @override
39
- def parameter_type(self) -> ParameterType:
40
- return "VALUE"
53
+ def __post_init__(self) -> None:
54
+ self._physical_default_value: Optional[AtomicOdxType] = None
41
55
 
42
56
  @override
43
57
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
@@ -60,20 +74,6 @@ class ValueParameter(ParameterWithDOP):
60
74
  self._physical_default_value = base_data_type.from_string(
61
75
  self.physical_default_value_raw)
62
76
 
63
- @property
64
- def physical_default_value(self) -> Optional[AtomicOdxType]:
65
- return self._physical_default_value
66
-
67
- @property
68
- @override
69
- def is_required(self) -> bool:
70
- return self._physical_default_value is None
71
-
72
- @property
73
- @override
74
- def is_settable(self) -> bool:
75
- return True
76
-
77
77
  @override
78
78
  def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
79
79
  encode_state: EncodeState) -> None:
odxtools/parentref.py CHANGED
@@ -37,6 +37,12 @@ class ParentRef:
37
37
  "NOT-INHERITED-DIAG-COMM/"
38
38
  "DIAG-COMM-SNREF")
39
39
  ]
40
+ not_inherited_variables = [
41
+ odxrequire(el.get("SHORT-NAME"))
42
+ for el in et_element.iterfind("NOT-INHERITED-VARIABLES/"
43
+ "NOT-INHERITED-VARIABLE/"
44
+ "DIAG-VARIABLE-SNREF")
45
+ ]
40
46
  not_inherited_dops = [
41
47
  odxrequire(el.get("SHORT-NAME")) for el in et_element.iterfind("NOT-INHERITED-DOPS/"
42
48
  "NOT-INHERITED-DOP/"
@@ -47,13 +53,6 @@ class ParentRef:
47
53
  "NOT-INHERITED-TABLE/"
48
54
  "TABLE-SNREF")
49
55
  ]
50
- not_inherited_variables = [
51
- odxrequire(el.get("SHORT-NAME"))
52
- for el in et_element.iterfind("NOT-INHERITED-VARIABLES/"
53
- "NOT-INHERITED-VARIABLE/"
54
- "DIAG-VARIABLE-SNREF")
55
- ]
56
-
57
56
  not_inherited_global_neg_responses = [
58
57
  odxrequire(el.get("SHORT-NAME"))
59
58
  for el in et_element.iterfind("NOT-INHERITED-GLOBAL-NEG-RESPONSES/"
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List
3
+ from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
@@ -41,24 +41,24 @@ class PhysicalDimension(IdentifiableElement):
41
41
  )
42
42
  ```
43
43
  """
44
- length_exp: int
45
- mass_exp: int
46
- time_exp: int
47
- current_exp: int
48
- temperature_exp: int
49
- molar_amount_exp: int
50
- luminous_intensity_exp: int
44
+ length_exp: Optional[int]
45
+ mass_exp: Optional[int]
46
+ time_exp: Optional[int]
47
+ current_exp: Optional[int]
48
+ temperature_exp: Optional[int]
49
+ molar_amount_exp: Optional[int]
50
+ luminous_intensity_exp: Optional[int]
51
51
 
52
52
  @staticmethod
53
53
  def from_et(et_element: ElementTree.Element,
54
54
  doc_frags: List[OdxDocFragment]) -> "PhysicalDimension":
55
55
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
56
56
 
57
- def read_optional_int(element: ElementTree.Element, name: str) -> int:
58
- if val_str := element.findtext(name):
57
+ def read_optional_int(element: ElementTree.Element, name: str) -> Optional[int]:
58
+ if (val_str := element.findtext(name)) is not None:
59
59
  return int(val_str)
60
60
  else:
61
- return 0
61
+ return None
62
62
 
63
63
  length_exp = read_optional_int(et_element, "LENGTH-EXP")
64
64
  mass_exp = read_optional_int(et_element, "MASS-EXP")
odxtools/physicaltype.py CHANGED
@@ -39,6 +39,11 @@ class PhysicalType:
39
39
  PhysicalType(DataType.A_FLOAT64, precision=2)
40
40
  """
41
41
 
42
+ precision: Optional[int]
43
+ """Number of digits after the decimal point to display to the user
44
+ The precision is only applicable if the base data type is A_FLOAT32 or A_FLOAT64.
45
+ """
46
+
42
47
  base_data_type: DataType
43
48
 
44
49
  display_radix: Optional[Radix]
@@ -46,18 +51,11 @@ class PhysicalType:
46
51
  The display radix is only applicable if the base data type is A_UINT32.
47
52
  """
48
53
 
49
- precision: Optional[int]
50
- """Number of digits after the decimal point to display to the user
51
- The precision is only applicable if the base data type is A_FLOAT32 or A_FLOAT64.
52
- """
53
-
54
- def __post_init__(self) -> None:
55
- self.base_data_type = DataType(self.base_data_type)
56
- if self.display_radix is not None:
57
- self.display_radix = Radix(self.display_radix)
58
-
59
54
  @staticmethod
60
55
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "PhysicalType":
56
+ precision_str = et_element.findtext("PRECISION")
57
+ precision = int(precision_str) if precision_str is not None else None
58
+
61
59
  base_data_type_str = et_element.get("BASE-DATA-TYPE")
62
60
  if base_data_type_str not in DataType.__members__:
63
61
  odxraise(f"Encountered unknown base data type '{base_data_type_str}'")
@@ -71,8 +69,5 @@ class PhysicalType:
71
69
  else:
72
70
  display_radix = None
73
71
 
74
- precision_str = et_element.findtext("PRECISION")
75
- precision = int(precision_str) if precision_str is not None else None
76
-
77
72
  return PhysicalType(
78
- base_data_type=base_data_type, display_radix=display_radix, precision=precision)
73
+ precision=precision, base_data_type=base_data_type, display_radix=display_radix)
@@ -0,0 +1,85 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
+ from xml.etree import ElementTree
5
+
6
+ from .exceptions import odxassert, odxrequire
7
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
8
+ from .odxtypes import ParameterValueDict
9
+ from .parameters.parameter import Parameter
10
+ from .snrefcontext import SnRefContext
11
+ from .state import State
12
+ from .statetransitionref import _check_applies
13
+ from .utils import dataclass_fields_asdict
14
+
15
+ if TYPE_CHECKING:
16
+ from .statemachine import StateMachine
17
+
18
+
19
+ @dataclass
20
+ class PreConditionStateRef(OdxLinkRef):
21
+ """
22
+ This class represents the PRE-CONDITION-STATE-REF XML tag.
23
+ """
24
+ value: Optional[str]
25
+
26
+ in_param_if_snref: Optional[str]
27
+ in_param_if_snpathref: Optional[str]
28
+
29
+ @property
30
+ def state(self) -> "State":
31
+ return self._state
32
+
33
+ @staticmethod
34
+ def from_et( # type: ignore[override]
35
+ et_element: ElementTree.Element,
36
+ doc_frags: List[OdxDocFragment]) -> "PreConditionStateRef":
37
+ kwargs = dataclass_fields_asdict(OdxLinkRef.from_et(et_element, doc_frags))
38
+
39
+ value = et_element.findtext("VALUE")
40
+
41
+ in_param_if_snref = None
42
+ if (in_param_if_snref_elem := et_element.find("IN-PARAM-IF-SNREF")) is not None:
43
+ in_param_if_snref = odxrequire(in_param_if_snref_elem.get("SHORT-NAME"))
44
+
45
+ in_param_if_snpathref = None
46
+ if (in_param_if_snpathref_elem := et_element.find("IN-PARAM-IF-SNPATHREF")) is not None:
47
+ in_param_if_snpathref = odxrequire(in_param_if_snpathref_elem.get("SHORT-NAME-PATH"))
48
+
49
+ return PreConditionStateRef(
50
+ value=value,
51
+ in_param_if_snref=in_param_if_snref,
52
+ in_param_if_snpathref=in_param_if_snpathref,
53
+ **kwargs)
54
+
55
+ def __post_init__(self) -> None:
56
+ if self.value is not None:
57
+ odxassert(self.in_param_if_snref is not None or self.in_param_if_snref is not None,
58
+ "If VALUE is specified, a parameter must be referenced")
59
+
60
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
61
+ return {}
62
+
63
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
64
+ self._state = odxlinks.resolve(self, State)
65
+
66
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
67
+ pass
68
+
69
+ def applies(self, state_machine: "StateMachine", params: List[Parameter],
70
+ param_value_dict: ParameterValueDict) -> bool:
71
+ """Given a state machine, evaluate whether the precondition is fulfilled or not
72
+
73
+ Note that the specification is unclear about what the
74
+ parameters are: It says "The optional VALUE together with the
75
+ also optional IN-PARAM-IF snref at STATE-TRANSITION-REF and
76
+ PRE-CONDITION-STATE-REF can be used if the STATE-TRANSITIONs
77
+ and pre-condition STATEs are dependent on the values of the
78
+ referenced PARAMs.", but it does not specify what the
79
+ "referenced PARAMs" are. For the state transition refs, let's
80
+ assume that they are the parameters of a positive response
81
+ received from the ECU, whilst we assume that they are the
82
+ parameters of the request for PRE-CONDITION-STATE-REFs.
83
+ """
84
+
85
+ return _check_applies(self, state_machine, params, param_value_dict)
odxtools/progcode.py CHANGED
@@ -31,7 +31,6 @@ class ProgCode:
31
31
  @staticmethod
32
32
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ProgCode":
33
33
  code_file = odxrequire(et_element.findtext("CODE-FILE"))
34
-
35
34
  encryption = et_element.findtext("ENCRYPTION")
36
35
  syntax = odxrequire(et_element.findtext("SYNTAX"))
37
36
  revision = odxrequire(et_element.findtext("REVISION"))
@@ -44,9 +43,9 @@ class ProgCode:
44
43
 
45
44
  return ProgCode(
46
45
  code_file=code_file,
46
+ encryption=encryption,
47
47
  syntax=syntax,
48
48
  revision=revision,
49
- encryption=encryption,
50
49
  entrypoint=entrypoint,
51
50
  library_refs=library_refs,
52
51
  )
odxtools/protstack.py CHANGED
@@ -19,6 +19,10 @@ class ProtStack(IdentifiableElement):
19
19
  physical_link_type: str
20
20
  comparam_subset_refs: List[OdxLinkRef]
21
21
 
22
+ @property
23
+ def comparam_subsets(self) -> NamedItemList[ComparamSubset]:
24
+ return self._comparam_subsets
25
+
22
26
  @staticmethod
23
27
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ProtStack":
24
28
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
@@ -47,7 +51,3 @@ class ProtStack(IdentifiableElement):
47
51
 
48
52
  def _resolve_snrefs(self, context: SnRefContext) -> None:
49
53
  pass
50
-
51
- @property
52
- def comparam_subsets(self) -> NamedItemList[ComparamSubset]:
53
- return self._comparam_subsets
odxtools/relateddoc.py CHANGED
@@ -11,20 +11,19 @@ from .xdoc import XDoc
11
11
 
12
12
  @dataclass
13
13
  class RelatedDoc:
14
- description: Optional[Description]
15
14
  xdoc: Optional[XDoc]
15
+ description: Optional[Description]
16
16
 
17
17
  @staticmethod
18
18
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "RelatedDoc":
19
- description = Description.from_et(et_element.find("DESC"), doc_frags)
20
-
21
19
  xdoc: Optional[XDoc] = None
22
20
  if (xdoc_elem := et_element.find("XDOC")) is not None:
23
21
  xdoc = XDoc.from_et(xdoc_elem, doc_frags)
22
+ description = Description.from_et(et_element.find("DESC"), doc_frags)
24
23
 
25
24
  return RelatedDoc(
26
- description=description,
27
25
  xdoc=xdoc,
26
+ description=description,
28
27
  )
29
28
 
30
29
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
odxtools/scaleconstr.py CHANGED
@@ -35,7 +35,6 @@ class ScaleConstr:
35
35
  value_type: DataType) -> "ScaleConstr":
36
36
  short_label = et_element.findtext("SHORT-LABEL")
37
37
  description = Description.from_et(et_element.find("DESC"), doc_frags)
38
-
39
38
  lower_limit = Limit.limit_from_et(
40
39
  odxrequire(et_element.find("LOWER-LIMIT")), doc_frags, value_type=value_type)
41
40
  upper_limit = Limit.limit_from_et(
odxtools/singleecujob.py CHANGED
@@ -18,12 +18,16 @@ from .utils import dataclass_fields_asdict
18
18
  class SingleEcuJob(DiagComm):
19
19
  """A single ECU job is a diagnostic communication primitive.
20
20
 
21
- A single ECU job is more complex than a diagnostic service and is not provided natively by the ECU.
22
- In particular, the job is defined in external programs which are referenced by the attribute `.prog_codes`.
21
+ A single ECU job is more complex than a diagnostic service and is
22
+ not provided natively by the ECU. In particular, the job is
23
+ defined in external programs which are referenced by the attribute
24
+ `.prog_codes`.
23
25
 
24
- In contrast to "multiple ECU jobs", a single ECU job only does service calls to a single ECU.
26
+ In contrast to "multiple ECU jobs", a single ECU job only involves
27
+ calls to services provided by a single ECU.
25
28
 
26
- Single ECU jobs are defined in section 7.3.5.7 of the ASAM MCD-2 standard.
29
+ Single ECU jobs are defined in section 7.3.5.7 of the ASAM MCD-2
30
+ standard.
27
31
  """
28
32
 
29
33
  prog_codes: List[ProgCode]
odxtools/specialdata.py CHANGED
@@ -9,19 +9,11 @@ from .snrefcontext import SnRefContext
9
9
 
10
10
  @dataclass
11
11
  class SpecialData:
12
+ """This corresponds to the SD XML tag"""
12
13
  semantic_info: Optional[str] # the "SI" attribute
13
14
  text_identifier: Optional[str] # the "TI" attribute, specifies the language used
14
15
  value: str
15
16
 
16
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
17
- return {}
18
-
19
- def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
20
- pass
21
-
22
- def _resolve_snrefs(self, context: SnRefContext) -> None:
23
- pass
24
-
25
17
  @staticmethod
26
18
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "SpecialData":
27
19
  semantic_info = et_element.get("SI")
@@ -30,3 +22,12 @@ class SpecialData:
30
22
 
31
23
  return SpecialData(
32
24
  semantic_info=semantic_info, text_identifier=text_identifier, value=value)
25
+
26
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
27
+ return {}
28
+
29
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
30
+ pass
31
+
32
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
33
+ pass
@@ -11,6 +11,7 @@ from .specialdatagroupcaption import SpecialDataGroupCaption
11
11
 
12
12
  @dataclass
13
13
  class SpecialDataGroup:
14
+ """This corresponds to the SDG XML tag"""
14
15
  sdg_caption: Optional[SpecialDataGroupCaption]
15
16
  sdg_caption_ref: Optional[OdxLinkRef]
16
17
  values: List[Union["SpecialDataGroup", SpecialData]]
@@ -10,8 +10,8 @@ from .diagcodedtype import DctType, DiagCodedType
10
10
  from .encodestate import EncodeState
11
11
  from .exceptions import odxassert, odxraise, odxrequire
12
12
  from .odxlink import OdxDocFragment
13
- from .odxtypes import AtomicOdxType, DataType, odxstr_to_bool
14
- from .utils import BytesTypes, dataclass_fields_asdict
13
+ from .odxtypes import AtomicOdxType, BytesTypes, DataType, odxstr_to_bool
14
+ from .utils import dataclass_fields_asdict
15
15
 
16
16
 
17
17
  @dataclass
@@ -21,6 +21,14 @@ class StandardLengthType(DiagCodedType):
21
21
  bit_mask: Optional[int]
22
22
  is_condensed_raw: Optional[bool]
23
23
 
24
+ @property
25
+ def dct_type(self) -> DctType:
26
+ return "STANDARD-LENGTH-TYPE"
27
+
28
+ @property
29
+ def is_condensed(self) -> bool:
30
+ return self.is_condensed_raw is True
31
+
24
32
  @staticmethod
25
33
  @override
26
34
  def from_et(et_element: ElementTree.Element,
@@ -43,14 +51,6 @@ class StandardLengthType(DiagCodedType):
43
51
  return StandardLengthType(
44
52
  bit_length=bit_length, bit_mask=bit_mask, is_condensed_raw=is_condensed_raw, **kwargs)
45
53
 
46
- @property
47
- def dct_type(self) -> DctType:
48
- return "STANDARD-LENGTH-TYPE"
49
-
50
- @property
51
- def is_condensed(self) -> bool:
52
- return self.is_condensed_raw is True
53
-
54
54
  def __post_init__(self) -> None:
55
55
  if self.bit_mask is not None:
56
56
  maskable_types = (DataType.A_UINT32, DataType.A_INT32, DataType.A_BYTEFIELD)
odxtools/statechart.py CHANGED
@@ -30,6 +30,7 @@ class StateChart(IdentifiableElement):
30
30
  @staticmethod
31
31
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "StateChart":
32
32
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
33
+
33
34
  semantic: str = odxrequire(et_element.findtext("SEMANTIC"))
34
35
 
35
36
  state_transitions = [
@@ -54,15 +55,18 @@ class StateChart(IdentifiableElement):
54
55
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
55
56
  odxlinks = {self.odx_id: self}
56
57
 
57
- for st in self.states:
58
- odxlinks.update(st._build_odxlinks())
59
-
60
58
  for strans in self.state_transitions:
61
59
  odxlinks.update(strans._build_odxlinks())
62
60
 
61
+ for st in self.states:
62
+ odxlinks.update(st._build_odxlinks())
63
+
63
64
  return odxlinks
64
65
 
65
66
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
67
+ for strans in self.state_transitions:
68
+ strans._resolve_odxlinks(odxlinks)
69
+
66
70
  for st in self.states:
67
71
  st._resolve_odxlinks(odxlinks)
68
72
 
@@ -77,10 +81,10 @@ class StateChart(IdentifiableElement):
77
81
  # does that mean?
78
82
  self._start_state = resolve_snref(self.start_state_snref, self.states, State)
79
83
 
80
- for st in self.states:
81
- st._resolve_snrefs(context)
82
-
83
84
  for strans in self.state_transitions:
84
85
  strans._resolve_snrefs(context)
85
86
 
87
+ for st in self.states:
88
+ st._resolve_snrefs(context)
89
+
86
90
  context.state_chart = None