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
odxtools/response.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from enum import Enum
4
4
  from typing import Any, cast
5
5
  from xml.etree import ElementTree
@@ -15,7 +15,8 @@ from .element import IdentifiableElement
15
15
  from .encodestate import EncodeState
16
16
  from .exceptions import odxraise
17
17
  from .nameditemlist import NamedItemList
18
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
18
+ from .odxdoccontext import OdxDocContext
19
+ from .odxlink import OdxLinkDatabase, OdxLinkId
19
20
  from .odxtypes import ParameterValue, ParameterValueDict
20
21
  from .parameters.createanyparameter import create_any_parameter_from_et
21
22
  from .parameters.parameter import Parameter
@@ -30,7 +31,7 @@ class ResponseType(Enum):
30
31
  GLOBAL_NEGATIVE = "GLOBAL-NEG-RESPONSE"
31
32
 
32
33
 
33
- @dataclass
34
+ @dataclass(kw_only=True)
34
35
  class Response(IdentifiableElement):
35
36
  """Represents all information related to an UDS response
36
37
 
@@ -39,14 +40,14 @@ class Response(IdentifiableElement):
39
40
 
40
41
  response_type: ResponseType
41
42
 
42
- admin_data: AdminData | None
43
- parameters: NamedItemList[Parameter]
44
- sdgs: list[SpecialDataGroup]
43
+ admin_data: AdminData | None = None
44
+ parameters: NamedItemList[Parameter] = field(default_factory=NamedItemList)
45
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
45
46
 
46
47
  @staticmethod
47
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Response":
48
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Response":
48
49
  """Reads a response."""
49
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
50
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
50
51
 
51
52
  try:
52
53
  response_type = ResponseType(et_element.tag)
@@ -54,14 +55,12 @@ class Response(IdentifiableElement):
54
55
  response_type = cast(ResponseType, None)
55
56
  odxraise(f"Encountered unknown response type '{et_element.tag}'")
56
57
 
57
- admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
58
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
58
59
  parameters = NamedItemList([
59
- create_any_parameter_from_et(et_parameter, doc_frags)
60
+ create_any_parameter_from_et(et_parameter, context)
60
61
  for et_parameter in et_element.iterfind("PARAMS/PARAM")
61
62
  ])
62
- sdgs = [
63
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
64
- ]
63
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
65
64
 
66
65
  return Response(
67
66
  response_type=response_type,
odxtools/scaleconstr.py CHANGED
@@ -5,32 +5,32 @@ from xml.etree import ElementTree
5
5
  from .compumethods.limit import Limit
6
6
  from .description import Description
7
7
  from .exceptions import odxraise, odxrequire
8
- from .odxlink import OdxDocFragment
8
+ from .odxdoccontext import OdxDocContext
9
9
  from .odxtypes import DataType
10
10
  from .validtype import ValidType
11
11
 
12
12
 
13
- @dataclass
13
+ @dataclass(kw_only=True)
14
14
  class ScaleConstr:
15
15
  """This class represents a SCALE-CONSTR.
16
16
  """
17
17
 
18
- short_label: str | None
19
- description: Description | None
18
+ short_label: str | None = None
19
+ description: Description | None = None
20
20
  lower_limit: Limit
21
21
  upper_limit: Limit
22
22
  validity: ValidType
23
23
  value_type: DataType
24
24
 
25
25
  @staticmethod
26
- def scale_constr_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
26
+ def scale_constr_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
27
27
  value_type: DataType) -> "ScaleConstr":
28
28
  short_label = et_element.findtext("SHORT-LABEL")
29
- description = Description.from_et(et_element.find("DESC"), doc_frags)
29
+ description = Description.from_et(et_element.find("DESC"), context)
30
30
  lower_limit = Limit.limit_from_et(
31
- odxrequire(et_element.find("LOWER-LIMIT")), doc_frags, value_type=value_type)
31
+ odxrequire(et_element.find("LOWER-LIMIT")), context, value_type=value_type)
32
32
  upper_limit = Limit.limit_from_et(
33
- odxrequire(et_element.find("UPPER-LIMIT")), doc_frags, value_type=value_type)
33
+ odxrequire(et_element.find("UPPER-LIMIT")), context, value_type=value_type)
34
34
 
35
35
  validity_str = odxrequire(et_element.get("VALIDITY"))
36
36
  try:
odxtools/singleecujob.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
@@ -7,14 +7,15 @@ from .diagcomm import DiagComm
7
7
  from .inputparam import InputParam
8
8
  from .nameditemlist import NamedItemList
9
9
  from .negoutputparam import NegOutputParam
10
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId
11
12
  from .outputparam import OutputParam
12
13
  from .progcode import ProgCode
13
14
  from .snrefcontext import SnRefContext
14
15
  from .utils import dataclass_fields_asdict
15
16
 
16
17
 
17
- @dataclass
18
+ @dataclass(kw_only=True)
18
19
  class SingleEcuJob(DiagComm):
19
20
  """A single ECU job is a diagnostic communication primitive.
20
21
 
@@ -30,30 +31,30 @@ class SingleEcuJob(DiagComm):
30
31
  standard.
31
32
  """
32
33
 
33
- prog_codes: list[ProgCode]
34
- input_params: NamedItemList[InputParam]
35
- output_params: NamedItemList[OutputParam]
36
- neg_output_params: NamedItemList[NegOutputParam]
34
+ prog_codes: list[ProgCode] = field(default_factory=list)
35
+ input_params: NamedItemList[InputParam] = field(default_factory=NamedItemList)
36
+ output_params: NamedItemList[OutputParam] = field(default_factory=NamedItemList)
37
+ neg_output_params: NamedItemList[NegOutputParam] = field(default_factory=NamedItemList)
37
38
 
38
39
  @staticmethod
39
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "SingleEcuJob":
40
- kwargs = dataclass_fields_asdict(DiagComm.from_et(et_element, doc_frags))
40
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "SingleEcuJob":
41
+ kwargs = dataclass_fields_asdict(DiagComm.from_et(et_element, context))
41
42
 
42
43
  prog_codes = [
43
- ProgCode.from_et(pc_elem, doc_frags)
44
+ ProgCode.from_et(pc_elem, context)
44
45
  for pc_elem in et_element.iterfind("PROG-CODES/PROG-CODE")
45
46
  ]
46
47
 
47
48
  input_params = NamedItemList([
48
- InputParam.from_et(el, doc_frags)
49
+ InputParam.from_et(el, context)
49
50
  for el in et_element.iterfind("INPUT-PARAMS/INPUT-PARAM")
50
51
  ])
51
52
  output_params = NamedItemList([
52
- OutputParam.from_et(el, doc_frags)
53
+ OutputParam.from_et(el, context)
53
54
  for el in et_element.iterfind("OUTPUT-PARAMS/OUTPUT-PARAM")
54
55
  ])
55
56
  neg_output_params = NamedItemList([
56
- NegOutputParam.from_et(el, doc_frags)
57
+ NegOutputParam.from_et(el, context)
57
58
  for el in et_element.iterfind("NEG-OUTPUT-PARAMS/NEG-OUTPUT-PARAM")
58
59
  ])
59
60
 
odxtools/snrefcontext.py CHANGED
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
13
13
  from .statechart import StateChart
14
14
 
15
15
 
16
- @dataclass
16
+ @dataclass(kw_only=True)
17
17
  class SnRefContext:
18
18
  """Represents the context for which a short name reference ought
19
19
  to be resolved
odxtools/specialdata.py CHANGED
@@ -3,19 +3,20 @@ from dataclasses import dataclass
3
3
  from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
6
+ from .odxdoccontext import OdxDocContext
7
+ from .odxlink import OdxLinkDatabase, OdxLinkId
7
8
  from .snrefcontext import SnRefContext
8
9
 
9
10
 
10
- @dataclass
11
+ @dataclass(kw_only=True)
11
12
  class SpecialData:
12
13
  """This corresponds to the SD XML tag"""
13
- semantic_info: str | None # the "SI" attribute
14
- text_identifier: str | None # the "TI" attribute, specifies the language used
14
+ semantic_info: str | None = None # the "SI" attribute
15
+ text_identifier: str | None = None # the "TI" attribute, specifies the language used
15
16
  value: str
16
17
 
17
18
  @staticmethod
18
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "SpecialData":
19
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "SpecialData":
19
20
  semantic_info = et_element.get("SI")
20
21
  text_identifier = et_element.get("TI")
21
22
  value = et_element.text or ""
@@ -1,33 +1,33 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from typing import Any, Union
4
4
  from xml.etree import ElementTree
5
5
 
6
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
6
+ from .odxdoccontext import OdxDocContext
7
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
7
8
  from .snrefcontext import SnRefContext
8
9
  from .specialdata import SpecialData
9
10
  from .specialdatagroupcaption import SpecialDataGroupCaption
10
11
 
11
12
 
12
- @dataclass
13
+ @dataclass(kw_only=True)
13
14
  class SpecialDataGroup:
14
15
  """This corresponds to the SDG XML tag"""
15
- sdg_caption: SpecialDataGroupCaption | None
16
- sdg_caption_ref: OdxLinkRef | None
17
- values: list[Union["SpecialDataGroup", SpecialData]]
18
- semantic_info: str | None # the "SI" attribute
16
+ sdg_caption: SpecialDataGroupCaption | None = None
17
+ sdg_caption_ref: OdxLinkRef | None = None
18
+ values: list[Union["SpecialDataGroup", SpecialData]] = field(default_factory=list)
19
+ semantic_info: str | None = None # the "SI" attribute
19
20
 
20
21
  @staticmethod
21
- def from_et(et_element: ElementTree.Element,
22
- doc_frags: list[OdxDocFragment]) -> "SpecialDataGroup":
22
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "SpecialDataGroup":
23
23
 
24
24
  sdg_caption = None
25
25
  if caption_elem := et_element.find("SDG-CAPTION"):
26
- sdg_caption = SpecialDataGroupCaption.from_et(caption_elem, doc_frags)
26
+ sdg_caption = SpecialDataGroupCaption.from_et(caption_elem, context)
27
27
 
28
28
  sdg_caption_ref = None
29
29
  if (caption_ref_elem := et_element.find("SDG-CAPTION-REF")) is not None:
30
- sdg_caption_ref = OdxLinkRef.from_et(caption_ref_elem, doc_frags)
30
+ sdg_caption_ref = OdxLinkRef.from_et(caption_ref_elem, context)
31
31
 
32
32
  semantic_info = et_element.get("SI")
33
33
 
@@ -35,9 +35,9 @@ class SpecialDataGroup:
35
35
  for value_elem in et_element:
36
36
  next_entry: SpecialData | SpecialDataGroup | None = None
37
37
  if value_elem.tag == "SDG":
38
- next_entry = SpecialDataGroup.from_et(value_elem, doc_frags)
38
+ next_entry = SpecialDataGroup.from_et(value_elem, context)
39
39
  elif value_elem.tag == "SD":
40
- next_entry = SpecialData.from_et(value_elem, doc_frags)
40
+ next_entry = SpecialData.from_et(value_elem, context)
41
41
 
42
42
  if next_entry is not None:
43
43
  values.append(next_entry)
@@ -4,18 +4,19 @@ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
7
+ from .odxdoccontext import OdxDocContext
8
+ from .odxlink import OdxLinkDatabase, OdxLinkId
8
9
  from .snrefcontext import SnRefContext
9
10
  from .utils import dataclass_fields_asdict
10
11
 
11
12
 
12
- @dataclass
13
+ @dataclass(kw_only=True)
13
14
  class SpecialDataGroupCaption(IdentifiableElement):
14
15
 
15
16
  @staticmethod
16
17
  def from_et(et_element: ElementTree.Element,
17
- doc_frags: list[OdxDocFragment]) -> "SpecialDataGroupCaption":
18
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
18
+ context: OdxDocContext) -> "SpecialDataGroupCaption":
19
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
19
20
 
20
21
  return SpecialDataGroupCaption(**kwargs)
21
22
 
@@ -9,7 +9,7 @@ from .decodestate import DecodeState
9
9
  from .diagcodedtype import DctType, DiagCodedType
10
10
  from .encodestate import EncodeState
11
11
  from .exceptions import odxassert, odxraise, odxrequire
12
- from .odxlink import OdxDocFragment
12
+ from .odxdoccontext import OdxDocContext
13
13
  from .odxtypes import AtomicOdxType, BytesTypes, DataType, odxstr_to_bool
14
14
  from .utils import dataclass_fields_asdict, read_hex_binary
15
15
 
@@ -31,9 +31,8 @@ class StandardLengthType(DiagCodedType):
31
31
 
32
32
  @staticmethod
33
33
  @override
34
- def from_et(et_element: ElementTree.Element,
35
- doc_frags: list[OdxDocFragment]) -> "StandardLengthType":
36
- kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, doc_frags))
34
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "StandardLengthType":
35
+ kwargs = dataclass_fields_asdict(DiagCodedType.from_et(et_element, context))
37
36
 
38
37
  bit_length = int(odxrequire(et_element.findtext("BIT-LENGTH")))
39
38
  bit_mask = read_hex_binary(et_element.find("BIT-MASK"))
@@ -72,11 +71,7 @@ class StandardLengthType(DiagCodedType):
72
71
  if self.is_condensed:
73
72
  # if a condensed bitmask is specified, the number of bits
74
73
  # set to one in the bit mask are used in the PDU
75
-
76
- # TODO: this is pretty slow. replace it by
77
- # `self.bit_mask.bit_count()` once we require python >=
78
- # 3.10.
79
- bit_sz = bin(self.bit_mask).count("1")
74
+ bit_sz = self.bit_mask.bit_count()
80
75
  used_mask = (1 << bit_sz) - 1
81
76
 
82
77
  return used_mask.to_bytes((bit_sz + 7) // 8, endianness)
@@ -171,10 +166,7 @@ class StandardLengthType(DiagCodedType):
171
166
 
172
167
  def get_static_bit_length(self) -> int | None:
173
168
  if self.bit_mask is not None and self.is_condensed:
174
- # TODO: this is pretty slow. replace it by
175
- # `self.bit_mask.bit_count()` once we require python >=
176
- # 3.10.
177
- return bin(self.bit_mask).count("1")
169
+ return self.bit_mask.bit_count()
178
170
 
179
171
  return self.bit_length
180
172
 
odxtools/state.py CHANGED
@@ -4,20 +4,21 @@ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
7
+ from .odxdoccontext import OdxDocContext
8
+ from .odxlink import OdxLinkDatabase, OdxLinkId
8
9
  from .snrefcontext import SnRefContext
9
10
  from .utils import dataclass_fields_asdict
10
11
 
11
12
 
12
- @dataclass
13
+ @dataclass(kw_only=True)
13
14
  class State(IdentifiableElement):
14
15
  """
15
16
  Corresponds to STATE.
16
17
  """
17
18
 
18
19
  @staticmethod
19
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "State":
20
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
20
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "State":
21
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
21
22
 
22
23
  return State(**kwargs)
23
24
 
odxtools/statechart.py CHANGED
@@ -1,40 +1,41 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from typing import Any
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
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
9
+ from .odxdoccontext import OdxDocContext
10
+ from .odxlink import OdxLinkDatabase, OdxLinkId, resolve_snref
10
11
  from .snrefcontext import SnRefContext
11
12
  from .state import State
12
13
  from .statetransition import StateTransition
13
14
  from .utils import dataclass_fields_asdict
14
15
 
15
16
 
16
- @dataclass
17
+ @dataclass(kw_only=True)
17
18
  class StateChart(IdentifiableElement):
18
19
  """
19
20
  Corresponds to STATE-CHART.
20
21
  """
21
22
  semantic: str
22
- state_transitions: list[StateTransition]
23
+ state_transitions: list[StateTransition] = field(default_factory=list)
23
24
  start_state_snref: str
24
- states: NamedItemList[State]
25
+ states: NamedItemList[State] = field(default_factory=NamedItemList)
25
26
 
26
27
  @property
27
28
  def start_state(self) -> State:
28
29
  return self._start_state
29
30
 
30
31
  @staticmethod
31
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "StateChart":
32
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
32
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "StateChart":
33
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
33
34
 
34
35
  semantic: str = odxrequire(et_element.findtext("SEMANTIC"))
35
36
 
36
37
  state_transitions = [
37
- StateTransition.from_et(st_elem, doc_frags)
38
+ StateTransition.from_et(st_elem, context)
38
39
  for st_elem in et_element.iterfind("STATE-TRANSITIONS/STATE-TRANSITION")
39
40
  ]
40
41
 
@@ -42,7 +43,7 @@ class StateChart(IdentifiableElement):
42
43
  start_state_snref = start_state_snref_elem.attrib["SHORT-NAME"]
43
44
 
44
45
  states = [
45
- State.from_et(st_elem, doc_frags) for st_elem in et_element.iterfind("STATES/STATE")
46
+ State.from_et(st_elem, context) for st_elem in et_element.iterfind("STATES/STATE")
46
47
  ]
47
48
 
48
49
  return StateChart(
odxtools/statemachine.py CHANGED
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
13
13
  from .diagservice import DiagService
14
14
 
15
15
 
16
- @dataclass
16
+ @dataclass(kw_only=True)
17
17
  class StateMachine:
18
18
  """Objects of this class represent the runtime state of a state chart
19
19
 
@@ -160,7 +160,7 @@ class StateMachine:
160
160
 
161
161
  if raw_resp is None:
162
162
  raise RuntimeError("The calling code must send back a reply")
163
- elif isinstance(raw_resp, bytes | bytearray):
163
+ elif isinstance(raw_resp, (bytes, bytearray)):
164
164
  for decoded_resp_msg in self.diag_layer.decode_response(raw_resp, raw_req):
165
165
  for stransref in service.state_transition_refs:
166
166
  # we only execute the first applicable state
@@ -6,20 +6,21 @@ from xml.etree import ElementTree
6
6
  from .element import IdentifiableElement
7
7
  from .exceptions import odxrequire
8
8
  from .externalaccessmethod import ExternalAccessMethod
9
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
9
+ from .odxdoccontext import OdxDocContext
10
+ from .odxlink import OdxLinkDatabase, OdxLinkId, resolve_snref
10
11
  from .snrefcontext import SnRefContext
11
12
  from .state import State
12
13
  from .utils import dataclass_fields_asdict
13
14
 
14
15
 
15
- @dataclass
16
+ @dataclass(kw_only=True)
16
17
  class StateTransition(IdentifiableElement):
17
18
  """
18
19
  Corresponds to STATE-TRANSITION.
19
20
  """
20
21
  source_snref: str
21
22
  target_snref: str
22
- external_access_method: ExternalAccessMethod | None
23
+ external_access_method: ExternalAccessMethod | None = None
23
24
 
24
25
  @property
25
26
  def source_state(self) -> State:
@@ -30,10 +31,9 @@ class StateTransition(IdentifiableElement):
30
31
  return self._target_state
31
32
 
32
33
  @staticmethod
33
- def from_et(et_element: ElementTree.Element,
34
- doc_frags: list[OdxDocFragment]) -> "StateTransition":
34
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "StateTransition":
35
35
 
36
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
36
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
37
37
 
38
38
  source_snref_elem = odxrequire(et_element.find("SOURCE-SNREF"))
39
39
  source_snref = odxrequire(source_snref_elem.attrib["SHORT-NAME"])
@@ -43,7 +43,7 @@ class StateTransition(IdentifiableElement):
43
43
 
44
44
  external_access_method = None
45
45
  if (eam_elem := et_element.find("EXTERNAL-ACCESS-METHOD")) is not None:
46
- external_access_method = ExternalAccessMethod.from_et(eam_elem, doc_frags)
46
+ external_access_method = ExternalAccessMethod.from_et(eam_elem, context)
47
47
  return StateTransition(
48
48
  source_snref=source_snref,
49
49
  target_snref=target_snref,
@@ -6,7 +6,8 @@ from xml.etree import ElementTree
6
6
  from .basicstructure import BasicStructure
7
7
  from .dataobjectproperty import DataObjectProperty
8
8
  from .exceptions import odxassert, odxraise, odxrequire
9
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
9
+ from .odxdoccontext import OdxDocContext
10
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
10
11
  from .odxtypes import ParameterValue, ParameterValueDict
11
12
  from .parameters.codedconstparameter import CodedConstParameter
12
13
  from .parameters.parameter import Parameter
@@ -108,13 +109,13 @@ def _check_applies(ref: Union["StateTransitionRef",
108
109
  return False
109
110
  elif not isinstance(
110
111
  param,
111
- CodedConstParameter | PhysicalConstantParameter | TableKeyParameter | ValueParameter):
112
+ (CodedConstParameter, PhysicalConstantParameter, TableKeyParameter, ValueParameter)):
112
113
  # see checker rule 194 in section B.2 of the spec
113
114
  odxraise(f"Parameter referenced by state transition ref is of "
114
115
  f"invalid type {type(param).__name__}")
115
116
  return False
116
- elif isinstance(param, CodedConstParameter | PhysicalConstantParameter
117
- | TableKeyParameter) and ref.value is not None:
117
+ elif isinstance(param, (CodedConstParameter, PhysicalConstantParameter,
118
+ TableKeyParameter)) and ref.value is not None:
118
119
  # see checker rule 193 in section B.2 of the spec. Why can
119
120
  # no values for constant parameters be specified? (This
120
121
  # seems to be rather inconvenient...)
@@ -146,7 +147,7 @@ def _check_applies(ref: Union["StateTransitionRef",
146
147
  return True
147
148
 
148
149
 
149
- @dataclass
150
+ @dataclass(kw_only=True)
150
151
  class StateTransitionRef(OdxLinkRef):
151
152
  """Describes a state transition that is to be potentially taken if
152
153
  a diagnostic communication is executed
@@ -155,10 +156,10 @@ class StateTransitionRef(OdxLinkRef):
155
156
  may also be conditional on the observed response of the ECU.
156
157
 
157
158
  """
158
- value: str | None
159
+ value: str | None = None
159
160
 
160
- in_param_if_snref: str | None
161
- in_param_if_snpathref: str | None
161
+ in_param_if_snref: str | None = None
162
+ in_param_if_snpathref: str | None = None
162
163
 
163
164
  @property
164
165
  def state_transition(self) -> StateTransition:
@@ -170,9 +171,8 @@ class StateTransitionRef(OdxLinkRef):
170
171
 
171
172
  @staticmethod
172
173
  def from_et( # type: ignore[override]
173
- et_element: ElementTree.Element,
174
- doc_frags: list[OdxDocFragment]) -> "StateTransitionRef":
175
- kwargs = dataclass_fields_asdict(OdxLinkRef.from_et(et_element, doc_frags))
174
+ et_element: ElementTree.Element, context: OdxDocContext) -> "StateTransitionRef":
175
+ kwargs = dataclass_fields_asdict(OdxLinkRef.from_et(et_element, context))
176
176
 
177
177
  value = et_element.findtext("VALUE")
178
178
 
odxtools/staticfield.py CHANGED
@@ -10,13 +10,14 @@ from .decodestate import DecodeState
10
10
  from .encodestate import EncodeState
11
11
  from .exceptions import odxassert, odxraise, odxrequire
12
12
  from .field import Field
13
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
13
+ from .odxdoccontext import OdxDocContext
14
+ from .odxlink import OdxLinkDatabase, OdxLinkId
14
15
  from .odxtypes import ParameterValue
15
16
  from .snrefcontext import SnRefContext
16
17
  from .utils import dataclass_fields_asdict
17
18
 
18
19
 
19
- @dataclass
20
+ @dataclass(kw_only=True)
20
21
  class StaticField(Field):
21
22
  """Array of a fixed number of structure objects"""
22
23
  fixed_number_of_items: int
@@ -24,8 +25,8 @@ class StaticField(Field):
24
25
 
25
26
  @staticmethod
26
27
  @override
27
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "StaticField":
28
- kwargs = dataclass_fields_asdict(Field.from_et(et_element, doc_frags))
28
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "StaticField":
29
+ kwargs = dataclass_fields_asdict(Field.from_et(et_element, context))
29
30
 
30
31
  fixed_number_of_items = int(odxrequire(et_element.findtext('FIXED-NUMBER-OF-ITEMS')))
31
32
  item_byte_size = int(odxrequire(et_element.findtext('ITEM-BYTE-SIZE')))
odxtools/structure.py CHANGED
@@ -3,23 +3,23 @@ from dataclasses import dataclass
3
3
  from xml.etree import ElementTree
4
4
 
5
5
  from .basicstructure import BasicStructure
6
- from .odxlink import OdxDocFragment
6
+ from .odxdoccontext import OdxDocContext
7
7
  from .odxtypes import odxstr_to_bool
8
8
  from .utils import dataclass_fields_asdict
9
9
 
10
10
 
11
- @dataclass
11
+ @dataclass(kw_only=True)
12
12
  class Structure(BasicStructure):
13
- is_visible_raw: bool | None
13
+ is_visible_raw: bool | None = None
14
14
 
15
15
  @property
16
16
  def is_visible(self) -> bool:
17
17
  return self.is_visible_raw in (True, None)
18
18
 
19
19
  @staticmethod
20
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Structure":
20
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Structure":
21
21
  """Read a STRUCTURE element from XML."""
22
- kwargs = dataclass_fields_asdict(BasicStructure.from_et(et_element, doc_frags))
22
+ kwargs = dataclass_fields_asdict(BasicStructure.from_et(et_element, context))
23
23
 
24
24
  is_visible_raw = odxstr_to_bool(et_element.get("IS-VISIBLE"))
25
25