odxtools 10.0.0__py3-none-any.whl → 10.1.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 (175) hide show
  1. odxtools/additionalaudience.py +5 -5
  2. odxtools/admindata.py +10 -9
  3. odxtools/audience.py +15 -15
  4. odxtools/basecomparam.py +7 -6
  5. odxtools/basevariantpattern.py +7 -7
  6. odxtools/basicstructure.py +9 -9
  7. odxtools/cli/_print_utils.py +1 -1
  8. odxtools/cli/browse.py +1 -1
  9. odxtools/cli/compare.py +143 -170
  10. odxtools/cli/list.py +1 -1
  11. odxtools/commrelation.py +14 -13
  12. odxtools/companydata.py +11 -11
  13. odxtools/companydocinfo.py +11 -13
  14. odxtools/companyrevisioninfo.py +7 -7
  15. odxtools/companyspecificinfo.py +9 -11
  16. odxtools/comparam.py +6 -5
  17. odxtools/comparaminstance.py +10 -10
  18. odxtools/comparamspec.py +8 -9
  19. odxtools/comparamsubset.py +14 -22
  20. odxtools/complexcomparam.py +10 -10
  21. odxtools/complexdop.py +1 -1
  22. odxtools/compositecodec.py +3 -3
  23. odxtools/compumethods/compucodecompumethod.py +4 -4
  24. odxtools/compumethods/compuconst.py +3 -3
  25. odxtools/compumethods/compudefaultvalue.py +2 -2
  26. odxtools/compumethods/compuinternaltophys.py +11 -10
  27. odxtools/compumethods/compumethod.py +8 -7
  28. odxtools/compumethods/compuphystointernal.py +11 -10
  29. odxtools/compumethods/compurationalcoeffs.py +6 -6
  30. odxtools/compumethods/compuscale.py +14 -14
  31. odxtools/compumethods/createanycompumethod.py +12 -12
  32. odxtools/compumethods/identicalcompumethod.py +4 -4
  33. odxtools/compumethods/limit.py +8 -8
  34. odxtools/compumethods/linearcompumethod.py +4 -4
  35. odxtools/compumethods/linearsegment.py +8 -8
  36. odxtools/compumethods/ratfunccompumethod.py +4 -4
  37. odxtools/compumethods/ratfuncsegment.py +8 -8
  38. odxtools/compumethods/scalelinearcompumethod.py +5 -5
  39. odxtools/compumethods/scaleratfunccompumethod.py +4 -4
  40. odxtools/compumethods/tabintpcompumethod.py +12 -12
  41. odxtools/compumethods/texttablecompumethod.py +4 -4
  42. odxtools/createanycomparam.py +4 -4
  43. odxtools/createanydiagcodedtype.py +7 -7
  44. odxtools/database.py +28 -26
  45. odxtools/dataobjectproperty.py +15 -16
  46. odxtools/description.py +7 -7
  47. odxtools/determinenumberofitems.py +6 -5
  48. odxtools/diagcodedtype.py +6 -6
  49. odxtools/diagcomm.py +26 -27
  50. odxtools/diagdatadictionaryspec.py +34 -34
  51. odxtools/diaglayercontainer.py +32 -31
  52. odxtools/diaglayers/basevariant.py +5 -4
  53. odxtools/diaglayers/basevariantraw.py +18 -19
  54. odxtools/diaglayers/diaglayer.py +5 -4
  55. odxtools/diaglayers/diaglayerraw.py +39 -48
  56. odxtools/diaglayers/ecushareddata.py +6 -6
  57. odxtools/diaglayers/ecushareddataraw.py +11 -12
  58. odxtools/diaglayers/ecuvariant.py +5 -4
  59. odxtools/diaglayers/ecuvariantraw.py +17 -18
  60. odxtools/diaglayers/functionalgroup.py +5 -5
  61. odxtools/diaglayers/functionalgroupraw.py +13 -14
  62. odxtools/diaglayers/hierarchyelement.py +9 -9
  63. odxtools/diaglayers/hierarchyelementraw.py +8 -9
  64. odxtools/diaglayers/protocol.py +4 -4
  65. odxtools/diaglayers/protocolraw.py +10 -11
  66. odxtools/diagnostictroublecode.py +12 -14
  67. odxtools/diagservice.py +19 -18
  68. odxtools/diagvariable.py +19 -20
  69. odxtools/docrevision.py +14 -13
  70. odxtools/dopbase.py +10 -11
  71. odxtools/dtcconnector.py +6 -5
  72. odxtools/dtcdop.py +15 -15
  73. odxtools/dynamicendmarkerfield.py +6 -6
  74. odxtools/dynamiclengthfield.py +6 -6
  75. odxtools/dyndefinedspec.py +7 -7
  76. odxtools/dynenddopref.py +7 -7
  77. odxtools/dyniddefmodeinfo.py +17 -17
  78. odxtools/ecuvariantpattern.py +6 -7
  79. odxtools/element.py +12 -12
  80. odxtools/endofpdufield.py +6 -7
  81. odxtools/envdataconnector.py +6 -6
  82. odxtools/environmentdata.py +7 -8
  83. odxtools/environmentdatadescription.py +13 -12
  84. odxtools/externalaccessmethod.py +4 -5
  85. odxtools/externaldoc.py +4 -4
  86. odxtools/field.py +12 -11
  87. odxtools/functionalclass.py +7 -7
  88. odxtools/inputparam.py +9 -8
  89. odxtools/internalconstr.py +10 -10
  90. odxtools/leadinglengthinfotype.py +5 -6
  91. odxtools/library.py +7 -6
  92. odxtools/linkeddtcdop.py +7 -6
  93. odxtools/matchingbasevariantparameter.py +5 -5
  94. odxtools/matchingparameter.py +6 -6
  95. odxtools/message.py +1 -1
  96. odxtools/minmaxlengthtype.py +6 -7
  97. odxtools/modification.py +5 -4
  98. odxtools/multiplexer.py +48 -12
  99. odxtools/multiplexercase.py +10 -10
  100. odxtools/multiplexerdefaultcase.py +8 -7
  101. odxtools/multiplexerswitchkey.py +6 -6
  102. odxtools/nameditemlist.py +1 -1
  103. odxtools/negoutputparam.py +6 -6
  104. odxtools/odxcategory.py +12 -24
  105. odxtools/odxdoccontext.py +16 -0
  106. odxtools/odxlink.py +11 -12
  107. odxtools/odxtypes.py +3 -3
  108. odxtools/outputparam.py +7 -6
  109. odxtools/parameters/codedconstparameter.py +6 -6
  110. odxtools/parameters/createanyparameter.py +15 -15
  111. odxtools/parameters/dynamicparameter.py +4 -5
  112. odxtools/parameters/lengthkeyparameter.py +6 -6
  113. odxtools/parameters/matchingrequestparameter.py +4 -4
  114. odxtools/parameters/nrcconstparameter.py +8 -8
  115. odxtools/parameters/parameter.py +12 -13
  116. odxtools/parameters/parameterwithdop.py +9 -9
  117. odxtools/parameters/physicalconstantparameter.py +5 -4
  118. odxtools/parameters/reservedparameter.py +4 -5
  119. odxtools/parameters/systemparameter.py +4 -5
  120. odxtools/parameters/tableentryparameter.py +6 -6
  121. odxtools/parameters/tablekeyparameter.py +12 -12
  122. odxtools/parameters/tablestructparameter.py +9 -9
  123. odxtools/parameters/valueparameter.py +6 -6
  124. odxtools/paramlengthinfotype.py +6 -7
  125. odxtools/parentref.py +12 -10
  126. odxtools/physicaldimension.py +12 -12
  127. odxtools/physicaltype.py +5 -5
  128. odxtools/posresponsesuppressible.py +11 -11
  129. odxtools/preconditionstateref.py +8 -8
  130. odxtools/progcode.py +9 -8
  131. odxtools/protstack.py +8 -7
  132. odxtools/relateddiagcommref.py +5 -5
  133. odxtools/relateddoc.py +8 -7
  134. odxtools/request.py +12 -13
  135. odxtools/response.py +12 -13
  136. odxtools/scaleconstr.py +8 -8
  137. odxtools/singleecujob.py +14 -13
  138. odxtools/snrefcontext.py +1 -1
  139. odxtools/specialdata.py +6 -5
  140. odxtools/specialdatagroup.py +13 -13
  141. odxtools/specialdatagroupcaption.py +5 -4
  142. odxtools/standardlengthtype.py +5 -13
  143. odxtools/state.py +5 -4
  144. odxtools/statechart.py +10 -9
  145. odxtools/statemachine.py +2 -2
  146. odxtools/statetransition.py +7 -7
  147. odxtools/statetransitionref.py +11 -11
  148. odxtools/staticfield.py +5 -4
  149. odxtools/structure.py +5 -5
  150. odxtools/subcomponent.py +18 -16
  151. odxtools/subcomponentparamconnector.py +8 -7
  152. odxtools/subcomponentpattern.py +7 -7
  153. odxtools/swvariable.py +6 -6
  154. odxtools/table.py +20 -21
  155. odxtools/tablediagcommconnector.py +7 -6
  156. odxtools/tablerow.py +57 -36
  157. odxtools/tablerowconnector.py +6 -6
  158. odxtools/teammember.py +14 -13
  159. odxtools/templates/macros/printParentRef.xml.jinja2 +3 -1
  160. odxtools/text.py +4 -4
  161. odxtools/unit.py +9 -8
  162. odxtools/unitgroup.py +9 -8
  163. odxtools/unitspec.py +15 -16
  164. odxtools/variablegroup.py +4 -5
  165. odxtools/variantpattern.py +3 -4
  166. odxtools/version.py +2 -2
  167. odxtools/writepdxfile.py +0 -19
  168. odxtools/xdoc.py +11 -10
  169. {odxtools-10.0.0.dist-info → odxtools-10.1.1.dist-info}/METADATA +1 -1
  170. odxtools-10.1.1.dist-info/RECORD +265 -0
  171. {odxtools-10.0.0.dist-info → odxtools-10.1.1.dist-info}/WHEEL +1 -1
  172. odxtools-10.0.0.dist-info/RECORD +0 -264
  173. {odxtools-10.0.0.dist-info → odxtools-10.1.1.dist-info}/entry_points.txt +0 -0
  174. {odxtools-10.0.0.dist-info → odxtools-10.1.1.dist-info}/licenses/LICENSE +0 -0
  175. {odxtools-10.0.0.dist-info → odxtools-10.1.1.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@
2
2
  from xml.etree import ElementTree
3
3
 
4
4
  from ..exceptions import odxraise, odxrequire
5
- from ..odxlink import OdxDocFragment
5
+ from ..odxdoccontext import OdxDocContext
6
6
  from ..odxtypes import DataType
7
7
  from .compucodecompumethod import CompuCodeCompuMethod
8
8
  from .compumethod import CompuMethod
@@ -15,38 +15,38 @@ from .tabintpcompumethod import TabIntpCompuMethod
15
15
  from .texttablecompumethod import TexttableCompuMethod
16
16
 
17
17
 
18
- def create_any_compu_method_from_et(et_element: ElementTree.Element,
19
- doc_frags: list[OdxDocFragment], *, internal_type: DataType,
18
+ def create_any_compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
19
+ internal_type: DataType,
20
20
  physical_type: DataType) -> CompuMethod:
21
21
  compu_category = odxrequire(et_element.findtext("CATEGORY"))
22
22
 
23
23
  if compu_category == "IDENTICAL":
24
24
  return IdenticalCompuMethod.compu_method_from_et(
25
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
25
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
26
26
  elif compu_category == "LINEAR":
27
27
  return LinearCompuMethod.compu_method_from_et(
28
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
28
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
29
29
  elif compu_category == "SCALE-LINEAR":
30
30
  return ScaleLinearCompuMethod.compu_method_from_et(
31
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
31
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
32
32
  elif compu_category == "RAT-FUNC":
33
33
  return RatFuncCompuMethod.compu_method_from_et(
34
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
34
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
35
35
  elif compu_category == "SCALE-RAT-FUNC":
36
36
  return ScaleRatFuncCompuMethod.compu_method_from_et(
37
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
37
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
38
38
  elif compu_category == "TEXTTABLE":
39
39
  return TexttableCompuMethod.compu_method_from_et(
40
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
40
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
41
41
  elif compu_category == "COMPUCODE":
42
42
  return CompuCodeCompuMethod.compu_method_from_et(
43
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
43
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
44
44
  elif compu_category == "TAB-INTP":
45
45
  return TabIntpCompuMethod.compu_method_from_et(
46
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
46
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
47
47
 
48
48
  # TODO: Implement all categories (never instantiate the CompuMethod base class!)
49
49
  odxraise(f"Warning: Computation category {compu_category} is not implemented!")
50
50
 
51
51
  return IdenticalCompuMethod.compu_method_from_et(
52
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
52
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
@@ -3,13 +3,13 @@ from dataclasses import dataclass
3
3
  from xml.etree import ElementTree
4
4
 
5
5
  from ..exceptions import odxassert
6
- from ..odxlink import OdxDocFragment
6
+ from ..odxdoccontext import OdxDocContext
7
7
  from ..odxtypes import AtomicOdxType, DataType
8
8
  from ..utils import dataclass_fields_asdict
9
9
  from .compumethod import CompuMethod
10
10
 
11
11
 
12
- @dataclass
12
+ @dataclass(kw_only=True)
13
13
  class IdenticalCompuMethod(CompuMethod):
14
14
  """Identical compu methods just pass through the internal value.
15
15
 
@@ -17,11 +17,11 @@ class IdenticalCompuMethod(CompuMethod):
17
17
  """
18
18
 
19
19
  @staticmethod
20
- def compu_method_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
20
+ def compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
21
21
  internal_type: DataType,
22
22
  physical_type: DataType) -> "IdenticalCompuMethod":
23
23
  cm = CompuMethod.compu_method_from_et(
24
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
24
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
25
25
  kwargs = dataclass_fields_asdict(cm)
26
26
 
27
27
  odxassert(
@@ -4,16 +4,16 @@ from typing import Optional, overload
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from ..exceptions import odxraise
7
- from ..odxlink import OdxDocFragment
7
+ from ..odxdoccontext import OdxDocContext
8
8
  from ..odxtypes import AtomicOdxType, DataType, compare_odx_values
9
9
  from .intervaltype import IntervalType
10
10
 
11
11
 
12
- @dataclass
12
+ @dataclass(kw_only=True)
13
13
  class Limit:
14
- value_raw: str | None
15
- value_type: DataType | None
16
- interval_type: IntervalType | None
14
+ value_raw: str | None = None
15
+ value_type: DataType | None = None
16
+ interval_type: IntervalType | None = None
17
17
 
18
18
  @property
19
19
  def value(self) -> AtomicOdxType | None:
@@ -21,18 +21,18 @@ class Limit:
21
21
 
22
22
  @staticmethod
23
23
  @overload
24
- def limit_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment],
24
+ def limit_from_et(et_element: ElementTree.Element, context: OdxDocContext,
25
25
  value_type: DataType | None) -> "Limit":
26
26
  ...
27
27
 
28
28
  @staticmethod
29
29
  @overload
30
- def limit_from_et(et_element: None, doc_frags: list[OdxDocFragment],
30
+ def limit_from_et(et_element: None, context: OdxDocContext,
31
31
  value_type: DataType | None) -> None:
32
32
  ...
33
33
 
34
34
  @staticmethod
35
- def limit_from_et(et_element: ElementTree.Element | None, doc_frags: list[OdxDocFragment],
35
+ def limit_from_et(et_element: ElementTree.Element | None, context: OdxDocContext,
36
36
  value_type: DataType | None) -> Optional["Limit"]:
37
37
 
38
38
  if et_element is None:
@@ -4,7 +4,7 @@ from typing import cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from ..exceptions import DecodeError, EncodeError, odxassert, odxraise
7
- from ..odxlink import OdxDocFragment
7
+ from ..odxdoccontext import OdxDocContext
8
8
  from ..odxtypes import AtomicOdxType, DataType
9
9
  from ..utils import dataclass_fields_asdict
10
10
  from .compucategory import CompuCategory
@@ -12,7 +12,7 @@ from .compumethod import CompuMethod
12
12
  from .linearsegment import LinearSegment
13
13
 
14
14
 
15
- @dataclass
15
+ @dataclass(kw_only=True)
16
16
  class LinearCompuMethod(CompuMethod):
17
17
  """A compu method which does linear interpoation
18
18
 
@@ -30,11 +30,11 @@ class LinearCompuMethod(CompuMethod):
30
30
  return self._segment
31
31
 
32
32
  @staticmethod
33
- def compu_method_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
33
+ def compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
34
34
  internal_type: DataType,
35
35
  physical_type: DataType) -> "LinearCompuMethod":
36
36
  cm = CompuMethod.compu_method_from_et(
37
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
37
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
38
38
  kwargs = dataclass_fields_asdict(cm)
39
39
 
40
40
  return LinearCompuMethod(**kwargs)
@@ -7,7 +7,7 @@ from .compuscale import CompuScale
7
7
  from .limit import Limit
8
8
 
9
9
 
10
- @dataclass
10
+ @dataclass(kw_only=True)
11
11
  class LinearSegment:
12
12
  """Helper class to represent a segment of a piecewise-linear interpolation.
13
13
 
@@ -23,8 +23,8 @@ class LinearSegment:
23
23
  offset: float
24
24
  factor: float
25
25
  denominator: float
26
- internal_lower_limit: Limit | None
27
- internal_upper_limit: Limit | None
26
+ internal_lower_limit: Limit | None = None
27
+ internal_upper_limit: Limit | None = None
28
28
 
29
29
  inverse_value: int | float # value used as inverse if factor is 0
30
30
 
@@ -54,7 +54,7 @@ class LinearSegment:
54
54
  inverse_value: int | float = 0
55
55
  if scale.compu_inverse_value is not None:
56
56
  x = odxrequire(scale.compu_inverse_value).value
57
- if not isinstance(x, int | float):
57
+ if not isinstance(x, (int, float)):
58
58
  odxraise(f"Non-numeric COMPU-INVERSE-VALUE specified ({x!r})")
59
59
  inverse_value = x
60
60
 
@@ -75,7 +75,7 @@ class LinearSegment:
75
75
  self.__compute_physical_limits()
76
76
 
77
77
  def convert_internal_to_physical(self, internal_value: AtomicOdxType) -> float | int:
78
- if not isinstance(internal_value, int | float):
78
+ if not isinstance(internal_value, (int, float)):
79
79
  odxraise(f"Internal values of linear compumethods must "
80
80
  f"either be int or float (is: {type(internal_value).__name__})")
81
81
 
@@ -90,7 +90,7 @@ class LinearSegment:
90
90
  return result
91
91
 
92
92
  def convert_physical_to_internal(self, physical_value: AtomicOdxType) -> float | int:
93
- if not isinstance(physical_value, int | float):
93
+ if not isinstance(physical_value, (int, float)):
94
94
  odxraise(f"Physical values of linear compumethods must "
95
95
  f"either be int or float (is: {type(physical_value).__name__})")
96
96
 
@@ -151,7 +151,7 @@ class LinearSegment:
151
151
  # Do type checks
152
152
  expected_type = self.physical_type.python_type
153
153
  if issubclass(expected_type, float):
154
- if not isinstance(physical_value, int | float):
154
+ if not isinstance(physical_value, (int, float)):
155
155
  return False
156
156
  else:
157
157
  if not isinstance(physical_value, expected_type):
@@ -172,7 +172,7 @@ class LinearSegment:
172
172
  # Do type checks
173
173
  expected_type = self.internal_type.python_type
174
174
  if issubclass(expected_type, float):
175
- if not isinstance(internal_value, int | float):
175
+ if not isinstance(internal_value, (int, float)):
176
176
  return False
177
177
  else:
178
178
  if not isinstance(internal_value, expected_type):
@@ -4,7 +4,7 @@ from typing import cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from ..exceptions import DecodeError, EncodeError, odxassert, odxraise
7
- from ..odxlink import OdxDocFragment
7
+ from ..odxdoccontext import OdxDocContext
8
8
  from ..odxtypes import AtomicOdxType, DataType
9
9
  from ..utils import dataclass_fields_asdict
10
10
  from .compucategory import CompuCategory
@@ -12,7 +12,7 @@ from .compumethod import CompuMethod
12
12
  from .ratfuncsegment import RatFuncSegment
13
13
 
14
14
 
15
- @dataclass
15
+ @dataclass(kw_only=True)
16
16
  class RatFuncCompuMethod(CompuMethod):
17
17
  """A compu method using a rational function
18
18
 
@@ -34,11 +34,11 @@ class RatFuncCompuMethod(CompuMethod):
34
34
  return self._phys_to_int_segment
35
35
 
36
36
  @staticmethod
37
- def compu_method_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
37
+ def compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
38
38
  internal_type: DataType,
39
39
  physical_type: DataType) -> "RatFuncCompuMethod":
40
40
  cm = CompuMethod.compu_method_from_et(
41
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
41
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
42
42
  kwargs = dataclass_fields_asdict(cm)
43
43
 
44
44
  return RatFuncCompuMethod(**kwargs)
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
 
4
4
  from ..exceptions import odxraise, odxrequire
5
5
  from ..odxtypes import AtomicOdxType, DataType
@@ -7,17 +7,17 @@ from .compuscale import CompuScale
7
7
  from .limit import Limit
8
8
 
9
9
 
10
- @dataclass
10
+ @dataclass(kw_only=True)
11
11
  class RatFuncSegment:
12
12
  """Helper class to represent a segment of a piecewise rational function.
13
13
  """
14
14
  value_type: DataType
15
15
 
16
- numerator_coeffs: list[int | float]
17
- denominator_coeffs: list[int | float]
16
+ numerator_coeffs: list[int | float] = field(default_factory=list)
17
+ denominator_coeffs: list[int | float] = field(default_factory=list)
18
18
 
19
- lower_limit: Limit | None
20
- upper_limit: Limit | None
19
+ lower_limit: Limit | None = None
20
+ upper_limit: Limit | None = None
21
21
 
22
22
  @staticmethod
23
23
  def from_compu_scale(scale: CompuScale, value_type: DataType) -> "RatFuncSegment":
@@ -39,7 +39,7 @@ class RatFuncSegment:
39
39
  value_type=scale.range_type)
40
40
 
41
41
  def convert(self, value: AtomicOdxType) -> float | int:
42
- if not isinstance(value, int | float):
42
+ if not isinstance(value, (int, float)):
43
43
  odxraise(f"Internal values of linear compumethods must "
44
44
  f"either be int or float (is: {type(value).__name__})")
45
45
 
@@ -69,7 +69,7 @@ class RatFuncSegment:
69
69
  # Do type checks
70
70
  expected_type = self.value_type.python_type
71
71
  if issubclass(expected_type, float):
72
- if not isinstance(value, int | float):
72
+ if not isinstance(value, (int, float)):
73
73
  return False
74
74
  else:
75
75
  if not isinstance(value, expected_type):
@@ -4,7 +4,7 @@ from typing import cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from ..exceptions import DecodeError, EncodeError, odxassert, odxraise
7
- from ..odxlink import OdxDocFragment
7
+ from ..odxdoccontext import OdxDocContext
8
8
  from ..odxtypes import AtomicOdxType, DataType
9
9
  from ..utils import dataclass_fields_asdict
10
10
  from .compucategory import CompuCategory
@@ -13,7 +13,7 @@ from .intervaltype import IntervalType
13
13
  from .linearsegment import LinearSegment
14
14
 
15
15
 
16
- @dataclass
16
+ @dataclass(kw_only=True)
17
17
  class ScaleLinearCompuMethod(CompuMethod):
18
18
  """A piecewise linear compu method which may feature discontinuities.
19
19
 
@@ -25,11 +25,11 @@ class ScaleLinearCompuMethod(CompuMethod):
25
25
  return self._segments
26
26
 
27
27
  @staticmethod
28
- def compu_method_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
28
+ def compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
29
29
  internal_type: DataType,
30
30
  physical_type: DataType) -> "ScaleLinearCompuMethod":
31
31
  cm = CompuMethod.compu_method_from_et(
32
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
32
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
33
33
  kwargs = dataclass_fields_asdict(cm)
34
34
 
35
35
  return ScaleLinearCompuMethod(**kwargs)
@@ -100,7 +100,7 @@ class ScaleLinearCompuMethod(CompuMethod):
100
100
  self._is_invertible = False
101
101
  break
102
102
 
103
- if not isinstance(x, int | float):
103
+ if not isinstance(x, (int, float)):
104
104
  odxraise("Linear segments must use int or float for all quantities")
105
105
 
106
106
  # the respective function value at the interval's
@@ -4,7 +4,7 @@ from typing import cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from ..exceptions import DecodeError, EncodeError, odxassert, odxraise
7
- from ..odxlink import OdxDocFragment
7
+ from ..odxdoccontext import OdxDocContext
8
8
  from ..odxtypes import AtomicOdxType, DataType
9
9
  from ..utils import dataclass_fields_asdict
10
10
  from .compucategory import CompuCategory
@@ -12,7 +12,7 @@ from .compumethod import CompuMethod
12
12
  from .ratfuncsegment import RatFuncSegment
13
13
 
14
14
 
15
- @dataclass
15
+ @dataclass(kw_only=True)
16
16
  class ScaleRatFuncCompuMethod(CompuMethod):
17
17
  """A compu method using a piecewise rational function
18
18
 
@@ -28,11 +28,11 @@ class ScaleRatFuncCompuMethod(CompuMethod):
28
28
  return self._phys_to_int_segments
29
29
 
30
30
  @staticmethod
31
- def compu_method_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
31
+ def compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
32
32
  internal_type: DataType,
33
33
  physical_type: DataType) -> "ScaleRatFuncCompuMethod":
34
34
  cm = CompuMethod.compu_method_from_et(
35
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
35
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
36
36
  kwargs = dataclass_fields_asdict(cm)
37
37
 
38
38
  return ScaleRatFuncCompuMethod(**kwargs)
@@ -3,7 +3,7 @@ from dataclasses import dataclass
3
3
  from xml.etree import ElementTree
4
4
 
5
5
  from ..exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
6
- from ..odxlink import OdxDocFragment
6
+ from ..odxdoccontext import OdxDocContext
7
7
  from ..odxtypes import AtomicOdxType, DataType
8
8
  from ..utils import dataclass_fields_asdict
9
9
  from .compucategory import CompuCategory
@@ -12,7 +12,7 @@ from .intervaltype import IntervalType
12
12
  from .limit import Limit
13
13
 
14
14
 
15
- @dataclass
15
+ @dataclass(kw_only=True)
16
16
  class TabIntpCompuMethod(CompuMethod):
17
17
  """A table-based interpolated compu method provides a continuous
18
18
  transfer function based on piecewise linear interpolation.
@@ -60,11 +60,11 @@ class TabIntpCompuMethod(CompuMethod):
60
60
  return self._physical_upper_limit
61
61
 
62
62
  @staticmethod
63
- def compu_method_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
63
+ def compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
64
64
  internal_type: DataType,
65
65
  physical_type: DataType) -> "TabIntpCompuMethod":
66
66
  cm = CompuMethod.compu_method_from_et(
67
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
67
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
68
68
  kwargs = dataclass_fields_asdict(cm)
69
69
 
70
70
  return TabIntpCompuMethod(**kwargs)
@@ -79,10 +79,10 @@ class TabIntpCompuMethod(CompuMethod):
79
79
  internal_point = odxrequire(scale.lower_limit).value
80
80
  physical_point = odxrequire(scale.compu_const).value
81
81
 
82
- if not isinstance(internal_point, float | int):
82
+ if not isinstance(internal_point, (float, int)):
83
83
  odxraise("The type of values of tab-intp compumethods must "
84
84
  "either int or float")
85
- if not isinstance(physical_point, float | int):
85
+ if not isinstance(physical_point, (float, int)):
86
86
  odxraise("The type of values of tab-intp compumethods must "
87
87
  "either int or float")
88
88
 
@@ -140,13 +140,13 @@ class TabIntpCompuMethod(CompuMethod):
140
140
  return None
141
141
 
142
142
  def convert_physical_to_internal(self, physical_value: AtomicOdxType) -> AtomicOdxType:
143
- if not isinstance(physical_value, int | float):
143
+ if not isinstance(physical_value, (int, float)):
144
144
  odxraise("The type of values of tab-intp compumethods must "
145
145
  "either int or float", EncodeError)
146
146
  return None
147
147
 
148
148
  odxassert(
149
- isinstance(physical_value, int | float),
149
+ isinstance(physical_value, (int, float)),
150
150
  "Only integers and floats can be piecewise linearly interpolated", EncodeError)
151
151
  result = self.__piecewise_linear_interpolate(physical_value, self._physical_points,
152
152
  self._internal_points)
@@ -161,14 +161,14 @@ class TabIntpCompuMethod(CompuMethod):
161
161
  return res
162
162
 
163
163
  def convert_internal_to_physical(self, internal_value: AtomicOdxType) -> AtomicOdxType:
164
- if not isinstance(internal_value, int | float):
164
+ if not isinstance(internal_value, (int, float)):
165
165
  odxraise(
166
166
  "The internal type of values of tab-intp compumethods must "
167
167
  "either int or float", EncodeError)
168
168
  return None
169
169
 
170
170
  odxassert(
171
- isinstance(internal_value, int | float),
171
+ isinstance(internal_value, (int, float)),
172
172
  "Only integers and floats can be piecewise linearly interpolated", DecodeError)
173
173
 
174
174
  result = self.__piecewise_linear_interpolate(internal_value, self._internal_points,
@@ -185,14 +185,14 @@ class TabIntpCompuMethod(CompuMethod):
185
185
  return res
186
186
 
187
187
  def is_valid_physical_value(self, physical_value: AtomicOdxType) -> bool:
188
- if not isinstance(physical_value, int | float):
188
+ if not isinstance(physical_value, (int, float)):
189
189
  return False
190
190
 
191
191
  return min(self.physical_points) <= physical_value and physical_value <= max(
192
192
  self.physical_points)
193
193
 
194
194
  def is_valid_internal_value(self, internal_value: AtomicOdxType) -> bool:
195
- if not isinstance(internal_value, int | float):
195
+ if not isinstance(internal_value, (int, float)):
196
196
  return False
197
197
 
198
198
  return min(self.internal_points) <= internal_value and internal_value <= max(
@@ -4,7 +4,7 @@ from typing import cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from ..exceptions import DecodeError, EncodeError, odxassert, odxraise, odxrequire
7
- from ..odxlink import OdxDocFragment
7
+ from ..odxdoccontext import OdxDocContext
8
8
  from ..odxtypes import AtomicOdxType, DataType
9
9
  from ..utils import dataclass_fields_asdict
10
10
  from .compucategory import CompuCategory
@@ -12,7 +12,7 @@ from .compumethod import CompuMethod
12
12
  from .compuscale import CompuScale
13
13
 
14
14
 
15
- @dataclass
15
+ @dataclass(kw_only=True)
16
16
  class TexttableCompuMethod(CompuMethod):
17
17
  """Text table compute methods translate numbers to human readable
18
18
  textual descriptions.
@@ -22,11 +22,11 @@ class TexttableCompuMethod(CompuMethod):
22
22
  """
23
23
 
24
24
  @staticmethod
25
- def compu_method_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
25
+ def compu_method_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
26
26
  internal_type: DataType,
27
27
  physical_type: DataType) -> "TexttableCompuMethod":
28
28
  cm = CompuMethod.compu_method_from_et(
29
- et_element, doc_frags, internal_type=internal_type, physical_type=physical_type)
29
+ et_element, context, internal_type=internal_type, physical_type=physical_type)
30
30
  kwargs = dataclass_fields_asdict(cm)
31
31
 
32
32
  return TexttableCompuMethod(**kwargs)
@@ -2,14 +2,14 @@ from xml.etree import ElementTree
2
2
 
3
3
  from .comparam import Comparam
4
4
  from .complexcomparam import ComplexComparam
5
- from .odxlink import OdxDocFragment
5
+ from .odxdoccontext import OdxDocContext
6
6
 
7
7
 
8
8
  def create_any_comparam_from_et(et_element: ElementTree.Element,
9
- doc_frags: list[OdxDocFragment]) -> Comparam | ComplexComparam:
9
+ context: OdxDocContext) -> Comparam | ComplexComparam:
10
10
  if et_element.tag == "COMPARAM":
11
- return Comparam.from_et(et_element, doc_frags)
11
+ return Comparam.from_et(et_element, context)
12
12
  elif et_element.tag == "COMPLEX-COMPARAM":
13
- return ComplexComparam.from_et(et_element, doc_frags)
13
+ return ComplexComparam.from_et(et_element, context)
14
14
 
15
15
  raise RuntimeError(f"Unhandled communication parameter type {et_element.tag}")
@@ -6,22 +6,22 @@ from .exceptions import odxraise
6
6
  from .globals import xsi
7
7
  from .leadinglengthinfotype import LeadingLengthInfoType
8
8
  from .minmaxlengthtype import MinMaxLengthType
9
- from .odxlink import OdxDocFragment
9
+ from .odxdoccontext import OdxDocContext
10
10
  from .paramlengthinfotype import ParamLengthInfoType
11
11
  from .standardlengthtype import StandardLengthType
12
12
 
13
13
 
14
14
  def create_any_diag_coded_type_from_et(et_element: ElementTree.Element,
15
- doc_frags: list[OdxDocFragment]) -> DiagCodedType:
15
+ context: OdxDocContext) -> DiagCodedType:
16
16
  dct_type = et_element.get(f"{xsi}type")
17
17
  if dct_type == "LEADING-LENGTH-INFO-TYPE":
18
- return LeadingLengthInfoType.from_et(et_element, doc_frags)
18
+ return LeadingLengthInfoType.from_et(et_element, context)
19
19
  elif dct_type == "MIN-MAX-LENGTH-TYPE":
20
- return MinMaxLengthType.from_et(et_element, doc_frags)
20
+ return MinMaxLengthType.from_et(et_element, context)
21
21
  elif dct_type == "PARAM-LENGTH-INFO-TYPE":
22
- return ParamLengthInfoType.from_et(et_element, doc_frags)
22
+ return ParamLengthInfoType.from_et(et_element, context)
23
23
  elif dct_type == "STANDARD-LENGTH-TYPE":
24
- return StandardLengthType.from_et(et_element, doc_frags)
24
+ return StandardLengthType.from_et(et_element, context)
25
25
 
26
26
  odxraise(f"Unknown DIAG-CODED-TYPE {dct_type}", NotImplementedError)
27
- return DiagCodedType.from_et(et_element, doc_frags)
27
+ return DiagCodedType.from_et(et_element, context)
odxtools/database.py CHANGED
@@ -20,7 +20,8 @@ from .diaglayers.functionalgroup import FunctionalGroup
20
20
  from .diaglayers.protocol import Protocol
21
21
  from .exceptions import odxraise, odxrequire
22
22
  from .nameditemlist import NamedItemList
23
- from .odxlink import OdxLinkDatabase, OdxLinkId
23
+ from .odxdoccontext import OdxDocContext
24
+ from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
24
25
  from .snrefcontext import SnRefContext
25
26
 
26
27
 
@@ -76,10 +77,6 @@ class Database:
76
77
  self.auxiliary_files[str(aux_file_name)] = aux_file_obj
77
78
 
78
79
  def _process_xml_tree(self, root: ElementTree.Element) -> None:
79
- dlcs: list[DiagLayerContainer] = []
80
- comparam_subsets: list[ComparamSubset] = []
81
- comparam_specs: list[ComparamSpec] = []
82
-
83
80
  # ODX spec version
84
81
  model_version = Version(root.attrib.get("MODEL-VERSION", "2.0"))
85
82
  if self.model_version is not None and self.model_version != model_version:
@@ -88,28 +85,33 @@ class Database:
88
85
 
89
86
  self.model_version = model_version
90
87
 
91
- dlc = root.find("DIAG-LAYER-CONTAINER")
92
- if dlc is not None:
93
- dlcs.append(DiagLayerContainer.from_et(dlc, []))
94
-
95
- # In ODX 2.0 there was only COMPARAM-SPEC. In ODX 2.2 the
96
- # content of COMPARAM-SPEC was moved to COMPARAM-SUBSET
97
- # and COMPARAM-SPEC became a container for PROT-STACKS and
98
- # a PROT-STACK references a list of COMPARAM-SUBSET
99
- cp_subset = root.find("COMPARAM-SUBSET")
100
- if cp_subset is not None:
101
- comparam_subsets.append(ComparamSubset.from_et(cp_subset, []))
102
-
103
- cp_spec = root.find("COMPARAM-SPEC")
104
- if cp_spec is not None:
88
+ child_elements = list(root)
89
+ if len(child_elements) != 1:
90
+ odxraise("Each ODX document must contain exactly one category.")
91
+
92
+ category_et = child_elements[0]
93
+ category_sn = odxrequire(category_et.findtext("SHORT-NAME"))
94
+ category_tag = category_et.tag
95
+
96
+ if category_tag == "DIAG-LAYER-CONTAINER":
97
+ context = OdxDocContext(model_version,
98
+ (OdxDocFragment(category_sn, DocType.CONTAINER),))
99
+ self._diag_layer_containers.append(DiagLayerContainer.from_et(category_et, context))
100
+ elif category_tag == "COMPARAM-SUBSET":
101
+ context = OdxDocContext(model_version,
102
+ (OdxDocFragment(category_sn, DocType.COMPARAM_SUBSET),))
103
+ self._comparam_subsets.append(ComparamSubset.from_et(category_et, context))
104
+ elif category_tag == "COMPARAM-SPEC":
105
+ # In ODX 2.0 there was only COMPARAM-SPEC. In ODX 2.2 the
106
+ # content of COMPARAM-SPEC was moved to COMPARAM-SUBSET
107
+ # and COMPARAM-SPEC became a container for PROT-STACKS and
108
+ # a PROT-STACK references a list of COMPARAM-SUBSET
109
+ context = OdxDocContext(model_version,
110
+ (OdxDocFragment(category_sn, DocType.COMPARAM_SPEC),))
105
111
  if model_version < Version("2.2"):
106
- comparam_subsets.append(ComparamSubset.from_et(cp_spec, []))
107
- else: # odx >= 2.2
108
- comparam_specs.append(ComparamSpec.from_et(cp_spec, []))
109
-
110
- self._diag_layer_containers.extend(dlcs)
111
- self._comparam_subsets.extend(comparam_subsets)
112
- self._comparam_specs.extend(comparam_specs)
112
+ self._comparam_subsets.append(ComparamSubset.from_et(category_et, context))
113
+ else:
114
+ self._comparam_specs.append(ComparamSpec.from_et(category_et, context))
113
115
 
114
116
  def refresh(self) -> None:
115
117
  # Create wrapper objects