odxtools 9.7.0__py3-none-any.whl → 10.1.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 (193) hide show
  1. odxtools/additionalaudience.py +7 -7
  2. odxtools/admindata.py +14 -13
  3. odxtools/audience.py +17 -17
  4. odxtools/basecomparam.py +9 -8
  5. odxtools/basevariantpattern.py +9 -10
  6. odxtools/basicstructure.py +15 -15
  7. odxtools/cli/_print_utils.py +34 -22
  8. odxtools/cli/browse.py +8 -8
  9. odxtools/cli/compare.py +24 -24
  10. odxtools/cli/decode.py +3 -4
  11. odxtools/cli/find.py +4 -5
  12. odxtools/cli/list.py +6 -6
  13. odxtools/cli/main.py +2 -2
  14. odxtools/cli/snoop.py +3 -3
  15. odxtools/codec.py +3 -3
  16. odxtools/commrelation.py +18 -17
  17. odxtools/companydata.py +13 -13
  18. odxtools/companydocinfo.py +15 -17
  19. odxtools/companyrevisioninfo.py +9 -9
  20. odxtools/companyspecificinfo.py +11 -13
  21. odxtools/comparam.py +8 -7
  22. odxtools/comparaminstance.py +14 -14
  23. odxtools/comparamspec.py +10 -11
  24. odxtools/comparamsubset.py +17 -25
  25. odxtools/complexcomparam.py +14 -14
  26. odxtools/complexdop.py +1 -1
  27. odxtools/compositecodec.py +8 -8
  28. odxtools/compumethods/compucodecompumethod.py +7 -7
  29. odxtools/compumethods/compuconst.py +5 -6
  30. odxtools/compumethods/compudefaultvalue.py +2 -3
  31. odxtools/compumethods/compuinternaltophys.py +13 -12
  32. odxtools/compumethods/compumethod.py +10 -9
  33. odxtools/compumethods/compuphystointernal.py +13 -12
  34. odxtools/compumethods/compurationalcoeffs.py +7 -7
  35. odxtools/compumethods/compuscale.py +15 -16
  36. odxtools/compumethods/createanycompumethod.py +12 -13
  37. odxtools/compumethods/identicalcompumethod.py +4 -5
  38. odxtools/compumethods/limit.py +14 -14
  39. odxtools/compumethods/linearcompumethod.py +5 -5
  40. odxtools/compumethods/linearsegment.py +10 -11
  41. odxtools/compumethods/ratfunccompumethod.py +6 -6
  42. odxtools/compumethods/ratfuncsegment.py +7 -8
  43. odxtools/compumethods/scalelinearcompumethod.py +9 -9
  44. odxtools/compumethods/scaleratfunccompumethod.py +7 -7
  45. odxtools/compumethods/tabintpcompumethod.py +10 -13
  46. odxtools/compumethods/texttablecompumethod.py +6 -6
  47. odxtools/createanycomparam.py +5 -7
  48. odxtools/createanydiagcodedtype.py +7 -8
  49. odxtools/database.py +34 -31
  50. odxtools/dataobjectproperty.py +19 -20
  51. odxtools/decodestate.py +5 -5
  52. odxtools/description.py +9 -9
  53. odxtools/determinenumberofitems.py +8 -7
  54. odxtools/diagcodedtype.py +10 -10
  55. odxtools/diagcomm.py +29 -30
  56. odxtools/diagdatadictionaryspec.py +36 -36
  57. odxtools/diaglayercontainer.py +35 -34
  58. odxtools/diaglayers/basevariant.py +14 -12
  59. odxtools/diaglayers/basevariantraw.py +22 -23
  60. odxtools/diaglayers/diaglayer.py +24 -22
  61. odxtools/diaglayers/diaglayerraw.py +43 -52
  62. odxtools/diaglayers/diaglayertype.py +1 -2
  63. odxtools/diaglayers/ecushareddata.py +9 -9
  64. odxtools/diaglayers/ecushareddataraw.py +15 -16
  65. odxtools/diaglayers/ecuvariant.py +15 -13
  66. odxtools/diaglayers/ecuvariantraw.py +21 -22
  67. odxtools/diaglayers/functionalgroup.py +12 -11
  68. odxtools/diaglayers/functionalgroupraw.py +17 -18
  69. odxtools/diaglayers/hierarchyelement.py +48 -54
  70. odxtools/diaglayers/hierarchyelementraw.py +10 -11
  71. odxtools/diaglayers/protocol.py +7 -7
  72. odxtools/diaglayers/protocolraw.py +13 -14
  73. odxtools/diagnostictroublecode.py +15 -17
  74. odxtools/diagservice.py +28 -27
  75. odxtools/diagvariable.py +24 -25
  76. odxtools/docrevision.py +18 -17
  77. odxtools/dopbase.py +13 -14
  78. odxtools/dtcconnector.py +8 -7
  79. odxtools/dtcdop.py +24 -20
  80. odxtools/dynamicendmarkerfield.py +10 -9
  81. odxtools/dynamiclengthfield.py +10 -9
  82. odxtools/dyndefinedspec.py +10 -10
  83. odxtools/dynenddopref.py +9 -9
  84. odxtools/dyniddefmodeinfo.py +21 -21
  85. odxtools/ecuvariantpattern.py +8 -10
  86. odxtools/element.py +12 -13
  87. odxtools/encodestate.py +11 -11
  88. odxtools/encoding.py +2 -3
  89. odxtools/endofpdufield.py +9 -10
  90. odxtools/envdataconnector.py +8 -8
  91. odxtools/environmentdata.py +7 -9
  92. odxtools/environmentdatadescription.py +18 -17
  93. odxtools/exceptions.py +5 -5
  94. odxtools/externalaccessmethod.py +4 -6
  95. odxtools/externaldoc.py +6 -6
  96. odxtools/field.py +15 -15
  97. odxtools/functionalclass.py +9 -9
  98. odxtools/inputparam.py +11 -10
  99. odxtools/internalconstr.py +10 -11
  100. odxtools/isotp_state_machine.py +12 -11
  101. odxtools/leadinglengthinfotype.py +4 -6
  102. odxtools/library.py +9 -8
  103. odxtools/linkeddtcdop.py +9 -8
  104. odxtools/loadfile.py +5 -6
  105. odxtools/matchingbasevariantparameter.py +5 -6
  106. odxtools/matchingparameter.py +10 -10
  107. odxtools/message.py +1 -1
  108. odxtools/minmaxlengthtype.py +6 -7
  109. odxtools/modification.py +7 -6
  110. odxtools/multiplexer.py +54 -18
  111. odxtools/multiplexercase.py +13 -13
  112. odxtools/multiplexerdefaultcase.py +11 -10
  113. odxtools/multiplexerswitchkey.py +8 -8
  114. odxtools/nameditemlist.py +13 -13
  115. odxtools/negoutputparam.py +8 -8
  116. odxtools/obd.py +1 -2
  117. odxtools/odxcategory.py +14 -26
  118. odxtools/odxdoccontext.py +16 -0
  119. odxtools/odxlink.py +23 -25
  120. odxtools/odxtypes.py +18 -15
  121. odxtools/outputparam.py +9 -8
  122. odxtools/parameterinfo.py +1 -1
  123. odxtools/parameters/codedconstparameter.py +10 -10
  124. odxtools/parameters/createanyparameter.py +15 -16
  125. odxtools/parameters/dynamicparameter.py +5 -7
  126. odxtools/parameters/lengthkeyparameter.py +10 -10
  127. odxtools/parameters/matchingrequestparameter.py +6 -7
  128. odxtools/parameters/nrcconstparameter.py +13 -13
  129. odxtools/parameters/parameter.py +17 -18
  130. odxtools/parameters/parameterwithdop.py +13 -13
  131. odxtools/parameters/physicalconstantparameter.py +8 -7
  132. odxtools/parameters/reservedparameter.py +6 -8
  133. odxtools/parameters/systemparameter.py +5 -7
  134. odxtools/parameters/tableentryparameter.py +8 -8
  135. odxtools/parameters/tablekeyparameter.py +17 -17
  136. odxtools/parameters/tablestructparameter.py +11 -11
  137. odxtools/parameters/valueparameter.py +11 -11
  138. odxtools/paramlengthinfotype.py +10 -9
  139. odxtools/parentref.py +15 -13
  140. odxtools/physicaldimension.py +15 -15
  141. odxtools/physicaltype.py +5 -6
  142. odxtools/posresponsesuppressible.py +11 -12
  143. odxtools/preconditionstateref.py +11 -11
  144. odxtools/progcode.py +11 -10
  145. odxtools/protstack.py +10 -9
  146. odxtools/relateddiagcommref.py +5 -6
  147. odxtools/relateddoc.py +11 -10
  148. odxtools/request.py +18 -19
  149. odxtools/response.py +19 -20
  150. odxtools/scaleconstr.py +8 -9
  151. odxtools/servicebinner.py +5 -5
  152. odxtools/singleecujob.py +16 -15
  153. odxtools/snrefcontext.py +3 -3
  154. odxtools/specialdata.py +8 -7
  155. odxtools/specialdatagroup.py +17 -17
  156. odxtools/specialdatagroupcaption.py +7 -6
  157. odxtools/standardlengthtype.py +14 -22
  158. odxtools/state.py +7 -6
  159. odxtools/statechart.py +12 -11
  160. odxtools/statemachine.py +4 -3
  161. odxtools/statetransition.py +9 -9
  162. odxtools/statetransitionref.py +19 -19
  163. odxtools/staticfield.py +9 -7
  164. odxtools/structure.py +5 -6
  165. odxtools/subcomponent.py +20 -18
  166. odxtools/subcomponentparamconnector.py +10 -9
  167. odxtools/subcomponentpattern.py +9 -9
  168. odxtools/swvariable.py +6 -7
  169. odxtools/table.py +25 -26
  170. odxtools/tablediagcommconnector.py +9 -8
  171. odxtools/tablerow.py +64 -43
  172. odxtools/tablerowconnector.py +8 -8
  173. odxtools/teammember.py +16 -15
  174. odxtools/templates/macros/printParentRef.xml.jinja2 +3 -1
  175. odxtools/text.py +4 -5
  176. odxtools/uds.py +2 -3
  177. odxtools/unit.py +14 -13
  178. odxtools/unitgroup.py +11 -10
  179. odxtools/unitspec.py +18 -19
  180. odxtools/utils.py +3 -3
  181. odxtools/variablegroup.py +5 -6
  182. odxtools/variantmatcher.py +10 -10
  183. odxtools/variantpattern.py +5 -6
  184. odxtools/version.py +2 -2
  185. odxtools/writepdxfile.py +5 -24
  186. odxtools/xdoc.py +13 -12
  187. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/METADATA +4 -5
  188. odxtools-10.1.0.dist-info/RECORD +265 -0
  189. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/WHEEL +1 -1
  190. odxtools-9.7.0.dist-info/RECORD +0 -264
  191. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/entry_points.txt +0 -0
  192. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/licenses/LICENSE +0 -0
  193. {odxtools-9.7.0.dist-info → odxtools-10.1.0.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,18 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .dopbase import DopBase
7
7
  from .element import NamedElement
8
8
  from .exceptions import odxrequire
9
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
+ from .odxdoccontext import OdxDocContext
10
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
10
11
  from .snrefcontext import SnRefContext
11
12
  from .utils import dataclass_fields_asdict
12
13
 
13
14
 
14
- @dataclass
15
+ @dataclass(kw_only=True)
15
16
  class NegOutputParam(NamedElement):
16
17
  dop_base_ref: OdxLinkRef
17
18
 
@@ -21,15 +22,14 @@ class NegOutputParam(NamedElement):
21
22
  return self._dop
22
23
 
23
24
  @staticmethod
24
- def from_et(et_element: ElementTree.Element,
25
- doc_frags: List[OdxDocFragment]) -> "NegOutputParam":
25
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "NegOutputParam":
26
26
 
27
- kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
28
- dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), doc_frags))
27
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, context))
28
+ dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), context))
29
29
 
30
30
  return NegOutputParam(dop_base_ref=dop_base_ref, **kwargs)
31
31
 
32
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
32
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
33
33
  return {}
34
34
 
35
35
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
odxtools/obd.py CHANGED
@@ -1,6 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from enum import IntEnum
3
- from typing import Optional
4
3
 
5
4
 
6
5
  class SID(IntEnum):
@@ -47,7 +46,7 @@ _sid_to_name = {
47
46
  }
48
47
 
49
48
 
50
- def sid_to_name(sid: int) -> Optional[str]:
49
+ def sid_to_name(sid: int) -> str | None:
51
50
  if sid in _sid_to_name:
52
51
  return _sid_to_name[sid]
53
52
 
odxtools/odxcategory.py CHANGED
@@ -1,14 +1,14 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
3
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
2
+ from dataclasses import dataclass, field
3
+ from typing import TYPE_CHECKING, Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
7
7
  from .companydata import CompanyData
8
8
  from .element import IdentifiableElement
9
- from .exceptions import odxrequire
10
9
  from .nameditemlist import NamedItemList
11
- from .odxlink import DocType, OdxDocFragment, OdxLinkDatabase, OdxLinkId
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId
12
12
  from .snrefcontext import SnRefContext
13
13
  from .specialdatagroup import SpecialDataGroup
14
14
  from .utils import dataclass_fields_asdict
@@ -17,41 +17,29 @@ if TYPE_CHECKING:
17
17
  from .database import Database
18
18
 
19
19
 
20
- @dataclass
20
+ @dataclass(kw_only=True)
21
21
  class OdxCategory(IdentifiableElement):
22
22
  """This is the base class for all top-level container classes in ODX"""
23
23
 
24
- admin_data: Optional[AdminData]
25
- company_datas: NamedItemList[CompanyData]
26
- sdgs: List[SpecialDataGroup]
24
+ admin_data: AdminData | None = None
25
+ company_datas: NamedItemList[CompanyData] = field(default_factory=NamedItemList)
26
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
27
27
 
28
28
  @staticmethod
29
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "OdxCategory":
30
- raise Exception("Calling `._from_et()` is not allowed for OdxCategory. "
31
- "Use `OdxCategory.category_from_et()`!")
29
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "OdxCategory":
32
30
 
33
- @staticmethod
34
- def category_from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment], *,
35
- doc_type: DocType) -> "OdxCategory":
36
-
37
- short_name = odxrequire(et_element.findtext("SHORT-NAME"))
38
- # create the current ODX "document fragment" (description of the
39
- # current document for references and IDs)
40
- doc_frags = [OdxDocFragment(short_name, doc_type)]
41
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
31
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
42
32
 
43
- admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
33
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
44
34
  company_datas = NamedItemList([
45
- CompanyData.from_et(cde, doc_frags)
35
+ CompanyData.from_et(cde, context)
46
36
  for cde in et_element.iterfind("COMPANY-DATAS/COMPANY-DATA")
47
37
  ])
48
- sdgs = [
49
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
50
- ]
38
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
51
39
 
52
40
  return OdxCategory(admin_data=admin_data, company_datas=company_datas, sdgs=sdgs, **kwargs)
53
41
 
54
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
42
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
55
43
  result = {self.odx_id: self}
56
44
 
57
45
  if self.admin_data is not None:
@@ -0,0 +1,16 @@
1
+ from dataclasses import dataclass
2
+ from typing import TYPE_CHECKING
3
+
4
+ from packaging.version import Version
5
+
6
+ if TYPE_CHECKING:
7
+ from odxtools.odxlink import OdxDocFragment
8
+
9
+
10
+ @dataclass(slots=True, frozen=True)
11
+ class OdxDocContext:
12
+ version: Version
13
+
14
+ # the doc_fragments are either tuple(doc_frag(category),)
15
+ # or tuple(doc_frag(category), doc_frag(diag_layer))
16
+ doc_fragments: tuple["OdxDocFragment"] | tuple["OdxDocFragment", "OdxDocFragment"]
odxtools/odxlink.py CHANGED
@@ -1,12 +1,14 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import warnings
3
+ from collections.abc import Iterable
3
4
  from dataclasses import dataclass
4
5
  from enum import Enum
5
- from typing import Any, Dict, Iterable, List, Optional, Type, TypeVar, overload
6
+ from typing import Any, Optional, TypeVar, overload
6
7
  from xml.etree import ElementTree
7
8
 
8
9
  from .exceptions import OdxWarning, odxassert, odxraise, odxrequire
9
10
  from .nameditemlist import OdxNamed, TNamed
11
+ from .odxdoccontext import OdxDocContext
10
12
 
11
13
 
12
14
  class DocType(Enum):
@@ -44,7 +46,7 @@ class OdxLinkId:
44
46
 
45
47
  #: The name and type of the document fragment to which the
46
48
  #: `local_id` is relative to
47
- doc_fragments: List[OdxDocFragment]
49
+ doc_fragments: tuple[OdxDocFragment] | tuple[OdxDocFragment, OdxDocFragment]
48
50
 
49
51
  def __hash__(self) -> int:
50
52
  # we do not hash about the document fragment here, because
@@ -67,8 +69,7 @@ class OdxLinkId:
67
69
  return f"OdxLinkId('{self.local_id}')"
68
70
 
69
71
  @staticmethod
70
- def from_et(et: ElementTree.Element,
71
- doc_fragments: List[OdxDocFragment]) -> Optional["OdxLinkId"]:
72
+ def from_et(et: ElementTree.Element, context: OdxDocContext) -> Optional["OdxLinkId"]:
72
73
  """Construct an OdxLinkId for a given XML node (ElementTree object).
73
74
 
74
75
  Returns None if the given XML node does not exhibit an ID.
@@ -78,7 +79,7 @@ class OdxLinkId:
78
79
  if local_id is None:
79
80
  return None
80
81
 
81
- return OdxLinkId(local_id, doc_fragments)
82
+ return OdxLinkId(local_id, context.doc_fragments)
82
83
 
83
84
 
84
85
  @dataclass
@@ -94,7 +95,7 @@ class OdxLinkRef:
94
95
  ref_id: str
95
96
 
96
97
  #: The document fragments to which the `ref_id` refers to (in reverse order)
97
- ref_docs: List[OdxDocFragment]
98
+ ref_docs: tuple[OdxDocFragment, ...]
98
99
 
99
100
  # TODO: this is difficult because OdxLinkRef is derived from and
100
101
  # we do not want having to specify it mandatorily
@@ -102,17 +103,16 @@ class OdxLinkRef:
102
103
 
103
104
  @overload
104
105
  @staticmethod
105
- def from_et(et: None, source_doc_frags: List[OdxDocFragment]) -> None:
106
+ def from_et(et: None, context: OdxDocContext) -> None:
106
107
  ...
107
108
 
108
109
  @overload
109
110
  @staticmethod
110
- def from_et(et: ElementTree.Element, source_doc_frags: List[OdxDocFragment]) -> "OdxLinkRef":
111
+ def from_et(et: ElementTree.Element, context: OdxDocContext) -> "OdxLinkRef":
111
112
  ...
112
113
 
113
114
  @staticmethod
114
- def from_et(et: Optional[ElementTree.Element],
115
- source_doc_frags: List[OdxDocFragment]) -> Optional["OdxLinkRef"]:
115
+ def from_et(et: ElementTree.Element | None, context: OdxDocContext) -> Optional["OdxLinkRef"]:
116
116
  """Construct an OdxLinkRef for a given XML node (ElementTree object).
117
117
 
118
118
  Returns None if the given XML node does not represent a reference.
@@ -143,10 +143,10 @@ class OdxLinkRef:
143
143
  # if the target document fragment is specified by the
144
144
  # reference, use it, else use the document fragment containing
145
145
  # the reference.
146
- if docref is not None:
147
- doc_frags = [OdxDocFragment(docref, odxrequire(doctype))]
146
+ if docref is None:
147
+ doc_frags = context.doc_fragments
148
148
  else:
149
- doc_frags = source_doc_frags
149
+ doc_frags = (OdxDocFragment(docref, odxrequire(doctype)),)
150
150
 
151
151
  return OdxLinkRef(id_ref, doc_frags)
152
152
 
@@ -170,17 +170,17 @@ class OdxLinkDatabase:
170
170
  """
171
171
 
172
172
  def __init__(self) -> None:
173
- self._db: Dict[OdxDocFragment, Dict[str, Any]] = {}
173
+ self._db: dict[OdxDocFragment, dict[str, Any]] = {}
174
174
 
175
175
  @overload
176
176
  def resolve(self, ref: OdxLinkRef, expected_type: None = None) -> Any:
177
177
  ...
178
178
 
179
179
  @overload
180
- def resolve(self, ref: OdxLinkRef, expected_type: Type[T]) -> T:
180
+ def resolve(self, ref: OdxLinkRef, expected_type: type[T]) -> T:
181
181
  ...
182
182
 
183
- def resolve(self, ref: OdxLinkRef, expected_type: Optional[Any] = None) -> Any:
183
+ def resolve(self, ref: OdxLinkRef, expected_type: Any | None = None) -> Any:
184
184
  """
185
185
  Resolve a reference to an object
186
186
 
@@ -219,12 +219,10 @@ class OdxLinkDatabase:
219
219
  ...
220
220
 
221
221
  @overload
222
- def resolve_lenient(self, ref: OdxLinkRef, expected_type: Type[T]) -> Optional[T]:
222
+ def resolve_lenient(self, ref: OdxLinkRef, expected_type: type[T]) -> T | None:
223
223
  ...
224
224
 
225
- def resolve_lenient(self,
226
- ref: OdxLinkRef,
227
- expected_type: Optional[Any] = None) -> Optional[Any]:
225
+ def resolve_lenient(self, ref: OdxLinkRef, expected_type: Any | None = None) -> Any | None:
228
226
  """
229
227
  Resolve a reference to an object
230
228
 
@@ -254,7 +252,7 @@ class OdxLinkDatabase:
254
252
 
255
253
  return None
256
254
 
257
- def update(self, new_entries: Dict[OdxLinkId, Any], *, overwrite: bool = True) -> None:
255
+ def update(self, new_entries: dict[OdxLinkId, Any], *, overwrite: bool = True) -> None:
258
256
  """
259
257
  Add a bunch of new objects to the ODXLINK database.
260
258
 
@@ -287,7 +285,7 @@ def resolve_snref(target_short_name: str,
287
285
  @overload
288
286
  def resolve_snref(target_short_name: str,
289
287
  items: Iterable[OdxNamed],
290
- expected_type: Type[TNamed],
288
+ expected_type: type[TNamed],
291
289
  *,
292
290
  lenient: None = None) -> TNamed:
293
291
  ...
@@ -296,16 +294,16 @@ def resolve_snref(target_short_name: str,
296
294
  @overload
297
295
  def resolve_snref(target_short_name: str,
298
296
  items: Iterable[OdxNamed],
299
- expected_type: Type[TNamed],
297
+ expected_type: type[TNamed],
300
298
  *,
301
- lenient: bool = True) -> Optional[TNamed]:
299
+ lenient: bool = True) -> TNamed | None:
302
300
  ...
303
301
 
304
302
 
305
303
  def resolve_snref(target_short_name: str,
306
304
  items: Iterable[OdxNamed],
307
305
  expected_type: Any = None,
308
- lenient: Optional[bool] = None) -> Any:
306
+ lenient: bool | None = None) -> Any:
309
307
  candidates = [x for x in items if x.short_name == target_short_name]
310
308
 
311
309
  if not candidates:
odxtools/odxtypes.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
+ from collections.abc import Callable, Iterable
2
3
  from enum import Enum
3
- from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional, SupportsBytes, Tuple,
4
- Type, Union, overload)
4
+ from typing import TYPE_CHECKING, Any, SupportsBytes, Union, overload
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from .exceptions import odxassert, odxraise, odxrequire
@@ -16,22 +16,22 @@ def bytefield_to_bytearray(bytefield: str) -> bytearray:
16
16
  return bytearray([int(x, 16) for x in bytes_string])
17
17
 
18
18
 
19
- BytesTypes = (bytearray, bytes, SupportsBytes)
20
- AtomicOdxType = Union[str, int, float, bytearray, bytes]
19
+ BytesTypes = bytearray | bytes | SupportsBytes
20
+ AtomicOdxType = str | int | float | BytesTypes
21
21
 
22
22
  # dictionary mapping short names to a Parameter that needs to be
23
23
  # specified. Complex parameters (structures) may contain
24
24
  # sub-parameters, so this is a recursive type...
25
- ParameterDict = Dict[str, Union["Parameter", "ParameterDict"]]
25
+ ParameterDict = dict[str, Union["Parameter", "ParameterDict"]]
26
26
 
27
27
  # Dictionary mapping short names of parameters to the value it
28
28
  # exhibits. Complex parameters (structures) may contain
29
29
  # sub-parameters, so this is a recursive type, and fields encompass
30
30
  # multiple items, so this can be a list of objects.
31
- TableStructParameterValue = Tuple[str, "ParameterValue"]
31
+ TableStructParameterValue = tuple[str, "ParameterValue"]
32
32
  ParameterValue = Union[AtomicOdxType, "ParameterValueDict", TableStructParameterValue,
33
33
  Iterable["ParameterValue"], "DiagnosticTroubleCode"]
34
- ParameterValueDict = Dict[str, ParameterValue]
34
+ ParameterValueDict = dict[str, ParameterValue]
35
35
 
36
36
 
37
37
  @overload
@@ -44,7 +44,7 @@ def odxstr_to_bool(str_val: str) -> bool:
44
44
  ...
45
45
 
46
46
 
47
- def odxstr_to_bool(str_val: Optional[str]) -> Optional[bool]:
47
+ def odxstr_to_bool(str_val: str | None) -> bool | None:
48
48
  if str_val is None:
49
49
  return None
50
50
 
@@ -79,7 +79,7 @@ def parse_int(value: str) -> int:
79
79
 
80
80
  #: conversion functions for strings from the XML to the types stored
81
81
  #: by the internalized database
82
- _PARSE_ODX_TYPE: Dict[str, Callable[[str], AtomicOdxType]] = {
82
+ _PARSE_ODX_TYPE: dict[str, Callable[[str], AtomicOdxType]] = {
83
83
  "A_INT32": parse_int,
84
84
  "A_UINT32": parse_int,
85
85
  "A_FLOAT32": float,
@@ -92,7 +92,7 @@ _PARSE_ODX_TYPE: Dict[str, Callable[[str], AtomicOdxType]] = {
92
92
 
93
93
  #: mapping from type name strings specified by the XML to the types
94
94
  #: used by the internalized database
95
- _ODX_TYPE_TO_PYTHON_TYPE: Dict[str, Type[AtomicOdxType]] = {
95
+ _ODX_TYPE_TO_PYTHON_TYPE: dict[str, type[int | float | str | bytearray]] = {
96
96
  "A_INT32": int,
97
97
  "A_UINT32": int,
98
98
  "A_FLOAT32": float,
@@ -140,10 +140,13 @@ def compare_odx_values(a: AtomicOdxType, b: AtomicOdxType) -> int:
140
140
  if not isinstance(b, BytesTypes):
141
141
  odxraise()
142
142
 
143
- obj_len = max(len(a), len(b))
143
+ a_bytes = bytes(a)
144
+ b_bytes = bytes(b)
144
145
 
145
- tmp_a = a.ljust(obj_len, b'\x00')
146
- tmp_b = b.ljust(obj_len, b'\x00')
146
+ obj_len = max(len(a_bytes), len(b_bytes))
147
+
148
+ tmp_a = a_bytes.ljust(obj_len, b'\x00')
149
+ tmp_b = b_bytes.ljust(obj_len, b'\x00')
147
150
 
148
151
  if tmp_a > tmp_b:
149
152
  return 1
@@ -193,7 +196,7 @@ class DataType(Enum):
193
196
  A_UTF8STRING = "A_UTF8STRING"
194
197
 
195
198
  @property
196
- def python_type(self) -> Type[AtomicOdxType]:
199
+ def python_type(self) -> type[int | float | str | bytearray]:
197
200
  return _ODX_TYPE_TO_PYTHON_TYPE[self.value]
198
201
 
199
202
  @property
@@ -211,7 +214,7 @@ class DataType(Enum):
211
214
  def create_from_et(self, et_element: ElementTree.Element) -> AtomicOdxType:
212
215
  ...
213
216
 
214
- def create_from_et(self, et_element: Optional[ElementTree.Element]) -> Optional[AtomicOdxType]:
217
+ def create_from_et(self, et_element: ElementTree.Element | None) -> AtomicOdxType | None:
215
218
  """
216
219
  Parse a V/VT value union and return an AtomicOdxType from them that match current datatype
217
220
  this includes, but not limited to COMPU-CONST, COMPU-DEFAULT-VALUE, COMPU-INVERSE-VALUE
odxtools/outputparam.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from deprecation import deprecated
@@ -8,15 +8,16 @@ from deprecation import deprecated
8
8
  from .dopbase import DopBase
9
9
  from .element import IdentifiableElement
10
10
  from .exceptions import odxrequire
11
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
11
+ from .odxdoccontext import OdxDocContext
12
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
12
13
  from .snrefcontext import SnRefContext
13
14
  from .utils import dataclass_fields_asdict
14
15
 
15
16
 
16
- @dataclass
17
+ @dataclass(kw_only=True)
17
18
  class OutputParam(IdentifiableElement):
18
19
  dop_base_ref: OdxLinkRef
19
- semantic: Optional[str]
20
+ semantic: str | None = None
20
21
 
21
22
  @property
22
23
  def dop(self) -> DopBase:
@@ -27,16 +28,16 @@ class OutputParam(IdentifiableElement):
27
28
  return self._dop
28
29
 
29
30
  @staticmethod
30
- def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "OutputParam":
31
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "OutputParam":
31
32
 
32
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
33
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
33
34
 
34
- dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), doc_frags))
35
+ dop_base_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DOP-BASE-REF"), context))
35
36
  semantic = et_element.get("SEMANTIC")
36
37
 
37
38
  return OutputParam(dop_base_ref=dop_base_ref, semantic=semantic, **kwargs)
38
39
 
39
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
40
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
40
41
  return {}
41
42
 
42
43
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
odxtools/parameterinfo.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import textwrap
3
+ from collections.abc import Iterable
3
4
  from io import StringIO
4
- from typing import Iterable
5
5
 
6
6
  from .compumethods.compucodecompumethod import CompuCodeCompuMethod
7
7
  from .compumethods.identicalcompumethod import IdenticalCompuMethod
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  import warnings
3
3
  from dataclasses import dataclass
4
- from typing import Any, Dict, List, Optional, cast
4
+ from typing import Any, cast
5
5
  from xml.etree import ElementTree
6
6
 
7
7
  from typing_extensions import override
@@ -11,13 +11,14 @@ from ..decodestate import DecodeState
11
11
  from ..diagcodedtype import DiagCodedType
12
12
  from ..encodestate import EncodeState
13
13
  from ..exceptions import DecodeError, EncodeError, odxraise, odxrequire
14
- from ..odxlink import OdxDocFragment, OdxLinkId
14
+ from ..odxdoccontext import OdxDocContext
15
+ from ..odxlink import OdxLinkId
15
16
  from ..odxtypes import AtomicOdxType, DataType, ParameterValue
16
17
  from ..utils import dataclass_fields_asdict
17
18
  from .parameter import Parameter, ParameterType
18
19
 
19
20
 
20
- @dataclass
21
+ @dataclass(kw_only=True)
21
22
  class CodedConstParameter(Parameter):
22
23
 
23
24
  coded_value_raw: str
@@ -44,14 +45,13 @@ class CodedConstParameter(Parameter):
44
45
 
45
46
  @staticmethod
46
47
  @override
47
- def from_et(et_element: ElementTree.Element,
48
- doc_frags: List[OdxDocFragment]) -> "CodedConstParameter":
48
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "CodedConstParameter":
49
49
 
50
- kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
50
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, context))
51
51
 
52
52
  coded_value_raw = odxrequire(et_element.findtext("CODED-VALUE"))
53
53
  dct_elem = odxrequire(et_element.find("DIAG-CODED-TYPE"))
54
- diag_coded_type = create_any_diag_coded_type_from_et(dct_elem, doc_frags)
54
+ diag_coded_type = create_any_diag_coded_type_from_et(dct_elem, context)
55
55
 
56
56
  return CodedConstParameter(
57
57
  coded_value_raw=coded_value_raw, diag_coded_type=diag_coded_type, **kwargs)
@@ -61,7 +61,7 @@ class CodedConstParameter(Parameter):
61
61
  AtomicOdxType, self.diag_coded_type.base_data_type.from_string(self.coded_value_raw))
62
62
 
63
63
  @override
64
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
64
+ def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
65
65
  result = super()._build_odxlinks()
66
66
 
67
67
  result.update(self.diag_coded_type._build_odxlinks())
@@ -69,7 +69,7 @@ class CodedConstParameter(Parameter):
69
69
  return result
70
70
 
71
71
  @override
72
- def get_static_bit_length(self) -> Optional[int]:
72
+ def get_static_bit_length(self) -> int | None:
73
73
  return self.diag_coded_type.get_static_bit_length()
74
74
 
75
75
  @property
@@ -77,7 +77,7 @@ class CodedConstParameter(Parameter):
77
77
  return self.diag_coded_type.base_data_type
78
78
 
79
79
  @override
80
- def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
80
+ def _encode_positioned_into_pdu(self, physical_value: ParameterValue | None,
81
81
  encode_state: EncodeState) -> None:
82
82
  if physical_value is not None and physical_value != self.coded_value:
83
83
  odxraise(
@@ -1,10 +1,9 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from typing import List
3
2
  from xml.etree import ElementTree
4
3
 
5
4
  from ..exceptions import odxraise
6
5
  from ..globals import xsi
7
- from ..odxlink import OdxDocFragment
6
+ from ..odxdoccontext import OdxDocContext
8
7
  from .codedconstparameter import CodedConstParameter
9
8
  from .dynamicparameter import DynamicParameter
10
9
  from .lengthkeyparameter import LengthKeyParameter
@@ -21,35 +20,35 @@ from .valueparameter import ValueParameter
21
20
 
22
21
 
23
22
  def create_any_parameter_from_et(et_element: ElementTree.Element,
24
- doc_frags: List[OdxDocFragment]) \
23
+ context: OdxDocContext) \
25
24
  -> Parameter:
26
25
  parameter_type = et_element.get(f"{xsi}type")
27
26
 
28
27
  # Which attributes are set depends on the type of the parameter.
29
28
  if parameter_type == "VALUE":
30
- return ValueParameter.from_et(et_element, doc_frags)
29
+ return ValueParameter.from_et(et_element, context)
31
30
  elif parameter_type == "CODED-CONST":
32
- return CodedConstParameter.from_et(et_element, doc_frags)
31
+ return CodedConstParameter.from_et(et_element, context)
33
32
  elif parameter_type == "PHYS-CONST":
34
- return PhysicalConstantParameter.from_et(et_element, doc_frags)
33
+ return PhysicalConstantParameter.from_et(et_element, context)
35
34
  elif parameter_type == "SYSTEM":
36
- return SystemParameter.from_et(et_element, doc_frags)
35
+ return SystemParameter.from_et(et_element, context)
37
36
  elif parameter_type == "LENGTH-KEY":
38
- return LengthKeyParameter.from_et(et_element, doc_frags)
37
+ return LengthKeyParameter.from_et(et_element, context)
39
38
  elif parameter_type == "NRC-CONST":
40
- return NrcConstParameter.from_et(et_element, doc_frags)
39
+ return NrcConstParameter.from_et(et_element, context)
41
40
  elif parameter_type == "RESERVED":
42
- return ReservedParameter.from_et(et_element, doc_frags)
41
+ return ReservedParameter.from_et(et_element, context)
43
42
  elif parameter_type == "MATCHING-REQUEST-PARAM":
44
- return MatchingRequestParameter.from_et(et_element, doc_frags)
43
+ return MatchingRequestParameter.from_et(et_element, context)
45
44
  elif parameter_type == "DYNAMIC":
46
- return DynamicParameter.from_et(et_element, doc_frags)
45
+ return DynamicParameter.from_et(et_element, context)
47
46
  elif parameter_type == "TABLE-STRUCT":
48
- return TableStructParameter.from_et(et_element, doc_frags)
47
+ return TableStructParameter.from_et(et_element, context)
49
48
  elif parameter_type == "TABLE-KEY":
50
- return TableKeyParameter.from_et(et_element, doc_frags)
49
+ return TableKeyParameter.from_et(et_element, context)
51
50
  elif parameter_type == "TABLE-ENTRY":
52
- return TableEntryParameter.from_et(et_element, doc_frags)
51
+ return TableEntryParameter.from_et(et_element, context)
53
52
 
54
53
  odxraise(f"I don't know about parameters of type {parameter_type}", NotImplementedError)
55
- return Parameter.from_et(et_element, doc_frags)
54
+ return Parameter.from_et(et_element, context)
@@ -1,19 +1,18 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from dataclasses import dataclass
3
- from typing import List, Optional
4
3
  from xml.etree import ElementTree
5
4
 
6
5
  from typing_extensions import override
7
6
 
8
7
  from ..decodestate import DecodeState
9
8
  from ..encodestate import EncodeState
10
- from ..odxlink import OdxDocFragment
9
+ from ..odxdoccontext import OdxDocContext
11
10
  from ..odxtypes import ParameterValue
12
11
  from ..utils import dataclass_fields_asdict
13
12
  from .parameter import Parameter, ParameterType
14
13
 
15
14
 
16
- @dataclass
15
+ @dataclass(kw_only=True)
17
16
  class DynamicParameter(Parameter):
18
17
 
19
18
  @property
@@ -33,15 +32,14 @@ class DynamicParameter(Parameter):
33
32
 
34
33
  @staticmethod
35
34
  @override
36
- def from_et(et_element: ElementTree.Element,
37
- doc_frags: List[OdxDocFragment]) -> "DynamicParameter":
35
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "DynamicParameter":
38
36
 
39
- kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, doc_frags))
37
+ kwargs = dataclass_fields_asdict(Parameter.from_et(et_element, context))
40
38
 
41
39
  return DynamicParameter(**kwargs)
42
40
 
43
41
  @override
44
- def _encode_positioned_into_pdu(self, physical_value: Optional[ParameterValue],
42
+ def _encode_positioned_into_pdu(self, physical_value: ParameterValue | None,
45
43
  encode_state: EncodeState) -> None:
46
44
  raise NotImplementedError("Encoding DynamicParameter is not implemented yet.")
47
45