odxtools 7.1.1__py3-none-any.whl → 7.2.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 (130) hide show
  1. odxtools/__init__.py +6 -4
  2. odxtools/additionalaudience.py +3 -5
  3. odxtools/admindata.py +5 -7
  4. odxtools/audience.py +3 -5
  5. odxtools/basecomparam.py +3 -5
  6. odxtools/basicstructure.py +10 -17
  7. odxtools/cli/_parser_utils.py +1 -1
  8. odxtools/cli/_print_utils.py +3 -2
  9. odxtools/cli/compare.py +1 -1
  10. odxtools/companydata.py +5 -7
  11. odxtools/companydocinfo.py +7 -8
  12. odxtools/companyrevisioninfo.py +3 -5
  13. odxtools/companyspecificinfo.py +8 -9
  14. odxtools/comparam.py +4 -6
  15. odxtools/comparaminstance.py +6 -8
  16. odxtools/comparamspec.py +14 -13
  17. odxtools/comparamsubset.py +17 -16
  18. odxtools/complexcomparam.py +5 -7
  19. odxtools/compumethods/compuconst.py +31 -0
  20. odxtools/compumethods/compudefaultvalue.py +27 -0
  21. odxtools/compumethods/compuinternaltophys.py +39 -0
  22. odxtools/compumethods/compuinversevalue.py +7 -0
  23. odxtools/compumethods/compumethod.py +67 -12
  24. odxtools/compumethods/compuphystointernal.py +39 -0
  25. odxtools/compumethods/compuscale.py +15 -26
  26. odxtools/compumethods/createanycompumethod.py +14 -160
  27. odxtools/compumethods/identicalcompumethod.py +31 -6
  28. odxtools/compumethods/linearcompumethod.py +69 -189
  29. odxtools/compumethods/linearsegment.py +193 -0
  30. odxtools/compumethods/scalelinearcompumethod.py +132 -26
  31. odxtools/compumethods/tabintpcompumethod.py +119 -99
  32. odxtools/compumethods/texttablecompumethod.py +107 -43
  33. odxtools/createanydiagcodedtype.py +10 -67
  34. odxtools/database.py +68 -62
  35. odxtools/dataobjectproperty.py +10 -19
  36. odxtools/description.py +47 -0
  37. odxtools/determinenumberofitems.py +4 -5
  38. odxtools/diagcodedtype.py +29 -12
  39. odxtools/diagcomm.py +10 -6
  40. odxtools/diagdatadictionaryspec.py +20 -21
  41. odxtools/diaglayer.py +34 -5
  42. odxtools/diaglayercontainer.py +17 -11
  43. odxtools/diaglayerraw.py +20 -21
  44. odxtools/diagnostictroublecode.py +7 -8
  45. odxtools/diagservice.py +9 -7
  46. odxtools/docrevision.py +5 -7
  47. odxtools/dopbase.py +7 -8
  48. odxtools/dtcdop.py +5 -8
  49. odxtools/dynamicendmarkerfield.py +22 -9
  50. odxtools/dynamiclengthfield.py +5 -11
  51. odxtools/element.py +4 -3
  52. odxtools/endofpdufield.py +0 -2
  53. odxtools/environmentdatadescription.py +4 -6
  54. odxtools/exceptions.py +1 -1
  55. odxtools/field.py +9 -9
  56. odxtools/functionalclass.py +3 -5
  57. odxtools/inputparam.py +3 -5
  58. odxtools/leadinglengthinfotype.py +15 -2
  59. odxtools/loadfile.py +64 -0
  60. odxtools/minmaxlengthtype.py +20 -2
  61. odxtools/modification.py +3 -5
  62. odxtools/multiplexer.py +7 -14
  63. odxtools/multiplexercase.py +4 -6
  64. odxtools/multiplexerdefaultcase.py +4 -6
  65. odxtools/multiplexerswitchkey.py +4 -5
  66. odxtools/negoutputparam.py +3 -5
  67. odxtools/outputparam.py +3 -5
  68. odxtools/parameterinfo.py +3 -3
  69. odxtools/parameters/codedconstparameter.py +2 -14
  70. odxtools/parameters/lengthkeyparameter.py +3 -17
  71. odxtools/parameters/nrcconstparameter.py +2 -14
  72. odxtools/parameters/parameter.py +22 -22
  73. odxtools/parameters/parameterwithdop.py +6 -8
  74. odxtools/parameters/physicalconstantparameter.py +5 -8
  75. odxtools/parameters/reservedparameter.py +4 -3
  76. odxtools/parameters/tablekeyparameter.py +6 -9
  77. odxtools/parameters/tablestructparameter.py +6 -8
  78. odxtools/parameters/valueparameter.py +5 -8
  79. odxtools/paramlengthinfotype.py +19 -6
  80. odxtools/parentref.py +15 -1
  81. odxtools/physicaldimension.py +3 -5
  82. odxtools/progcode.py +18 -7
  83. odxtools/protstack.py +3 -5
  84. odxtools/relateddoc.py +7 -9
  85. odxtools/request.py +8 -0
  86. odxtools/response.py +8 -0
  87. odxtools/scaleconstr.py +3 -3
  88. odxtools/singleecujob.py +12 -10
  89. odxtools/snrefcontext.py +29 -0
  90. odxtools/specialdata.py +3 -5
  91. odxtools/specialdatagroup.py +5 -7
  92. odxtools/specialdatagroupcaption.py +3 -6
  93. odxtools/standardlengthtype.py +27 -2
  94. odxtools/state.py +3 -5
  95. odxtools/statechart.py +9 -11
  96. odxtools/statetransition.py +4 -9
  97. odxtools/staticfield.py +4 -8
  98. odxtools/table.py +7 -8
  99. odxtools/tablerow.py +7 -6
  100. odxtools/teammember.py +3 -5
  101. odxtools/templates/comparam-spec.odx-c.xml.jinja2 +2 -5
  102. odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +2 -5
  103. odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -5
  104. odxtools/templates/macros/printComparamRef.xml.jinja2 +5 -12
  105. odxtools/templates/macros/printCompuMethod.xml.jinja2 +153 -0
  106. odxtools/templates/macros/printDOP.xml.jinja2 +10 -132
  107. odxtools/templates/macros/printDescription.xml.jinja2 +18 -0
  108. odxtools/templates/macros/printElementId.xml.jinja2 +3 -3
  109. odxtools/templates/macros/printMux.xml.jinja2 +3 -2
  110. odxtools/templates/macros/printTable.xml.jinja2 +2 -3
  111. odxtools/unit.py +3 -5
  112. odxtools/unitgroup.py +3 -5
  113. odxtools/unitspec.py +9 -10
  114. odxtools/utils.py +1 -26
  115. odxtools/version.py +2 -2
  116. odxtools/{write_pdx_file.py → writepdxfile.py} +19 -10
  117. odxtools/xdoc.py +3 -5
  118. {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/METADATA +1 -1
  119. odxtools-7.2.0.dist-info/RECORD +192 -0
  120. {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/WHEEL +1 -1
  121. odxtools/createcompanydatas.py +0 -17
  122. odxtools/createsdgs.py +0 -19
  123. odxtools/load_file.py +0 -13
  124. odxtools/load_odx_d_file.py +0 -6
  125. odxtools/load_pdx_file.py +0 -8
  126. odxtools-7.1.1.dist-info/RECORD +0 -186
  127. /odxtools/templates/{index.xml.xml.jinja2 → index.xml.jinja2} +0 -0
  128. {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/LICENSE +0 -0
  129. {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/entry_points.txt +0 -0
  130. {odxtools-7.1.1.dist-info → odxtools-7.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,29 @@
1
+ # SPDX-License-Identifier: MIT
2
+ from dataclasses import dataclass
3
+ from typing import TYPE_CHECKING, List, Optional
4
+
5
+ if TYPE_CHECKING:
6
+ from .database import Database
7
+ from .diaglayer import DiagLayer
8
+ from .diagservice import DiagService
9
+ from .parameters.parameter import Parameter
10
+ from .request import Request
11
+ from .response import Response
12
+ from .singleecujob import SingleEcuJob
13
+ from .statechart import StateChart
14
+
15
+
16
+ @dataclass
17
+ class SnRefContext:
18
+ """Represents the context for which a short name reference ought
19
+ to be resolved
20
+ """
21
+
22
+ database: Optional["Database"] = None
23
+ diag_layer: Optional["DiagLayer"] = None
24
+ diag_service: Optional["DiagService"] = None
25
+ single_ecu_job: Optional["SingleEcuJob"] = None
26
+ request: Optional["Request"] = None
27
+ response: Optional["Response"] = None
28
+ parameters: Optional[List["Parameter"]] = None
29
+ state_chart: Optional["StateChart"] = None
odxtools/specialdata.py CHANGED
@@ -1,12 +1,10 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
3
+ from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
7
-
8
- if TYPE_CHECKING:
9
- from .diaglayer import DiagLayer
7
+ from .snrefcontext import SnRefContext
10
8
 
11
9
 
12
10
  @dataclass
@@ -21,7 +19,7 @@ class SpecialData:
21
19
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
22
20
  pass
23
21
 
24
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
22
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
25
23
  pass
26
24
 
27
25
  @staticmethod
@@ -1,15 +1,13 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
3
+ from typing import Any, Dict, List, Optional, Union
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
7
+ from .snrefcontext import SnRefContext
7
8
  from .specialdata import SpecialData
8
9
  from .specialdatagroupcaption import SpecialDataGroupCaption
9
10
 
10
- if TYPE_CHECKING:
11
- from .diaglayer import DiagLayer
12
-
13
11
 
14
12
  @dataclass
15
13
  class SpecialDataGroup:
@@ -72,11 +70,11 @@ class SpecialDataGroup:
72
70
  for val in self.values:
73
71
  val._resolve_odxlinks(odxlinks)
74
72
 
75
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
73
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
76
74
  # resolve the SNREFs of the caption, but only if the caption
77
75
  # was specified by value, not by reference
78
76
  if self.sdg_caption is not None and self.sdg_caption_ref is None:
79
- self.sdg_caption._resolve_snrefs(diag_layer)
77
+ self.sdg_caption._resolve_snrefs(context)
80
78
 
81
79
  for val in self.values:
82
- val._resolve_snrefs(diag_layer)
80
+ val._resolve_snrefs(context)
@@ -1,16 +1,13 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # import warnings
3
2
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import Any, Dict, List
5
4
  from xml.etree import ElementTree
6
5
 
7
6
  from .element import IdentifiableElement
8
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
+ from .snrefcontext import SnRefContext
9
9
  from .utils import dataclass_fields_asdict
10
10
 
11
- if TYPE_CHECKING:
12
- from .diaglayer import DiagLayer
13
-
14
11
 
15
12
  @dataclass
16
13
  class SpecialDataGroupCaption(IdentifiableElement):
@@ -32,5 +29,5 @@ class SpecialDataGroupCaption(IdentifiableElement):
32
29
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
33
30
  pass
34
31
 
35
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
32
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
36
33
  pass
@@ -1,6 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Literal, Optional
3
+ from typing import List, Literal, Optional
4
+ from xml.etree import ElementTree
4
5
 
5
6
  from typing_extensions import override
6
7
 
@@ -8,7 +9,9 @@ from .decodestate import DecodeState
8
9
  from .diagcodedtype import DctType, DiagCodedType
9
10
  from .encodestate import EncodeState
10
11
  from .exceptions import odxassert, odxraise, odxrequire
11
- from .odxtypes import AtomicOdxType, DataType
12
+ from .odxlink import OdxDocFragment
13
+ from .odxtypes import AtomicOdxType, DataType, odxstr_to_bool
14
+ from .utils import dataclass_fields_asdict
12
15
 
13
16
 
14
17
  @dataclass
@@ -18,6 +21,28 @@ class StandardLengthType(DiagCodedType):
18
21
  bit_mask: Optional[int]
19
22
  is_condensed_raw: Optional[bool]
20
23
 
24
+ @staticmethod
25
+ @override
26
+ def from_et(et_element: ElementTree.Element,
27
+ doc_frags: List[OdxDocFragment]) -> "StandardLengthType":
28
+ kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
29
+
30
+ bit_length = int(odxrequire(et_element.findtext("BIT-LENGTH")))
31
+ bit_mask = None
32
+ if (bit_mask_str := et_element.findtext("BIT-MASK")) is not None:
33
+ # The XSD uses the type xsd:hexBinary
34
+ # xsd:hexBinary allows for leading/trailing whitespace, empty strings, and it only allows an even
35
+ # number of hex digits, while some of the examples shown in the ODX specification exhibit an
36
+ # odd number of hex digits.
37
+ # This causes a validation paradox, so we try to be flexible
38
+ bit_mask_str = bit_mask_str.strip()
39
+ if len(bit_mask_str):
40
+ bit_mask = int(bit_mask_str, 16)
41
+ is_condensed_raw = odxstr_to_bool(et_element.get("IS-CONDENSED"))
42
+
43
+ return StandardLengthType(
44
+ bit_length=bit_length, bit_mask=bit_mask, is_condensed_raw=is_condensed_raw, **kwargs)
45
+
21
46
  @property
22
47
  def dct_type(self) -> DctType:
23
48
  return "STANDARD-LENGTH-TYPE"
odxtools/state.py CHANGED
@@ -1,15 +1,13 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
+ from .snrefcontext import SnRefContext
8
9
  from .utils import dataclass_fields_asdict
9
10
 
10
- if TYPE_CHECKING:
11
- from .diaglayer import DiagLayer
12
-
13
11
 
14
12
  @dataclass
15
13
  class State(IdentifiableElement):
@@ -29,5 +27,5 @@ class State(IdentifiableElement):
29
27
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
30
28
  pass
31
29
 
32
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
30
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
33
31
  pass
odxtools/statechart.py CHANGED
@@ -1,19 +1,17 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .exceptions import odxrequire
8
8
  from .nameditemlist import NamedItemList
9
9
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
10
+ from .snrefcontext import SnRefContext
10
11
  from .state import State
11
12
  from .statetransition import StateTransition
12
13
  from .utils import dataclass_fields_asdict
13
14
 
14
- if TYPE_CHECKING:
15
- from .diaglayer import DiagLayer
16
-
17
15
 
18
16
  @dataclass
19
17
  class StateChart(IdentifiableElement):
@@ -68,7 +66,9 @@ class StateChart(IdentifiableElement):
68
66
  for st in self.states:
69
67
  st._resolve_odxlinks(odxlinks)
70
68
 
71
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
69
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
70
+ context.state_chart = self
71
+
72
72
  # For now, we assume that the start state short name reference
73
73
  # points to a local state of the state chart. TODO: The XSD
74
74
  # allows to define state charts without any states, yet the
@@ -78,11 +78,9 @@ class StateChart(IdentifiableElement):
78
78
  self._start_state = resolve_snref(self.start_state_snref, self.states, State)
79
79
 
80
80
  for st in self.states:
81
- st._resolve_snrefs(diag_layer)
81
+ st._resolve_snrefs(context)
82
82
 
83
83
  for strans in self.state_transitions:
84
- # note that the signature of the state transition's
85
- # _resolve_snrefs() method is non-standard as the
86
- # namespace of these SNREFs is the state chart, not the
87
- # whole diag layer...
88
- strans._resolve_snrefs(diag_layer, states=self.states)
84
+ strans._resolve_snrefs(context)
85
+
86
+ context.state_chart = None
@@ -1,17 +1,15 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, Iterable, List
3
+ from typing import Any, Dict, List
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .exceptions import odxrequire
8
8
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
9
+ from .snrefcontext import SnRefContext
9
10
  from .state import State
10
11
  from .utils import dataclass_fields_asdict
11
12
 
12
- if TYPE_CHECKING:
13
- from .diaglayer import DiagLayer
14
-
15
13
 
16
14
  @dataclass
17
15
  class StateTransition(IdentifiableElement):
@@ -50,10 +48,7 @@ class StateTransition(IdentifiableElement):
50
48
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
51
49
  pass
52
50
 
53
- # note that the signature of this method is non-standard because
54
- # the namespace of these SNREFs is the corresponding state
55
- # chart. To mitigate this a bit, the non-standard parameters are
56
- # keyword-only...
57
- def _resolve_snrefs(self, diag_layer: "DiagLayer", *, states: Iterable[State]) -> None:
51
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
52
+ states = odxrequire(context.state_chart).states
58
53
  self._source_state = resolve_snref(self.source_snref, states, State)
59
54
  self._target_state = resolve_snref(self.target_snref, states, State)
odxtools/staticfield.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Sequence
3
+ from typing import Any, Dict, List, Sequence
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from typing_extensions import override
@@ -11,11 +11,9 @@ from .exceptions import odxassert, odxraise, odxrequire
11
11
  from .field import Field
12
12
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
13
13
  from .odxtypes import ParameterValue
14
+ from .snrefcontext import SnRefContext
14
15
  from .utils import dataclass_fields_asdict
15
16
 
16
- if TYPE_CHECKING:
17
- from .diaglayer import DiagLayer
18
-
19
17
 
20
18
  @dataclass
21
19
  class StaticField(Field):
@@ -44,8 +42,8 @@ class StaticField(Field):
44
42
  super()._resolve_odxlinks(odxlinks)
45
43
 
46
44
  @override
47
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
48
- super()._resolve_snrefs(diag_layer)
45
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
46
+ super()._resolve_snrefs(context)
49
47
 
50
48
  @override
51
49
  def encode_into_pdu(self, physical_value: ParameterValue, encode_state: EncodeState) -> None:
@@ -89,7 +87,6 @@ class StaticField(Field):
89
87
  "No bit position can be specified for static length fields!")
90
88
 
91
89
  orig_origin = decode_state.origin_byte_position
92
- orig_cursor = decode_state.cursor_byte_position
93
90
  decode_state.origin_byte_position = decode_state.cursor_byte_position
94
91
 
95
92
  result: List[ParameterValue] = []
@@ -106,6 +103,5 @@ class StaticField(Field):
106
103
  decode_state.cursor_byte_position = orig_cursor + self.item_byte_size
107
104
 
108
105
  decode_state.origin_byte_position = orig_origin
109
- decode_state.cursor_byte_position = max(orig_cursor, decode_state.cursor_byte_position)
110
106
 
111
107
  return result
odxtools/table.py CHANGED
@@ -1,22 +1,19 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
3
+ from typing import Any, Dict, List, Optional, Union
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
7
- from .createsdgs import create_sdgs_from_et
8
7
  from .dataobjectproperty import DataObjectProperty
9
8
  from .element import IdentifiableElement
10
9
  from .exceptions import odxassert
11
10
  from .nameditemlist import NamedItemList
12
11
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
12
+ from .snrefcontext import SnRefContext
13
13
  from .specialdatagroup import SpecialDataGroup
14
14
  from .tablerow import TableRow
15
15
  from .utils import dataclass_fields_asdict
16
16
 
17
- if TYPE_CHECKING:
18
- from .diaglayer import DiagLayer
19
-
20
17
 
21
18
  @dataclass
22
19
  class Table(IdentifiableElement):
@@ -50,7 +47,9 @@ class Table(IdentifiableElement):
50
47
  elif sub_elem.tag == "TABLE-ROW-REF":
51
48
  table_rows_raw.append(OdxLinkRef.from_et(sub_elem, doc_frags))
52
49
 
53
- sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
50
+ sdgs = [
51
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
52
+ ]
54
53
 
55
54
  return Table(
56
55
  semantic=semantic,
@@ -99,7 +98,7 @@ class Table(IdentifiableElement):
99
98
 
100
99
  self._table_rows = NamedItemList(table_rows)
101
100
 
102
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
101
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
103
102
  for table_row_wrapper in self.table_rows_raw:
104
103
  if isinstance(table_row_wrapper, TableRow):
105
- table_row_wrapper._resolve_snrefs(diag_layer)
104
+ table_row_wrapper._resolve_snrefs(context)
odxtools/tablerow.py CHANGED
@@ -4,18 +4,17 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .basicstructure import BasicStructure
7
- from .createsdgs import create_sdgs_from_et
8
7
  from .dataobjectproperty import DataObjectProperty
9
8
  from .dtcdop import DtcDop
10
9
  from .element import IdentifiableElement
11
10
  from .exceptions import odxassert, odxraise, odxrequire
12
11
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
13
12
  from .odxtypes import AtomicOdxType
13
+ from .snrefcontext import SnRefContext
14
14
  from .specialdatagroup import SpecialDataGroup
15
15
  from .utils import dataclass_fields_asdict
16
16
 
17
17
  if TYPE_CHECKING:
18
- from .diaglayer import DiagLayer
19
18
  from .table import Table
20
19
 
21
20
 
@@ -70,7 +69,9 @@ class TableRow(IdentifiableElement):
70
69
  dop_snref: Optional[str] = None
71
70
  if (dop_snref_elem := et_element.find("DATA-OBJECT-PROP-SNREF")) is not None:
72
71
  dop_snref = dop_snref_elem.attrib["SHORT-NAME"]
73
- sdgs = create_sdgs_from_et(et_element.find("SDGS"), doc_frags)
72
+ sdgs = [
73
+ SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
74
+ ]
74
75
 
75
76
  return TableRow(
76
77
  table_ref=table_ref,
@@ -107,7 +108,7 @@ class TableRow(IdentifiableElement):
107
108
  for sdg in self.sdgs:
108
109
  sdg._resolve_odxlinks(odxlinks)
109
110
 
110
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
111
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
111
112
  # convert the raw key into the proper internal
112
113
  # representation. note that we cannot do this earlier because
113
114
  # the table's ODXLINKs must be resolved and the order of
@@ -125,7 +126,7 @@ class TableRow(IdentifiableElement):
125
126
  else:
126
127
  self._key = key_dop.physical_type.base_data_type.from_string(self.key_raw)
127
128
 
128
- ddd_spec = diag_layer.diag_data_dictionary_spec
129
+ ddd_spec = odxrequire(context.diag_layer).diag_data_dictionary_spec
129
130
 
130
131
  if self.structure_snref is not None:
131
132
  self._structure = resolve_snref(self.structure_snref, ddd_spec.structures,
@@ -135,7 +136,7 @@ class TableRow(IdentifiableElement):
135
136
  DataObjectProperty)
136
137
 
137
138
  for sdg in self.sdgs:
138
- sdg._resolve_snrefs(diag_layer)
139
+ sdg._resolve_snrefs(context)
139
140
 
140
141
  @property
141
142
  def table(self) -> "Table":
odxtools/teammember.py CHANGED
@@ -1,16 +1,14 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
3
+ from typing import Any, Dict, List, Optional
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .exceptions import odxrequire
8
8
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
9
+ from .snrefcontext import SnRefContext
9
10
  from .utils import dataclass_fields_asdict
10
11
 
11
- if TYPE_CHECKING:
12
- from .diaglayer import DiagLayer
13
-
14
12
 
15
13
  @dataclass
16
14
  class TeamMember(IdentifiableElement):
@@ -55,5 +53,5 @@ class TeamMember(IdentifiableElement):
55
53
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
56
54
  pass
57
55
 
58
- def _resolve_snrefs(self, diag_layer: "DiagLayer") -> None:
56
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
59
57
  pass
@@ -8,6 +8,7 @@
8
8
  {%- import('macros/printAdminData.xml.jinja2') as pad -%}
9
9
  {%- import('macros/printCompanyData.xml.jinja2') as pcd -%}
10
10
  {%- import('macros/printProtStack.xml.jinja2') as pps %}
11
+ {%- import('macros/printDescription.xml.jinja2') as pd %}
11
12
  {#- -#}
12
13
 
13
14
  <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
@@ -18,11 +19,7 @@
18
19
  {%- if comparam_spec.long_name is not none %}
19
20
  <LONG-NAME>{{comparam_spec.long_name|e}}</LONG-NAME>
20
21
  {%- endif %}
21
- {%- if comparam_spec.description and comparam_spec.description.strip() %}
22
- <DESC>
23
- {{comparam_spec.description}}
24
- </DESC>
25
- {%- endif %}
22
+ {{pd.printDescription(comparam_spec.description)}}
26
23
  {%- if comparam_spec.admin_data is not none %}
27
24
  {{- pad.printAdminData(comparam_spec.admin_data) | indent(3) }}
28
25
  {%- endif %}
@@ -11,6 +11,7 @@
11
11
  {%- import('macros/printDOP.xml.jinja2') as pdop %}
12
12
  {%- import('macros/printUnitSpec.xml.jinja2') as pus %}
13
13
  {%- import('macros/printSpecialData.xml.jinja2') as psd %}
14
+ {%- import('macros/printDescription.xml.jinja2') as pd %}
14
15
  {#- -#}
15
16
 
16
17
  <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
@@ -22,11 +23,7 @@
22
23
  {%- if comparam_subset.long_name is not none %}
23
24
  <LONG-NAME>{{comparam_subset.long_name|e}}</LONG-NAME>
24
25
  {%- endif %}
25
- {%- if comparam_subset.description and comparam_subset.description.strip() %}
26
- <DESC>
27
- {{comparam_subset.description}}
28
- </DESC>
29
- {%- endif %}
26
+ {{pd.printDescription(comparam_subset.description)}}
30
27
  {%- if comparam_subset.admin_data is not none %}
31
28
  {{- pad.printAdminData(comparam_subset.admin_data) | indent(3) }}
32
29
  {%- endif %}
@@ -5,6 +5,7 @@
5
5
 
6
6
  {%- import('macros/printElementId.xml.jinja2') as peid %}
7
7
  {%- import('macros/printSpecialData.xml.jinja2') as psd %}
8
+ {%- import('macros/printDescription.xml.jinja2') as pd %}
8
9
 
9
10
  {%- macro printCompanyData(company_data) %}
10
11
  <COMPANY-DATA ID="{{company_data.odx_id.local_id}}">
@@ -81,11 +82,7 @@
81
82
  {%- endif %}
82
83
  </XDOC>
83
84
  {%- endif %}
84
- {%- if rd.description is not none %}
85
- <DESC>
86
- {{rd.description}}
87
- </DESC>
88
- {%- endif %}
85
+ {{pd.printDescription(rd.description)}}
89
86
  </RELATED-DOC>
90
87
  {%- endfor %}
91
88
  </RELATED-DOCS>
@@ -3,6 +3,7 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
  -#}
5
5
  {%- import('macros/printComparam.xml.jinja2') as pcp %}
6
+ {%- import('macros/printDescription.xml.jinja2') as pd %}
6
7
  {#- -#}
7
8
 
8
9
  {%- macro printComparamRef(cp) %}
@@ -11,27 +12,19 @@
11
12
  DOCTYPE="COMPARAM-SUBSET">
12
13
  {%- if cp.value is string %}
13
14
  <SIMPLE-VALUE>{{cp.value}}</SIMPLE-VALUE>
14
- {%- if cp.description %}
15
- <DESC>{{cp.description}}</DESC>
16
- {%- endif %}
15
+ {{ pd.printDescription(cp.description) }}
17
16
  {%- elif cp.value is iterable %}
18
17
  {%- if hasattr(cp.value, "hex") %}
19
18
  {#- the value has a hex() method. assume that is a bytes or bytestring #}
20
19
  <SIMPLE-VALUE>{{cp.value.hex().upper()}}</SIMPLE-VALUE>
21
- {%- if cp.description %}
22
- <DESC>{{cp.description}}</DESC>
23
- {%- endif %}
20
+ {{ pd.printDescription(cp.description) }}
24
21
  {%- else %}
25
22
  {{ pcp.printComplexValue(cp.value)|indent(1) }}
26
- {%- if cp.description %}
27
- <DESC>{{cp.description}}</DESC>
28
- {%- endif %}
23
+ {{ pd.printDescription(cp.description) }}
29
24
  {%- endif %}
30
25
  {%- else %}
31
26
  <SIMPLE-VALUE>{{cp.value}}</SIMPLE-VALUE>
32
- {%- if cp.description %}
33
- <DESC>{{cp.description}}</DESC>
34
- {%- endif %}
27
+ {{ pd.printDescription(cp.description) }}
35
28
  {%- endif %}
36
29
  {%- if cp.prot_stack_snref is not none %}
37
30
  <PROT-STACK-SNREF SHORT-NAME="{{cp.prot_stack_snref}}"/>