odxtools 10.0.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 (174) 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/list.py +1 -1
  10. odxtools/commrelation.py +14 -13
  11. odxtools/companydata.py +11 -11
  12. odxtools/companydocinfo.py +11 -13
  13. odxtools/companyrevisioninfo.py +7 -7
  14. odxtools/companyspecificinfo.py +9 -11
  15. odxtools/comparam.py +6 -5
  16. odxtools/comparaminstance.py +10 -10
  17. odxtools/comparamspec.py +8 -9
  18. odxtools/comparamsubset.py +14 -22
  19. odxtools/complexcomparam.py +10 -10
  20. odxtools/complexdop.py +1 -1
  21. odxtools/compositecodec.py +3 -3
  22. odxtools/compumethods/compucodecompumethod.py +4 -4
  23. odxtools/compumethods/compuconst.py +3 -3
  24. odxtools/compumethods/compudefaultvalue.py +2 -2
  25. odxtools/compumethods/compuinternaltophys.py +11 -10
  26. odxtools/compumethods/compumethod.py +8 -7
  27. odxtools/compumethods/compuphystointernal.py +11 -10
  28. odxtools/compumethods/compurationalcoeffs.py +6 -6
  29. odxtools/compumethods/compuscale.py +14 -14
  30. odxtools/compumethods/createanycompumethod.py +12 -12
  31. odxtools/compumethods/identicalcompumethod.py +4 -4
  32. odxtools/compumethods/limit.py +8 -8
  33. odxtools/compumethods/linearcompumethod.py +4 -4
  34. odxtools/compumethods/linearsegment.py +8 -8
  35. odxtools/compumethods/ratfunccompumethod.py +4 -4
  36. odxtools/compumethods/ratfuncsegment.py +8 -8
  37. odxtools/compumethods/scalelinearcompumethod.py +5 -5
  38. odxtools/compumethods/scaleratfunccompumethod.py +4 -4
  39. odxtools/compumethods/tabintpcompumethod.py +12 -12
  40. odxtools/compumethods/texttablecompumethod.py +4 -4
  41. odxtools/createanycomparam.py +4 -4
  42. odxtools/createanydiagcodedtype.py +7 -7
  43. odxtools/database.py +28 -26
  44. odxtools/dataobjectproperty.py +15 -16
  45. odxtools/description.py +7 -7
  46. odxtools/determinenumberofitems.py +6 -5
  47. odxtools/diagcodedtype.py +6 -6
  48. odxtools/diagcomm.py +26 -27
  49. odxtools/diagdatadictionaryspec.py +34 -34
  50. odxtools/diaglayercontainer.py +32 -31
  51. odxtools/diaglayers/basevariant.py +5 -4
  52. odxtools/diaglayers/basevariantraw.py +18 -19
  53. odxtools/diaglayers/diaglayer.py +5 -4
  54. odxtools/diaglayers/diaglayerraw.py +39 -48
  55. odxtools/diaglayers/ecushareddata.py +6 -6
  56. odxtools/diaglayers/ecushareddataraw.py +11 -12
  57. odxtools/diaglayers/ecuvariant.py +5 -4
  58. odxtools/diaglayers/ecuvariantraw.py +17 -18
  59. odxtools/diaglayers/functionalgroup.py +5 -5
  60. odxtools/diaglayers/functionalgroupraw.py +13 -14
  61. odxtools/diaglayers/hierarchyelement.py +9 -9
  62. odxtools/diaglayers/hierarchyelementraw.py +8 -9
  63. odxtools/diaglayers/protocol.py +4 -4
  64. odxtools/diaglayers/protocolraw.py +10 -11
  65. odxtools/diagnostictroublecode.py +12 -14
  66. odxtools/diagservice.py +19 -18
  67. odxtools/diagvariable.py +19 -20
  68. odxtools/docrevision.py +14 -13
  69. odxtools/dopbase.py +10 -11
  70. odxtools/dtcconnector.py +6 -5
  71. odxtools/dtcdop.py +15 -15
  72. odxtools/dynamicendmarkerfield.py +6 -6
  73. odxtools/dynamiclengthfield.py +6 -6
  74. odxtools/dyndefinedspec.py +7 -7
  75. odxtools/dynenddopref.py +7 -7
  76. odxtools/dyniddefmodeinfo.py +17 -17
  77. odxtools/ecuvariantpattern.py +6 -7
  78. odxtools/element.py +12 -12
  79. odxtools/endofpdufield.py +6 -7
  80. odxtools/envdataconnector.py +6 -6
  81. odxtools/environmentdata.py +7 -8
  82. odxtools/environmentdatadescription.py +13 -12
  83. odxtools/externalaccessmethod.py +4 -5
  84. odxtools/externaldoc.py +4 -4
  85. odxtools/field.py +12 -11
  86. odxtools/functionalclass.py +7 -7
  87. odxtools/inputparam.py +9 -8
  88. odxtools/internalconstr.py +10 -10
  89. odxtools/leadinglengthinfotype.py +5 -6
  90. odxtools/library.py +7 -6
  91. odxtools/linkeddtcdop.py +7 -6
  92. odxtools/matchingbasevariantparameter.py +5 -5
  93. odxtools/matchingparameter.py +6 -6
  94. odxtools/message.py +1 -1
  95. odxtools/minmaxlengthtype.py +6 -7
  96. odxtools/modification.py +5 -4
  97. odxtools/multiplexer.py +48 -12
  98. odxtools/multiplexercase.py +10 -10
  99. odxtools/multiplexerdefaultcase.py +8 -7
  100. odxtools/multiplexerswitchkey.py +6 -6
  101. odxtools/nameditemlist.py +1 -1
  102. odxtools/negoutputparam.py +6 -6
  103. odxtools/odxcategory.py +12 -24
  104. odxtools/odxdoccontext.py +16 -0
  105. odxtools/odxlink.py +11 -12
  106. odxtools/odxtypes.py +3 -3
  107. odxtools/outputparam.py +7 -6
  108. odxtools/parameters/codedconstparameter.py +6 -6
  109. odxtools/parameters/createanyparameter.py +15 -15
  110. odxtools/parameters/dynamicparameter.py +4 -5
  111. odxtools/parameters/lengthkeyparameter.py +6 -6
  112. odxtools/parameters/matchingrequestparameter.py +4 -4
  113. odxtools/parameters/nrcconstparameter.py +8 -8
  114. odxtools/parameters/parameter.py +12 -13
  115. odxtools/parameters/parameterwithdop.py +9 -9
  116. odxtools/parameters/physicalconstantparameter.py +5 -4
  117. odxtools/parameters/reservedparameter.py +4 -5
  118. odxtools/parameters/systemparameter.py +4 -5
  119. odxtools/parameters/tableentryparameter.py +6 -6
  120. odxtools/parameters/tablekeyparameter.py +12 -12
  121. odxtools/parameters/tablestructparameter.py +9 -9
  122. odxtools/parameters/valueparameter.py +6 -6
  123. odxtools/paramlengthinfotype.py +6 -7
  124. odxtools/parentref.py +12 -10
  125. odxtools/physicaldimension.py +12 -12
  126. odxtools/physicaltype.py +5 -5
  127. odxtools/posresponsesuppressible.py +11 -11
  128. odxtools/preconditionstateref.py +8 -8
  129. odxtools/progcode.py +9 -8
  130. odxtools/protstack.py +8 -7
  131. odxtools/relateddiagcommref.py +5 -5
  132. odxtools/relateddoc.py +8 -7
  133. odxtools/request.py +12 -13
  134. odxtools/response.py +12 -13
  135. odxtools/scaleconstr.py +8 -8
  136. odxtools/singleecujob.py +14 -13
  137. odxtools/snrefcontext.py +1 -1
  138. odxtools/specialdata.py +6 -5
  139. odxtools/specialdatagroup.py +13 -13
  140. odxtools/specialdatagroupcaption.py +5 -4
  141. odxtools/standardlengthtype.py +5 -13
  142. odxtools/state.py +5 -4
  143. odxtools/statechart.py +10 -9
  144. odxtools/statemachine.py +2 -2
  145. odxtools/statetransition.py +7 -7
  146. odxtools/statetransitionref.py +11 -11
  147. odxtools/staticfield.py +5 -4
  148. odxtools/structure.py +5 -5
  149. odxtools/subcomponent.py +18 -16
  150. odxtools/subcomponentparamconnector.py +8 -7
  151. odxtools/subcomponentpattern.py +7 -7
  152. odxtools/swvariable.py +6 -6
  153. odxtools/table.py +20 -21
  154. odxtools/tablediagcommconnector.py +7 -6
  155. odxtools/tablerow.py +57 -36
  156. odxtools/tablerowconnector.py +6 -6
  157. odxtools/teammember.py +14 -13
  158. odxtools/templates/macros/printParentRef.xml.jinja2 +3 -1
  159. odxtools/text.py +4 -4
  160. odxtools/unit.py +9 -8
  161. odxtools/unitgroup.py +9 -8
  162. odxtools/unitspec.py +15 -16
  163. odxtools/variablegroup.py +4 -5
  164. odxtools/variantpattern.py +3 -4
  165. odxtools/version.py +2 -2
  166. odxtools/writepdxfile.py +0 -19
  167. odxtools/xdoc.py +11 -10
  168. {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/METADATA +1 -1
  169. odxtools-10.1.0.dist-info/RECORD +265 -0
  170. {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/WHEEL +1 -1
  171. odxtools-10.0.0.dist-info/RECORD +0 -264
  172. {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/entry_points.txt +0 -0
  173. {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/licenses/LICENSE +0 -0
  174. {odxtools-10.0.0.dist-info → odxtools-10.1.0.dist-info}/top_level.txt +0 -0
odxtools/subcomponent.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,7 +7,8 @@ from .dtcconnector import DtcConnector
7
7
  from .element import IdentifiableElement
8
8
  from .envdataconnector import EnvDataConnector
9
9
  from .nameditemlist import NamedItemList
10
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId
11
12
  from .snrefcontext import SnRefContext
12
13
  from .subcomponentparamconnector import SubComponentParamConnector
13
14
  from .subcomponentpattern import SubComponentPattern
@@ -15,7 +16,7 @@ from .tablerowconnector import TableRowConnector
15
16
  from .utils import dataclass_fields_asdict
16
17
 
17
18
 
18
- @dataclass
19
+ @dataclass(kw_only=True)
19
20
  class SubComponent(IdentifiableElement):
20
21
  """Sub-components describe collections of related diagnostic variables
21
22
 
@@ -25,38 +26,39 @@ class SubComponent(IdentifiableElement):
25
26
 
26
27
  """
27
28
 
28
- sub_component_patterns: list[SubComponentPattern]
29
- sub_component_param_connectors: NamedItemList[SubComponentParamConnector]
30
- table_row_connectors: NamedItemList[TableRowConnector]
31
- env_data_connectors: NamedItemList[EnvDataConnector]
32
- dtc_connectors: NamedItemList[DtcConnector]
29
+ sub_component_patterns: list[SubComponentPattern] = field(default_factory=list)
30
+ sub_component_param_connectors: NamedItemList[SubComponentParamConnector] = field(
31
+ default_factory=NamedItemList)
32
+ table_row_connectors: NamedItemList[TableRowConnector] = field(default_factory=NamedItemList)
33
+ env_data_connectors: NamedItemList[EnvDataConnector] = field(default_factory=NamedItemList)
34
+ dtc_connectors: NamedItemList[DtcConnector] = field(default_factory=NamedItemList)
33
35
 
34
- semantic: str | None
36
+ semantic: str | None = None
35
37
 
36
38
  @staticmethod
37
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "SubComponent":
38
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
39
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "SubComponent":
40
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
39
41
 
40
42
  semantic = et_element.get("SEMANTIC")
41
43
 
42
44
  sub_component_patterns = [
43
- SubComponentPattern.from_et(el, doc_frags)
45
+ SubComponentPattern.from_et(el, context)
44
46
  for el in et_element.iterfind("SUB-COMPONENT-PATTERNS/SUB-COMPONENT-PATTERN")
45
47
  ]
46
48
  sub_component_param_connectors = [
47
- SubComponentParamConnector.from_et(el, doc_frags) for el in et_element.iterfind(
49
+ SubComponentParamConnector.from_et(el, context) for el in et_element.iterfind(
48
50
  "SUB-COMPONENT-PARAM-CONNECTORS/SUB-COMPONENT-PARAM-CONNECTOR")
49
51
  ]
50
52
  table_row_connectors = [
51
- TableRowConnector.from_et(el, doc_frags)
53
+ TableRowConnector.from_et(el, context)
52
54
  for el in et_element.iterfind("TABLE-ROW-CONNECTORS/TABLE-ROW-CONNECTOR")
53
55
  ]
54
56
  env_data_connectors = [
55
- EnvDataConnector.from_et(el, doc_frags)
57
+ EnvDataConnector.from_et(el, context)
56
58
  for el in et_element.iterfind("ENV-DATA-CONNECTORS/ENV-DATA-CONNECTOR")
57
59
  ]
58
60
  dtc_connectors = [
59
- DtcConnector.from_et(el, doc_frags)
61
+ DtcConnector.from_et(el, context)
60
62
  for el in et_element.iterfind("DTC-CONNECTORS/DTC-CONNECTOR")
61
63
  ]
62
64
 
@@ -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,19 +7,20 @@ from .diagservice import DiagService
7
7
  from .element import IdentifiableElement
8
8
  from .exceptions import odxassert, odxraise, odxrequire
9
9
  from .nameditemlist import NamedItemList
10
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, resolve_snref
10
+ from .odxdoccontext import OdxDocContext
11
+ from .odxlink import OdxLinkDatabase, OdxLinkId, resolve_snref
11
12
  from .parameters.parameter import Parameter
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 SubComponentParamConnector(IdentifiableElement):
18
19
  diag_comm_snref: str
19
20
 
20
21
  # TODO: we currently only support SNREFs, not SNPATHREFs
21
- out_param_if_refs: list[str]
22
- in_param_if_refs: list[str]
22
+ out_param_if_refs: list[str] = field(default_factory=list)
23
+ in_param_if_refs: list[str] = field(default_factory=list)
23
24
 
24
25
  @property
25
26
  def service(self) -> DiagService:
@@ -35,8 +36,8 @@ class SubComponentParamConnector(IdentifiableElement):
35
36
 
36
37
  @staticmethod
37
38
  def from_et(et_element: ElementTree.Element,
38
- doc_frags: list[OdxDocFragment]) -> "SubComponentParamConnector":
39
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
39
+ context: OdxDocContext) -> "SubComponentParamConnector":
40
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
40
41
 
41
42
  diag_comm_snref = odxrequire(
42
43
  odxrequire(et_element.find("DIAG-COMM-SNREF")).get("SHORT-NAME"))
@@ -1,26 +1,26 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass
2
+ from dataclasses import dataclass, field
3
3
  from typing import TYPE_CHECKING, 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
  if TYPE_CHECKING:
10
11
  from .matchingparameter import MatchingParameter
11
12
 
12
13
 
13
- @dataclass
14
+ @dataclass(kw_only=True)
14
15
  class SubComponentPattern:
15
- matching_parameters: list["MatchingParameter"]
16
+ matching_parameters: list["MatchingParameter"] = field(default_factory=list)
16
17
 
17
18
  @staticmethod
18
- def from_et(et_element: ElementTree.Element,
19
- doc_frags: list[OdxDocFragment]) -> "SubComponentPattern":
19
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "SubComponentPattern":
20
20
  from .matchingparameter import MatchingParameter
21
21
 
22
22
  matching_parameters = [
23
- MatchingParameter.from_et(el, doc_frags)
23
+ MatchingParameter.from_et(el, context)
24
24
  for el in et_element.iterfind("MATCHING-PARAMETERS/MATCHING-PARAMETER")
25
25
  ]
26
26
 
odxtools/swvariable.py CHANGED
@@ -3,18 +3,18 @@ from dataclasses import dataclass
3
3
  from xml.etree import ElementTree
4
4
 
5
5
  from .element import NamedElement
6
- from .odxlink import OdxDocFragment
6
+ from .odxdoccontext import OdxDocContext
7
7
  from .utils import dataclass_fields_asdict
8
8
 
9
9
 
10
- @dataclass
10
+ @dataclass(kw_only=True)
11
11
  class SwVariable(NamedElement):
12
- origin: str | None
13
- oid: str | None
12
+ origin: str | None = None
13
+ oid: str | None = None
14
14
 
15
15
  @staticmethod
16
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "SwVariable":
17
- kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
16
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "SwVariable":
17
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, context))
18
18
 
19
19
  origin = et_element.findtext("ORIGIN")
20
20
  oid = et_element.attrib.get("OID")
odxtools/table.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
 
@@ -8,7 +8,8 @@ from .dataobjectproperty import DataObjectProperty
8
8
  from .element import IdentifiableElement
9
9
  from .exceptions import odxassert
10
10
  from .nameditemlist import NamedItemList
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 .specialdatagroup import SpecialDataGroup
14
15
  from .tablediagcommconnector import TableDiagCommConnector
@@ -16,17 +17,17 @@ from .tablerow import TableRow
16
17
  from .utils import dataclass_fields_asdict
17
18
 
18
19
 
19
- @dataclass
20
+ @dataclass(kw_only=True)
20
21
  class Table(IdentifiableElement):
21
22
  """This class represents a TABLE."""
22
- key_label: str | None
23
- struct_label: str | None
24
- admin_data: AdminData | None
25
- key_dop_ref: OdxLinkRef | None
26
- table_rows_raw: list[TableRow | OdxLinkRef]
27
- table_diag_comm_connectors: list[TableDiagCommConnector]
28
- sdgs: list[SpecialDataGroup]
29
- semantic: str | None
23
+ key_label: str | None = None
24
+ struct_label: str | None = None
25
+ admin_data: AdminData | None = None
26
+ key_dop_ref: OdxLinkRef | None = None
27
+ table_rows_raw: list[TableRow | OdxLinkRef] = field(default_factory=list)
28
+ table_diag_comm_connectors: list[TableDiagCommConnector] = field(default_factory=list)
29
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
30
+ semantic: str | None = None
30
31
 
31
32
  @property
32
33
  def key_dop(self) -> DataObjectProperty | None:
@@ -39,31 +40,29 @@ class Table(IdentifiableElement):
39
40
  return self._table_rows
40
41
 
41
42
  @staticmethod
42
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Table":
43
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Table":
43
44
  """Reads a TABLE."""
44
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
45
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
45
46
  odx_id = kwargs["odx_id"]
46
47
  key_label = et_element.findtext("KEY-LABEL")
47
48
  struct_label = et_element.findtext("STRUCT-LABEL")
48
- admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
49
- key_dop_ref = OdxLinkRef.from_et(et_element.find("KEY-DOP-REF"), doc_frags)
49
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
50
+ key_dop_ref = OdxLinkRef.from_et(et_element.find("KEY-DOP-REF"), context)
50
51
 
51
52
  table_rows_raw: list[OdxLinkRef | TableRow] = []
52
53
  for sub_elem in et_element:
53
54
  if sub_elem.tag == "TABLE-ROW":
54
55
  table_rows_raw.append(
55
56
  TableRow.tablerow_from_et(
56
- sub_elem, doc_frags, table_ref=OdxLinkRef.from_id(odx_id)))
57
+ sub_elem, context, table_ref=OdxLinkRef.from_id(odx_id)))
57
58
  elif sub_elem.tag == "TABLE-ROW-REF":
58
- table_rows_raw.append(OdxLinkRef.from_et(sub_elem, doc_frags))
59
+ table_rows_raw.append(OdxLinkRef.from_et(sub_elem, context))
59
60
 
60
61
  table_diag_comm_connectors = [
61
- TableDiagCommConnector.from_et(dcc_elem, doc_frags) for dcc_elem in et_element.iterfind(
62
+ TableDiagCommConnector.from_et(dcc_elem, context) for dcc_elem in et_element.iterfind(
62
63
  "TABLE-DIAG-COMM-CONNECTORS/TABLE-DIAG-COMM-CONNECTOR")
63
64
  ]
64
- sdgs = [
65
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
66
- ]
65
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
67
66
  semantic = et_element.get("SEMANTIC")
68
67
 
69
68
  return Table(
@@ -5,16 +5,17 @@ from xml.etree import ElementTree
5
5
 
6
6
  from .diagcomm import DiagComm
7
7
  from .exceptions import odxrequire
8
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
8
+ from .odxdoccontext import OdxDocContext
9
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
9
10
  from .snrefcontext import SnRefContext
10
11
 
11
12
 
12
- @dataclass
13
+ @dataclass(kw_only=True)
13
14
  class TableDiagCommConnector:
14
15
  semantic: str
15
16
 
16
- diag_comm_ref: OdxLinkRef | None
17
- diag_comm_snref: str | None
17
+ diag_comm_ref: OdxLinkRef | None = None
18
+ diag_comm_snref: str | None = None
18
19
 
19
20
  @property
20
21
  def diag_comm(self) -> DiagComm:
@@ -22,11 +23,11 @@ class TableDiagCommConnector:
22
23
 
23
24
  @staticmethod
24
25
  def from_et(et_element: ElementTree.Element,
25
- doc_frags: list[OdxDocFragment]) -> "TableDiagCommConnector":
26
+ context: OdxDocContext) -> "TableDiagCommConnector":
26
27
 
27
28
  semantic = odxrequire(et_element.findtext("SEMANTIC"))
28
29
 
29
- diag_comm_ref = OdxLinkRef.from_et(et_element.find("DIAG-COMM-REF"), doc_frags)
30
+ diag_comm_ref = OdxLinkRef.from_et(et_element.find("DIAG-COMM-REF"), context)
30
31
  diag_comm_snref = None
31
32
  if (dc_snref_elem := et_element.find("DIAG-COMM-SNREF")) is not None:
32
33
  diag_comm_snref = odxrequire(dc_snref_elem.get("SHORT-NAME"))
odxtools/tablerow.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # SPDX-License-Identifier: MIT
2
- from dataclasses import dataclass, fields
3
- from typing import TYPE_CHECKING, Any
2
+ from dataclasses import dataclass, field
3
+ from typing import TYPE_CHECKING, Any, cast
4
4
  from xml.etree import ElementTree
5
5
 
6
6
  from .admindata import AdminData
@@ -11,7 +11,8 @@ from .element import IdentifiableElement
11
11
  from .exceptions import odxassert, odxraise, odxrequire
12
12
  from .functionalclass import FunctionalClass
13
13
  from .nameditemlist import NamedItemList
14
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
14
+ from .odxdoccontext import OdxDocContext
15
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
15
16
  from .odxtypes import AtomicOdxType, odxstr_to_bool
16
17
  from .preconditionstateref import PreConditionStateRef
17
18
  from .snrefcontext import SnRefContext
@@ -24,7 +25,7 @@ if TYPE_CHECKING:
24
25
  from .table import Table
25
26
 
26
27
 
27
- @dataclass
28
+ @dataclass(kw_only=True)
28
29
  class TableRow(IdentifiableElement):
29
30
  """This class represents a TABLE-ROW."""
30
31
  table_ref: OdxLinkRef
@@ -33,22 +34,22 @@ class TableRow(IdentifiableElement):
33
34
  # The spec mandates that either a structure or a non-complex DOP
34
35
  # must be referenced here, i.e., exactly one of the four
35
36
  # attributes below is not None
36
- dop_ref: OdxLinkRef | None
37
- dop_snref: str | None
38
- structure_ref: OdxLinkRef | None
39
- structure_snref: str | None
40
-
41
- sdgs: list[SpecialDataGroup]
42
- audience: Audience | None
43
- functional_class_refs: list[OdxLinkRef]
44
- state_transition_refs: list[StateTransitionRef]
45
- pre_condition_state_refs: list[PreConditionStateRef]
46
- admin_data: AdminData | None
47
-
48
- is_executable_raw: bool | None
49
- semantic: str | None
50
- is_mandatory_raw: bool | None
51
- is_final_raw: bool | None
37
+ dop_ref: OdxLinkRef | None = None
38
+ dop_snref: str | None = None
39
+ structure_ref: OdxLinkRef | None = None
40
+ structure_snref: str | None = None
41
+
42
+ sdgs: list[SpecialDataGroup] = field(default_factory=list)
43
+ audience: Audience | None = None
44
+ functional_class_refs: list[OdxLinkRef] = field(default_factory=list)
45
+ state_transition_refs: list[StateTransitionRef] = field(default_factory=list)
46
+ pre_condition_state_refs: list[PreConditionStateRef] = field(default_factory=list)
47
+ admin_data: AdminData | None = None
48
+
49
+ is_executable_raw: bool | None = None
50
+ semantic: str | None = None
51
+ is_mandatory_raw: bool | None = None
52
+ is_final_raw: bool | None = None
52
53
 
53
54
  @property
54
55
  def table(self) -> "Table":
@@ -87,52 +88,50 @@ class TableRow(IdentifiableElement):
87
88
  return self.is_final_raw is True
88
89
 
89
90
  @staticmethod
90
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> Any:
91
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> Any:
91
92
  raise RuntimeError(
92
93
  "Calling TableRow.from_et() is not allowed. Use TableRow.tablerow_from_et().")
93
94
 
94
95
  @staticmethod
95
- def tablerow_from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment], *,
96
+ def tablerow_from_et(et_element: ElementTree.Element, context: OdxDocContext, *,
96
97
  table_ref: OdxLinkRef) -> "TableRow":
97
98
  """Reads a TABLE-ROW."""
98
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
99
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
99
100
 
100
101
  key_raw = odxrequire(et_element.findtext("KEY"))
101
102
 
102
- dop_ref = OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), doc_frags)
103
+ dop_ref = OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), context)
103
104
  dop_snref: str | None = None
104
105
  if (dop_snref_elem := et_element.find("DATA-OBJECT-PROP-SNREF")) is not None:
105
106
  dop_snref = dop_snref_elem.attrib["SHORT-NAME"]
106
107
 
107
- structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), doc_frags)
108
+ structure_ref = OdxLinkRef.from_et(et_element.find("STRUCTURE-REF"), context)
108
109
  structure_snref: str | None = None
109
110
  if (structure_snref_elem := et_element.find("STRUCTURE-SNREF")) is not None:
110
111
  structure_snref = structure_snref_elem.attrib["SHORT-NAME"]
111
112
 
112
- sdgs = [
113
- SpecialDataGroup.from_et(sdge, doc_frags) for sdge in et_element.iterfind("SDGS/SDG")
114
- ]
113
+ sdgs = [SpecialDataGroup.from_et(sdge, context) for sdge in et_element.iterfind("SDGS/SDG")]
115
114
 
116
115
  audience = None
117
116
  if (audience_elem := et_element.find("AUDIENCE")) is not None:
118
- audience = Audience.from_et(audience_elem, doc_frags)
117
+ audience = Audience.from_et(audience_elem, context)
119
118
 
120
119
  functional_class_refs = [
121
- odxrequire(OdxLinkRef.from_et(el, doc_frags))
120
+ odxrequire(OdxLinkRef.from_et(el, context))
122
121
  for el in et_element.iterfind("FUNCT-CLASS-REFS/FUNCT-CLASS-REF")
123
122
  ]
124
123
 
125
124
  state_transition_refs = [
126
- StateTransitionRef.from_et(el, doc_frags)
125
+ StateTransitionRef.from_et(el, context)
127
126
  for el in et_element.iterfind("STATE-TRANSITION-REFS/STATE-TRANSITION-REF")
128
127
  ]
129
128
 
130
129
  pre_condition_state_refs = [
131
- PreConditionStateRef.from_et(el, doc_frags)
130
+ PreConditionStateRef.from_et(el, context)
132
131
  for el in et_element.iterfind("PRE-CONDITION-STATE-REFS/PRE-CONDITION-STATE-REF")
133
132
  ]
134
133
 
135
- admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), doc_frags)
134
+ admin_data = AdminData.from_et(et_element.find("ADMIN-DATA"), context)
136
135
 
137
136
  is_executable_raw = odxstr_to_bool(et_element.attrib.get("IS-EXECUTABLE"))
138
137
  semantic = et_element.attrib.get("SEMANTIC")
@@ -199,7 +198,7 @@ class TableRow(IdentifiableElement):
199
198
 
200
199
  if self.dop_ref is not None:
201
200
  self._dop = odxlinks.resolve(self.dop_ref)
202
- if not isinstance(self._dop, DataObjectProperty | DtcDop):
201
+ if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
203
202
  odxraise("The DOP-REF of TABLE-ROWs must reference a simple DOP!")
204
203
  if self.structure_ref is not None:
205
204
  self._structure = odxlinks.resolve(self.structure_ref, Structure)
@@ -243,7 +242,7 @@ class TableRow(IdentifiableElement):
243
242
  self._structure = resolve_snref(self.structure_snref, ddd_spec.structures, Structure)
244
243
  if self.dop_snref is not None:
245
244
  self._dop = resolve_snref(self.dop_snref, ddd_spec.data_object_props)
246
- if not isinstance(self._dop, DataObjectProperty | DtcDop):
245
+ if not isinstance(self._dop, (DataObjectProperty, DtcDop)):
247
246
  odxraise("The DOP-SNREF of TABLE-ROWs must reference a simple DOP!")
248
247
 
249
248
  if self.audience is not None:
@@ -261,4 +260,26 @@ class TableRow(IdentifiableElement):
261
260
  def __reduce__(self) -> tuple[Any, ...]:
262
261
  """This ensures that the object can be correctly reconstructed during unpickling."""
263
262
  state = self.__dict__.copy()
264
- return self.__class__, tuple([getattr(self, x.name) for x in fields(self)]), state
263
+ return _reconstruct_tablerow, (self.__class__, state)
264
+
265
+ def __setstate__(self, state: dict[str, Any]) -> None:
266
+ """
267
+ Restore the object's internal state.
268
+
269
+ This method is called during the unpickling, it updates
270
+ the instance's __dict__ with the saved state.
271
+ """
272
+ self.__dict__.update(state)
273
+
274
+
275
+ def _reconstruct_tablerow(cls: Any, state: dict[str, Any]) -> TableRow:
276
+ """
277
+ Reconstruct a TableRow instance from pickled state.
278
+
279
+ This function is used during unpickling to bypass the `__init__`
280
+ constructor, which would normally enforce `kw_only=True` arguments.
281
+ Instead, it creates an uninitialized object and restores its state.
282
+ """
283
+ obj = cls.__new__(cls)
284
+ obj.__setstate__(state)
285
+ return cast(TableRow, obj)
@@ -5,14 +5,15 @@ from xml.etree import ElementTree
5
5
 
6
6
  from .element import NamedElement
7
7
  from .exceptions import odxrequire
8
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
8
+ from .odxdoccontext import OdxDocContext
9
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef, resolve_snref
9
10
  from .snrefcontext import SnRefContext
10
11
  from .table import Table
11
12
  from .tablerow import TableRow
12
13
  from .utils import dataclass_fields_asdict
13
14
 
14
15
 
15
- @dataclass
16
+ @dataclass(kw_only=True)
16
17
  class TableRowConnector(NamedElement):
17
18
  table_ref: OdxLinkRef
18
19
  table_row_snref: str
@@ -26,11 +27,10 @@ class TableRowConnector(NamedElement):
26
27
  return self._table_row
27
28
 
28
29
  @staticmethod
29
- def from_et(et_element: ElementTree.Element,
30
- doc_frags: list[OdxDocFragment]) -> "TableRowConnector":
31
- kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, doc_frags))
30
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "TableRowConnector":
31
+ kwargs = dataclass_fields_asdict(NamedElement.from_et(et_element, context))
32
32
 
33
- table_ref = odxrequire(OdxLinkRef.from_et(et_element.find("TABLE-REF"), doc_frags))
33
+ table_ref = odxrequire(OdxLinkRef.from_et(et_element.find("TABLE-REF"), context))
34
34
  table_row_snref_el = odxrequire(et_element.find("TABLE-ROW-SNREF"))
35
35
  table_row_snref = odxrequire(table_row_snref_el.get("SHORT-NAME"))
36
36
 
odxtools/teammember.py CHANGED
@@ -1,29 +1,30 @@
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
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
8
+ from .odxdoccontext import OdxDocContext
9
+ from .odxlink import OdxLinkDatabase, OdxLinkId
9
10
  from .snrefcontext import SnRefContext
10
11
  from .utils import dataclass_fields_asdict
11
12
 
12
13
 
13
- @dataclass
14
+ @dataclass(kw_only=True)
14
15
  class TeamMember(IdentifiableElement):
15
- roles: list[str]
16
- department: str | None
17
- address: str | None
18
- zipcode: str | None # the tag for this is "ZIP", but `zip` is a keyword in python
19
- city: str | None
20
- phone: str | None
21
- fax: str | None
22
- email: str | None
16
+ roles: list[str] = field(default_factory=list)
17
+ department: str | None = None
18
+ address: str | None = None
19
+ zipcode: str | None = None # the tag for this is "ZIP", but `zip` is a keyword in python
20
+ city: str | None = None
21
+ phone: str | None = None
22
+ fax: str | None = None
23
+ email: str | None = None
23
24
 
24
25
  @staticmethod
25
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "TeamMember":
26
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
26
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "TeamMember":
27
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
27
28
 
28
29
  roles = [odxrequire(role_elem.text) for role_elem in et_element.iterfind("ROLES/ROLE")]
29
30
  department = et_element.findtext("DEPARTMENT")
@@ -5,8 +5,10 @@
5
5
 
6
6
  {%- macro printParentRef(par) -%}
7
7
  <PARENT-REF ID-REF="{{par.layer.odx_id.local_id}}"
8
- DOCREF="{{get_parent_container_name(par.layer.short_name)}}"
8
+ {%- if par.layer_ref.ref_docs|length == 1 %}
9
+ DOCREF="{{par.layer_ref.ref_docs[0].doc_name}}"
9
10
  DOCTYPE="CONTAINER"
11
+ {%- endif %}
10
12
  xsi:type="{{par.layer.variant_type.value}}-REF">
11
13
  {%- if par.not_inherited_diag_comms %}
12
14
  <NOT-INHERITED-DIAG-COMMS>
odxtools/text.py CHANGED
@@ -1,16 +1,16 @@
1
1
  from dataclasses import dataclass
2
2
  from xml.etree import ElementTree
3
3
 
4
- from .odxlink import OdxDocFragment
4
+ from .odxdoccontext import OdxDocContext
5
5
 
6
6
 
7
- @dataclass
7
+ @dataclass(kw_only=True)
8
8
  class Text:
9
9
  text: str
10
- text_identifier: str | None
10
+ text_identifier: str | None = None
11
11
 
12
12
  @staticmethod
13
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Text":
13
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Text":
14
14
  # Extract the contents of the tag as a string.
15
15
  raw_string = et_element.text or ""
16
16
  for e in et_element:
odxtools/unit.py CHANGED
@@ -5,13 +5,14 @@ from xml.etree import ElementTree
5
5
 
6
6
  from .element import IdentifiableElement
7
7
  from .exceptions import odxrequire
8
- from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
8
+ from .odxdoccontext import OdxDocContext
9
+ from .odxlink import OdxLinkDatabase, OdxLinkId, OdxLinkRef
9
10
  from .physicaldimension import PhysicalDimension
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 Unit(IdentifiableElement):
16
17
  """
17
18
  A unit consists of an ID, short name and a display name.
@@ -53,17 +54,17 @@ class Unit(IdentifiableElement):
53
54
  ```
54
55
  """
55
56
  display_name: str
56
- factor_si_to_unit: float | None
57
- offset_si_to_unit: float | None
58
- physical_dimension_ref: OdxLinkRef | None
57
+ factor_si_to_unit: float | None = None
58
+ offset_si_to_unit: float | None = None
59
+ physical_dimension_ref: OdxLinkRef | None = None
59
60
 
60
61
  @property
61
62
  def physical_dimension(self) -> PhysicalDimension | None:
62
63
  return self._physical_dimension
63
64
 
64
65
  @staticmethod
65
- def from_et(et_element: ElementTree.Element, doc_frags: list[OdxDocFragment]) -> "Unit":
66
- kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
66
+ def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Unit":
67
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
67
68
 
68
69
  display_name = odxrequire(et_element.findtext("DISPLAY-NAME"))
69
70
 
@@ -76,7 +77,7 @@ class Unit(IdentifiableElement):
76
77
  factor_si_to_unit = read_optional_float(et_element, "FACTOR-SI-TO-UNIT")
77
78
  offset_si_to_unit = read_optional_float(et_element, "OFFSET-SI-TO-UNIT")
78
79
  physical_dimension_ref = OdxLinkRef.from_et(
79
- et_element.find("PHYSICAL-DIMENSION-REF"), doc_frags)
80
+ et_element.find("PHYSICAL-DIMENSION-REF"), context)
80
81
 
81
82
  return Unit(
82
83
  display_name=display_name,