odxtools 9.6.1__py3-none-any.whl → 9.7.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.
Files changed (65) hide show
  1. odxtools/addressing.py +8 -0
  2. odxtools/basecomparam.py +2 -15
  3. odxtools/basicstructure.py +4 -3
  4. odxtools/codec.py +1 -184
  5. odxtools/commrelation.py +1 -8
  6. odxtools/commrelationvaluetype.py +9 -0
  7. odxtools/compositecodec.py +191 -0
  8. odxtools/compumethods/compucategory.py +13 -0
  9. odxtools/compumethods/compucodecompumethod.py +2 -1
  10. odxtools/compumethods/compumethod.py +1 -12
  11. odxtools/compumethods/intervaltype.py +8 -0
  12. odxtools/compumethods/limit.py +1 -7
  13. odxtools/compumethods/linearcompumethod.py +2 -1
  14. odxtools/compumethods/ratfunccompumethod.py +2 -1
  15. odxtools/compumethods/scalelinearcompumethod.py +3 -2
  16. odxtools/compumethods/scaleratfunccompumethod.py +2 -1
  17. odxtools/compumethods/tabintpcompumethod.py +4 -2
  18. odxtools/compumethods/texttablecompumethod.py +2 -1
  19. odxtools/description.py +1 -17
  20. odxtools/diagclasstype.py +11 -0
  21. odxtools/diagcomm.py +2 -25
  22. odxtools/diagservice.py +3 -79
  23. odxtools/dtcconnector.py +45 -0
  24. odxtools/dtcdop.py +2 -47
  25. odxtools/dyndefinedspec.py +3 -155
  26. odxtools/dyniddefmodeinfo.py +161 -0
  27. odxtools/envdataconnector.py +49 -0
  28. odxtools/externalaccessmethod.py +23 -0
  29. odxtools/externaldoc.py +23 -0
  30. odxtools/linkeddtcdop.py +62 -0
  31. odxtools/minmaxlengthtype.py +1 -7
  32. odxtools/parameterinfo.py +1 -1
  33. odxtools/parameters/rowfragment.py +7 -0
  34. odxtools/parameters/tableentryparameter.py +1 -6
  35. odxtools/physicaltype.py +1 -8
  36. odxtools/posresponsesuppressible.py +73 -0
  37. odxtools/radix.py +9 -0
  38. odxtools/relateddiagcommref.py +23 -0
  39. odxtools/request.py +5 -3
  40. odxtools/response.py +5 -3
  41. odxtools/scaleconstr.py +1 -8
  42. odxtools/standardizationlevel.py +9 -0
  43. odxtools/standardlengthtype.py +2 -11
  44. odxtools/statetransition.py +1 -14
  45. odxtools/subcomponent.py +8 -241
  46. odxtools/subcomponentparamconnector.py +103 -0
  47. odxtools/subcomponentpattern.py +42 -0
  48. odxtools/table.py +3 -41
  49. odxtools/tablediagcommconnector.py +47 -0
  50. odxtools/tablerowconnector.py +46 -0
  51. odxtools/templates/macros/printService.xml.jinja2 +2 -1
  52. odxtools/termination.py +8 -0
  53. odxtools/transmode.py +9 -0
  54. odxtools/unitgroup.py +1 -6
  55. odxtools/unitgroupcategory.py +7 -0
  56. odxtools/usage.py +9 -0
  57. odxtools/utils.py +29 -0
  58. odxtools/validtype.py +9 -0
  59. odxtools/version.py +2 -2
  60. {odxtools-9.6.1.dist-info → odxtools-9.7.0.dist-info}/METADATA +1 -1
  61. {odxtools-9.6.1.dist-info → odxtools-9.7.0.dist-info}/RECORD +65 -39
  62. {odxtools-9.6.1.dist-info → odxtools-9.7.0.dist-info}/WHEEL +0 -0
  63. {odxtools-9.6.1.dist-info → odxtools-9.7.0.dist-info}/entry_points.txt +0 -0
  64. {odxtools-9.6.1.dist-info → odxtools-9.7.0.dist-info}/licenses/LICENSE +0 -0
  65. {odxtools-9.6.1.dist-info → odxtools-9.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,103 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any, Dict, List
4
+ from xml.etree import ElementTree
5
+
6
+ from .diagservice import DiagService
7
+ from .element import IdentifiableElement
8
+ from .exceptions import odxassert, odxraise, odxrequire
9
+ from .nameditemlist import NamedItemList
10
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
11
+ from .parameters.parameter import Parameter
12
+ from .snrefcontext import SnRefContext
13
+ from .utils import dataclass_fields_asdict
14
+
15
+
16
+ @dataclass
17
+ class SubComponentParamConnector(IdentifiableElement):
18
+ diag_comm_snref: str
19
+
20
+ # TODO: we currently only support SNREFs, not SNPATHREFs
21
+ out_param_if_refs: List[str]
22
+ in_param_if_refs: List[str]
23
+
24
+ @property
25
+ def service(self) -> DiagService:
26
+ return self._service
27
+
28
+ @property
29
+ def out_param_ifs(self) -> NamedItemList[Parameter]:
30
+ return self._out_param_ifs
31
+
32
+ @property
33
+ def in_param_ifs(self) -> NamedItemList[Parameter]:
34
+ return self._in_param_ifs
35
+
36
+ @staticmethod
37
+ def from_et(et_element: ElementTree.Element,
38
+ doc_frags: List[OdxDocFragment]) -> "SubComponentParamConnector":
39
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
40
+
41
+ diag_comm_snref = odxrequire(
42
+ odxrequire(et_element.find("DIAG-COMM-SNREF")).get("SHORT-NAME"))
43
+
44
+ out_param_if_refs = []
45
+ for elem in et_element.find("OUT-PARAM-IF-REFS") or []:
46
+ if elem.tag != "OUT-PARAM-IF-SNREF":
47
+ odxraise("Currently, only SNREFS are supported for OUT-PARAM-IF-REFS")
48
+ continue
49
+ else:
50
+ odxassert(elem.tag == "OUT-PARAM-IF-SNREF")
51
+ out_param_if_refs.append(odxrequire(elem.attrib.get("SHORT-NAME")))
52
+
53
+ in_param_if_refs = []
54
+ for elem in et_element.find("IN-PARAM-IF-REFS") or []:
55
+ if elem.tag != "IN-PARAM-IF-SNREF":
56
+ odxraise("Currently, only SNREFS are supported for IN-PARAM-IF-REFS")
57
+ continue
58
+ else:
59
+ odxassert(elem.tag == "IN-PARAM-IF-SNREF")
60
+ in_param_if_refs.append(odxrequire(elem.attrib.get("SHORT-NAME")))
61
+
62
+ return SubComponentParamConnector(
63
+ diag_comm_snref=diag_comm_snref,
64
+ out_param_if_refs=out_param_if_refs,
65
+ in_param_if_refs=in_param_if_refs,
66
+ **kwargs)
67
+
68
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
69
+ return {}
70
+
71
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
72
+ pass
73
+
74
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
75
+ service = resolve_snref(self.diag_comm_snref,
76
+ odxrequire(context.diag_layer).diag_comms, DiagService)
77
+ self._service = service
78
+
79
+ if self._service.request is not None:
80
+ odxraise()
81
+ return
82
+ if not self._service.positive_responses:
83
+ odxraise()
84
+ return
85
+
86
+ request = odxrequire(service.request)
87
+ in_param_ifs = []
88
+ for x in self.in_param_if_refs:
89
+ in_param_ifs.append(resolve_snref(x, request.parameters, Parameter))
90
+
91
+ # TODO: The output parameters are probably part of a response
92
+ # (?). If so, they cannot be resolved ahead of time because
93
+ # the service in question can have multiple responses
94
+ # associated with it and each of these has its own set of
95
+ # parameters. In the meantime, we simply use the first
96
+ # positive response specified.
97
+ response = service.positive_responses[0]
98
+ out_param_ifs = []
99
+ for x in self.out_param_if_refs:
100
+ out_param_ifs.append(resolve_snref(x, response.parameters, Parameter))
101
+
102
+ self._in_param_ifs = NamedItemList(in_param_ifs)
103
+ self._out_param_ifs = NamedItemList(out_param_ifs)
@@ -0,0 +1,42 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import TYPE_CHECKING, Any, Dict, List
4
+ from xml.etree import ElementTree
5
+
6
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
7
+ from .snrefcontext import SnRefContext
8
+
9
+ if TYPE_CHECKING:
10
+ from .matchingparameter import MatchingParameter
11
+
12
+
13
+ @dataclass
14
+ class SubComponentPattern:
15
+ matching_parameters: List["MatchingParameter"]
16
+
17
+ @staticmethod
18
+ def from_et(et_element: ElementTree.Element,
19
+ doc_frags: List[OdxDocFragment]) -> "SubComponentPattern":
20
+ from .matchingparameter import MatchingParameter
21
+
22
+ matching_parameters = [
23
+ MatchingParameter.from_et(el, doc_frags)
24
+ for el in et_element.iterfind("MATCHING-PARAMETERS/MATCHING-PARAMETER")
25
+ ]
26
+
27
+ return SubComponentPattern(matching_parameters=matching_parameters)
28
+
29
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
30
+ result = {}
31
+ for mp in self.matching_parameters:
32
+ result.update(mp._build_odxlinks())
33
+
34
+ return result
35
+
36
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
37
+ for mp in self.matching_parameters:
38
+ mp._resolve_odxlinks(odxlinks)
39
+
40
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
41
+ for mp in self.matching_parameters:
42
+ mp._resolve_snrefs(context)
odxtools/table.py CHANGED
@@ -5,55 +5,17 @@ from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
7
7
  from .dataobjectproperty import DataObjectProperty
8
- from .diagcomm import DiagComm
9
8
  from .element import IdentifiableElement
10
- from .exceptions import odxassert, odxrequire
9
+ from .exceptions import odxassert
11
10
  from .nameditemlist import NamedItemList
12
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
11
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
13
12
  from .snrefcontext import SnRefContext
14
13
  from .specialdatagroup import SpecialDataGroup
14
+ from .tablediagcommconnector import TableDiagCommConnector
15
15
  from .tablerow import TableRow
16
16
  from .utils import dataclass_fields_asdict
17
17
 
18
18
 
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
-
36
- diag_comm_ref = OdxLinkRef.from_et(et_element.find("DIAG-COMM-REF"), doc_frags)
37
- diag_comm_snref = None
38
- if (dc_snref_elem := et_element.find("DIAG-COMM-SNREF")) is not None:
39
- diag_comm_snref = odxrequire(dc_snref_elem.get("SHORT-NAME"))
40
-
41
- return TableDiagCommConnector(
42
- semantic=semantic, diag_comm_ref=diag_comm_ref, diag_comm_snref=diag_comm_snref)
43
-
44
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
45
- return {}
46
-
47
- def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
48
- if self.diag_comm_ref is not None:
49
- self._diag_comm = odxlinks.resolve(self.diag_comm_ref, DiagComm)
50
-
51
- def _resolve_snrefs(self, context: SnRefContext) -> None:
52
- if self.diag_comm_snref is not None:
53
- dl = odxrequire(context.diag_layer)
54
- self._diag_comm = resolve_snref(self.diag_comm_snref, dl.diag_comms, DiagComm)
55
-
56
-
57
19
  @dataclass
58
20
  class Table(IdentifiableElement):
59
21
  """This class represents a TABLE."""
@@ -0,0 +1,47 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any, Dict, List, Optional
4
+ from xml.etree import ElementTree
5
+
6
+ from .diagcomm import DiagComm
7
+ from .exceptions import odxrequire
8
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
9
+ from .snrefcontext import SnRefContext
10
+
11
+
12
+ @dataclass
13
+ class TableDiagCommConnector:
14
+ semantic: str
15
+
16
+ diag_comm_ref: Optional[OdxLinkRef]
17
+ diag_comm_snref: Optional[str]
18
+
19
+ @property
20
+ def diag_comm(self) -> DiagComm:
21
+ return self._diag_comm
22
+
23
+ @staticmethod
24
+ def from_et(et_element: ElementTree.Element,
25
+ doc_frags: List[OdxDocFragment]) -> "TableDiagCommConnector":
26
+
27
+ semantic = odxrequire(et_element.findtext("SEMANTIC"))
28
+
29
+ diag_comm_ref = OdxLinkRef.from_et(et_element.find("DIAG-COMM-REF"), doc_frags)
30
+ diag_comm_snref = None
31
+ if (dc_snref_elem := et_element.find("DIAG-COMM-SNREF")) is not None:
32
+ diag_comm_snref = odxrequire(dc_snref_elem.get("SHORT-NAME"))
33
+
34
+ return TableDiagCommConnector(
35
+ semantic=semantic, diag_comm_ref=diag_comm_ref, diag_comm_snref=diag_comm_snref)
36
+
37
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
38
+ return {}
39
+
40
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
41
+ if self.diag_comm_ref is not None:
42
+ self._diag_comm = odxlinks.resolve(self.diag_comm_ref, DiagComm)
43
+
44
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
45
+ if self.diag_comm_snref is not None:
46
+ dl = odxrequire(context.diag_layer)
47
+ self._diag_comm = resolve_snref(self.diag_comm_snref, dl.diag_comms, DiagComm)
@@ -0,0 +1,46 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import Any, Dict, List
4
+ from xml.etree import ElementTree
5
+
6
+ from .element import NamedElement
7
+ from .exceptions import odxrequire
8
+ from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
9
+ from .snrefcontext import SnRefContext
10
+ from .table import Table
11
+ from .tablerow import TableRow
12
+ from .utils import dataclass_fields_asdict
13
+
14
+
15
+ @dataclass
16
+ class TableRowConnector(NamedElement):
17
+ table_ref: OdxLinkRef
18
+ table_row_snref: str
19
+
20
+ @property
21
+ def table(self) -> Table:
22
+ return self._table
23
+
24
+ @property
25
+ def table_row(self) -> TableRow:
26
+ return self._table_row
27
+
28
+ @staticmethod
29
+ def from_et(et_element: ElementTree.Element,
30
+ doc_frags: List[OdxDocFragment]) -> "TableRowConnector":
31
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
32
+
33
+ table_ref = odxrequire(OdxLinkRef.from_et(et_element.find("TABLE-REF"), doc_frags))
34
+ table_row_snref_el = odxrequire(et_element.find("TABLE-ROW-SNREF"))
35
+ table_row_snref = odxrequire(table_row_snref_el.get("SHORT-NAME"))
36
+
37
+ return TableRowConnector(table_ref=table_ref, table_row_snref=table_row_snref, **kwargs)
38
+
39
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
40
+ return {}
41
+
42
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
43
+ self._table = odxlinks.resolve(self.table_ref, Table)
44
+
45
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
46
+ self._table_row = resolve_snref(self.table_row_snref, self._table.table_rows, TableRow)
@@ -8,7 +8,8 @@
8
8
 
9
9
  {%- macro printPosResponseSuppressible(prs) -%}
10
10
  <POS-RESPONSE-SUPPRESSABLE>
11
- <BIT-MASK>{{ hex(prs.bit_mask).lower() }}</BIT-MASK>
11
+ {%- set num_nibbles = (prs.bit_mask.bit_length() + 7) // 8 * 2 %}
12
+ <BIT-MASK>{{ ("%%0%dX" | format(num_nibbles | int)) | format(prs.bit_mask | int) }}</BIT-MASK>
12
13
  {%- if prs.coded_const_snref is not none %}
13
14
  <CODED-CONST-SNREF SHORT-NAME="{{ prs.coded_const_snref }}" />
14
15
  {%- endif %}
@@ -0,0 +1,8 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+
5
+ class Termination(Enum):
6
+ END_OF_PDU = "END-OF-PDU"
7
+ ZERO = "ZERO"
8
+ HEX_FF = "HEX-FF"
odxtools/transmode.py ADDED
@@ -0,0 +1,9 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+
5
+ class TransMode(Enum):
6
+ SEND_ONLY = "SEND-ONLY"
7
+ RECEIVE_ONLY = "RECEIVE-ONLY"
8
+ SEND_AND_RECEIVE = "SEND-AND-RECEIVE"
9
+ SEND_OR_RECEIVE = "SEND-OR-RECEIVE"
odxtools/unitgroup.py CHANGED
@@ -1,6 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from enum import Enum
4
3
  from typing import Any, Dict, List, Optional, cast
5
4
  from xml.etree import ElementTree
6
5
 
@@ -10,14 +9,10 @@ from .nameditemlist import NamedItemList
10
9
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
10
  from .snrefcontext import SnRefContext
12
11
  from .unit import Unit
12
+ from .unitgroupcategory import UnitGroupCategory
13
13
  from .utils import dataclass_fields_asdict
14
14
 
15
15
 
16
- class UnitGroupCategory(Enum):
17
- COUNTRY = "COUNTRY"
18
- EQUIV_UNITS = "EQUIV-UNITS"
19
-
20
-
21
16
  @dataclass
22
17
  class UnitGroup(NamedElement):
23
18
  """A group of units.
@@ -0,0 +1,7 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+
5
+ class UnitGroupCategory(Enum):
6
+ COUNTRY = "COUNTRY"
7
+ EQUIV_UNITS = "EQUIV-UNITS"
odxtools/usage.py ADDED
@@ -0,0 +1,9 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+
5
+ class Usage(Enum):
6
+ ECU_SOFTWARE = "ECU-SOFTWARE"
7
+ ECU_COMM = "ECU-COMM"
8
+ APPLICATION = "APPLICATION"
9
+ TESTER = "TESTER"
odxtools/utils.py CHANGED
@@ -2,6 +2,9 @@
2
2
  import dataclasses
3
3
  import re
4
4
  from typing import TYPE_CHECKING, Any, Dict, Optional
5
+ from xml.etree import ElementTree
6
+
7
+ from .exceptions import odxraise
5
8
 
6
9
  if TYPE_CHECKING:
7
10
  from .database import Database
@@ -9,6 +12,32 @@ if TYPE_CHECKING:
9
12
  from .snrefcontext import SnRefContext
10
13
 
11
14
 
15
+ def read_hex_binary(et_element: Optional[ElementTree.Element]) -> Optional[int]:
16
+ """Convert the contents of an xsd:hexBinary to an integer
17
+ """
18
+ if et_element is None:
19
+ return None
20
+
21
+ if (bytes_str := et_element.text) is None:
22
+ # tag exists but is immediately terminated ("<FOO />"). we
23
+ # treat this like an empty string.
24
+ return 0
25
+
26
+ # The XSD uses the type xsd:hexBinary and xsd:hexBinary allows for
27
+ # leading/trailing whitespace and empty strings whilst `int(x,
28
+ # 16)` raises an exception if one of these things happen.
29
+ bytes_str = bytes_str.strip()
30
+ if len(bytes_str) == 0:
31
+ return 0
32
+
33
+ try:
34
+ return int(bytes_str, 16)
35
+ except Exception as e:
36
+ odxraise(f"Caught exception while parsing hex string `{bytes_str}`"
37
+ f" of {et_element.tag}: {e}")
38
+ return None
39
+
40
+
12
41
  def retarget_snrefs(database: "Database",
13
42
  diag_layer: "DiagLayer",
14
43
  context: Optional["SnRefContext"] = None) -> None:
odxtools/validtype.py ADDED
@@ -0,0 +1,9 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from enum import Enum
3
+
4
+
5
+ class ValidType(Enum):
6
+ VALID = "VALID"
7
+ NOT_VALID = "NOT-VALID"
8
+ NOT_DEFINED = "NOT-DEFINED"
9
+ NOT_AVAILABLE = "NOT-AVAILABLE"
odxtools/version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '9.6.1'
21
- __version_tuple__ = version_tuple = (9, 6, 1)
20
+ __version__ = version = '9.7.0'
21
+ __version_tuple__ = version_tuple = (9, 7, 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: odxtools
3
- Version: 9.6.1
3
+ Version: 9.7.0
4
4
  Summary: Utilities to work with the ODX standard for automotive diagnostics
5
5
  Author-email: Katrin Bauer <katrin.bauer@mbition.io>, Andreas Lauser <andreas.lauser@mbition.io>, Ayoub Kaanich <kayoub5@live.com>
6
6
  Maintainer-email: Andreas Lauser <andreas.lauser@mbition.io>, Ayoub Kaanich <kayoub5@live.com>