odxtools 9.5.0__py3-none-any.whl → 9.6.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 (102) hide show
  1. odxtools/additionalaudience.py +2 -2
  2. odxtools/admindata.py +3 -0
  3. odxtools/audience.py +9 -13
  4. odxtools/basecomparam.py +1 -2
  5. odxtools/basevariantpattern.py +5 -5
  6. odxtools/basicstructure.py +34 -35
  7. odxtools/commrelation.py +2 -1
  8. odxtools/companydata.py +1 -2
  9. odxtools/companyspecificinfo.py +3 -0
  10. odxtools/comparam.py +16 -8
  11. odxtools/comparaminstance.py +12 -12
  12. odxtools/comparamspec.py +4 -3
  13. odxtools/comparamsubset.py +26 -24
  14. odxtools/compumethods/compuconst.py +4 -4
  15. odxtools/compumethods/limit.py +9 -9
  16. odxtools/compumethods/linearsegment.py +8 -8
  17. odxtools/dataobjectproperty.py +16 -18
  18. odxtools/description.py +4 -2
  19. odxtools/determinenumberofitems.py +4 -4
  20. odxtools/diagcodedtype.py +20 -20
  21. odxtools/diagcomm.py +61 -41
  22. odxtools/diagdatadictionaryspec.py +51 -55
  23. odxtools/diaglayercontainer.py +25 -25
  24. odxtools/diaglayers/diaglayerraw.py +26 -27
  25. odxtools/diagnostictroublecode.py +13 -10
  26. odxtools/diagservice.py +48 -50
  27. odxtools/diagvariable.py +10 -8
  28. odxtools/docrevision.py +5 -5
  29. odxtools/dtcdop.py +17 -17
  30. odxtools/dynamicendmarkerfield.py +8 -8
  31. odxtools/dynamiclengthfield.py +2 -0
  32. odxtools/dyndefinedspec.py +21 -8
  33. odxtools/encodestate.py +1 -2
  34. odxtools/endofpdufield.py +7 -9
  35. odxtools/environmentdatadescription.py +9 -20
  36. odxtools/field.py +21 -21
  37. odxtools/inputparam.py +15 -14
  38. odxtools/leadinglengthinfotype.py +4 -4
  39. odxtools/matchingparameter.py +2 -3
  40. odxtools/minmaxlengthtype.py +7 -7
  41. odxtools/multiplexer.py +38 -39
  42. odxtools/multiplexercase.py +3 -6
  43. odxtools/multiplexerdefaultcase.py +3 -6
  44. odxtools/multiplexerswitchkey.py +4 -4
  45. odxtools/negoutputparam.py +6 -9
  46. odxtools/odxlink.py +21 -5
  47. odxtools/odxtypes.py +4 -4
  48. odxtools/outputparam.py +9 -8
  49. odxtools/parameterinfo.py +1 -1
  50. odxtools/parameters/codedconstparameter.py +28 -27
  51. odxtools/parameters/dynamicparameter.py +9 -9
  52. odxtools/parameters/lengthkeyparameter.py +18 -18
  53. odxtools/parameters/matchingrequestparameter.py +15 -15
  54. odxtools/parameters/nrcconstparameter.py +32 -24
  55. odxtools/parameters/parameter.py +35 -37
  56. odxtools/parameters/parameterwithdop.py +6 -6
  57. odxtools/parameters/physicalconstantparameter.py +19 -20
  58. odxtools/parameters/reservedparameter.py +10 -11
  59. odxtools/parameters/systemparameter.py +10 -11
  60. odxtools/parameters/tableentryparameter.py +19 -20
  61. odxtools/parameters/tablekeyparameter.py +0 -2
  62. odxtools/parameters/tablestructparameter.py +27 -21
  63. odxtools/parameters/valueparameter.py +20 -20
  64. odxtools/parentref.py +6 -7
  65. odxtools/physicaldimension.py +11 -11
  66. odxtools/physicaltype.py +9 -14
  67. odxtools/preconditionstateref.py +85 -0
  68. odxtools/progcode.py +1 -2
  69. odxtools/protstack.py +4 -4
  70. odxtools/relateddoc.py +3 -4
  71. odxtools/scaleconstr.py +0 -1
  72. odxtools/singleecujob.py +8 -4
  73. odxtools/specialdata.py +10 -9
  74. odxtools/specialdatagroup.py +1 -0
  75. odxtools/standardlengthtype.py +10 -10
  76. odxtools/statechart.py +10 -6
  77. odxtools/statemachine.py +186 -0
  78. odxtools/statetransitionref.py +231 -0
  79. odxtools/structure.py +4 -4
  80. odxtools/subcomponent.py +72 -8
  81. odxtools/table.py +23 -13
  82. odxtools/tablerow.py +86 -69
  83. odxtools/teammember.py +4 -4
  84. odxtools/templates/macros/printCompanyData.xml.jinja2 +2 -2
  85. odxtools/templates/macros/printComparam.xml.jinja2 +3 -5
  86. odxtools/templates/macros/printDOP.xml.jinja2 +4 -1
  87. odxtools/templates/macros/printDiagComm.xml.jinja2 +6 -5
  88. odxtools/templates/macros/printParam.xml.jinja2 +5 -5
  89. odxtools/templates/macros/printPreConditionStateRef.xml.jinja2 +18 -0
  90. odxtools/templates/macros/printStateTransitionRef.xml.jinja2 +18 -0
  91. odxtools/templates/macros/printTable.xml.jinja2 +13 -9
  92. odxtools/text.py +35 -0
  93. odxtools/unit.py +1 -3
  94. odxtools/unitgroup.py +6 -8
  95. odxtools/utils.py +0 -4
  96. odxtools/version.py +2 -2
  97. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/METADATA +3 -2
  98. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/RECORD +102 -96
  99. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/WHEEL +1 -1
  100. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/entry_points.txt +0 -0
  101. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info/licenses}/LICENSE +0 -0
  102. {odxtools-9.5.0.dist-info → odxtools-9.6.0.dist-info}/top_level.txt +0 -0
@@ -18,9 +18,9 @@ class AdditionalAudience(IdentifiableElement):
18
18
  @staticmethod
19
19
  def from_et(et_element: ElementTree.Element,
20
20
  doc_frags: List[OdxDocFragment]) -> "AdditionalAudience":
21
+ kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
21
22
 
22
- return AdditionalAudience(
23
- **dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags)))
23
+ return AdditionalAudience(**kwargs)
24
24
 
25
25
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
26
26
  return {self.odx_id: self}
odxtools/admindata.py CHANGED
@@ -43,6 +43,9 @@ class AdminData:
43
43
  for cdi in self.company_doc_infos:
44
44
  result.update(cdi._build_odxlinks())
45
45
 
46
+ for dr in self.doc_revisions:
47
+ result.update(dr._build_odxlinks())
48
+
46
49
  return result
47
50
 
48
51
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
odxtools/audience.py CHANGED
@@ -16,31 +16,27 @@ class Audience:
16
16
  disabled_audience_refs: List[OdxLinkRef]
17
17
 
18
18
  is_supplier_raw: Optional[bool]
19
+ is_development_raw: Optional[bool]
20
+ is_manufacturing_raw: Optional[bool]
21
+ is_aftersales_raw: Optional[bool]
22
+ is_aftermarket_raw: Optional[bool]
19
23
 
20
24
  @property
21
25
  def is_supplier(self) -> bool:
22
26
  return self.is_supplier_raw in [None, True]
23
27
 
24
- is_development_raw: Optional[bool]
25
-
26
28
  @property
27
29
  def is_development(self) -> bool:
28
30
  return self.is_development_raw in [None, True]
29
31
 
30
- is_manufacturing_raw: Optional[bool]
31
-
32
32
  @property
33
33
  def is_manufacturing(self) -> bool:
34
34
  return self.is_manufacturing_raw in [None, True]
35
35
 
36
- is_aftersales_raw: Optional[bool]
37
-
38
36
  @property
39
37
  def is_aftersales(self) -> bool:
40
38
  return self.is_aftersales_raw in [None, True]
41
39
 
42
- is_aftermarket_raw: Optional[bool]
43
-
44
40
  @property
45
41
  def is_aftermarket(self) -> bool:
46
42
  return self.is_aftermarket_raw in [None, True]
@@ -66,11 +62,11 @@ class Audience:
66
62
  for ref in et_element.iterfind("DISABLED-AUDIENCE-REFS/"
67
63
  "DISABLED-AUDIENCE-REF")
68
64
  ]
69
- is_supplier_raw = odxstr_to_bool(et_element.get("IS-SUPPLIER"))
70
- is_development_raw = odxstr_to_bool(et_element.get("IS-DEVELOPMENT"))
71
- is_manufacturing_raw = odxstr_to_bool(et_element.get("IS-MANUFACTURING"))
72
- is_aftersales_raw = odxstr_to_bool(et_element.get("IS-AFTERSALES"))
73
- is_aftermarket_raw = odxstr_to_bool(et_element.get("IS-AFTERMARKET"))
65
+ is_supplier_raw = odxstr_to_bool(et_element.attrib.get("IS-SUPPLIER"))
66
+ is_development_raw = odxstr_to_bool(et_element.attrib.get("IS-DEVELOPMENT"))
67
+ is_manufacturing_raw = odxstr_to_bool(et_element.attrib.get("IS-MANUFACTURING"))
68
+ is_aftersales_raw = odxstr_to_bool(et_element.attrib.get("IS-AFTERSALES"))
69
+ is_aftermarket_raw = odxstr_to_bool(et_element.attrib.get("IS-AFTERMARKET"))
74
70
 
75
71
  return Audience(
76
72
  enabled_audience_refs=enabled_audience_refs,
odxtools/basecomparam.py CHANGED
@@ -29,9 +29,8 @@ class Usage(Enum):
29
29
  class BaseComparam(IdentifiableElement):
30
30
  param_class: str
31
31
  cptype: StandardizationLevel
32
- # Required in ODX 2.2, missing in ODX 2.0
33
- cpusage: Optional[Usage]
34
32
  display_level: Optional[int]
33
+ cpusage: Optional[Usage] # Required in ODX 2.2, missing in ODX 2.0
35
34
 
36
35
  @staticmethod
37
36
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "BaseComparam":
@@ -19,11 +19,6 @@ class BaseVariantPattern(VariantPattern):
19
19
  """
20
20
  matching_base_variant_parameters: List[MatchingBaseVariantParameter]
21
21
 
22
- @override
23
- def get_matching_parameters(
24
- self) -> Union[List[MatchingParameter], List[MatchingBaseVariantParameter]]:
25
- return self.matching_base_variant_parameters
26
-
27
22
  @staticmethod
28
23
  def from_et(et_element: ElementTree.Element,
29
24
  doc_frags: List[OdxDocFragment]) -> "BaseVariantPattern":
@@ -36,3 +31,8 @@ class BaseVariantPattern(VariantPattern):
36
31
 
37
32
  odxassert(len(matching_base_variant_parameters) > 0) # required by ISO 22901-1 Figure 141
38
33
  return BaseVariantPattern(matching_base_variant_parameters=matching_base_variant_parameters)
34
+
35
+ @override
36
+ def get_matching_parameters(
37
+ self) -> Union[List[MatchingParameter], List[MatchingBaseVariantParameter]]:
38
+ return self.matching_base_variant_parameters
@@ -29,8 +29,16 @@ class BasicStructure(ComplexDop):
29
29
  data objects. All structure-like objects adhere to the
30
30
  `CompositeCodec` type protocol.
31
31
  """
32
- parameters: NamedItemList[Parameter]
33
32
  byte_size: Optional[int]
33
+ parameters: NamedItemList[Parameter]
34
+
35
+ @property
36
+ def required_parameters(self) -> List[Parameter]:
37
+ return composite_codec_get_required_parameters(self)
38
+
39
+ @property
40
+ def free_parameters(self) -> List[Parameter]:
41
+ return composite_codec_get_free_parameters(self)
34
42
 
35
43
  @staticmethod
36
44
  def from_et(et_element: ElementTree.Element,
@@ -38,15 +46,37 @@ class BasicStructure(ComplexDop):
38
46
  """Read a BASIC-STRUCTURE."""
39
47
  kwargs = dataclass_fields_asdict(ComplexDop.from_et(et_element, doc_frags))
40
48
 
49
+ byte_size_str = et_element.findtext("BYTE-SIZE")
50
+ byte_size = int(byte_size_str) if byte_size_str is not None else None
41
51
  parameters = NamedItemList([
42
52
  create_any_parameter_from_et(et_parameter, doc_frags)
43
53
  for et_parameter in et_element.iterfind("PARAMS/PARAM")
44
54
  ])
45
55
 
46
- byte_size_str = et_element.findtext("BYTE-SIZE")
47
- byte_size = int(byte_size_str) if byte_size_str is not None else None
56
+ return BasicStructure(byte_size=byte_size, parameters=parameters, **kwargs)
57
+
58
+ def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
59
+ result = super()._build_odxlinks()
48
60
 
49
- return BasicStructure(parameters=parameters, byte_size=byte_size, **kwargs)
61
+ for param in self.parameters:
62
+ result.update(param._build_odxlinks())
63
+
64
+ return result
65
+
66
+ def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
67
+ super()._resolve_odxlinks(odxlinks)
68
+
69
+ for param in self.parameters:
70
+ param._resolve_odxlinks(odxlinks)
71
+
72
+ def _resolve_snrefs(self, context: SnRefContext) -> None:
73
+ context.parameters = self.parameters
74
+
75
+ super()._resolve_snrefs(context)
76
+ for param in self.parameters:
77
+ param._resolve_snrefs(context)
78
+
79
+ context.parameters = None
50
80
 
51
81
  def get_static_bit_length(self) -> Optional[int]:
52
82
  # Explicit size was specified, so we do not need to look at
@@ -56,14 +86,6 @@ class BasicStructure(ComplexDop):
56
86
 
57
87
  return composite_codec_get_static_bit_length(self)
58
88
 
59
- @property
60
- def required_parameters(self) -> List[Parameter]:
61
- return composite_codec_get_required_parameters(self)
62
-
63
- @property
64
- def free_parameters(self) -> List[Parameter]:
65
- return composite_codec_get_free_parameters(self)
66
-
67
89
  def print_free_parameters_info(self) -> None:
68
90
  """Return a human readable description of the structure's
69
91
  free parameters.
@@ -109,26 +131,3 @@ class BasicStructure(ComplexDop):
109
131
  decode_state.cursor_byte_position = orig_pos + self.byte_size
110
132
 
111
133
  return result
112
-
113
- def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
114
- result = super()._build_odxlinks()
115
-
116
- for param in self.parameters:
117
- result.update(param._build_odxlinks())
118
-
119
- return result
120
-
121
- def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
122
- super()._resolve_odxlinks(odxlinks)
123
-
124
- for param in self.parameters:
125
- param._resolve_odxlinks(odxlinks)
126
-
127
- def _resolve_snrefs(self, context: SnRefContext) -> None:
128
- context.parameters = self.parameters
129
-
130
- super()._resolve_snrefs(context)
131
- for param in self.parameters:
132
- param._resolve_snrefs(context)
133
-
134
- context.parameters = None
odxtools/commrelation.py CHANGED
@@ -77,7 +77,7 @@ class CommRelation:
77
77
  warnings.warn("SNPATHREFs are not supported by odxtools yet", OdxWarning, stacklevel=1)
78
78
 
79
79
  value_type_raw = None
80
- if (value_type_str := et_element.get("VALUE-TYPE")) is not None:
80
+ if (value_type_str := et_element.attrib.get("VALUE-TYPE")) is not None:
81
81
  try:
82
82
  value_type_raw = CommRelationValueType(value_type_str)
83
83
  except ValueError:
@@ -109,6 +109,7 @@ class CommRelation:
109
109
  if not isinstance(service, DiagService):
110
110
  odxraise(f"DIAG-VARIABLE references non-service {type(service).__name__} "
111
111
  f"diagnostic communication")
112
+ return
112
113
 
113
114
  self._in_param_if = None
114
115
  if self.in_param_if_snref is not None:
odxtools/companydata.py CHANGED
@@ -23,10 +23,10 @@ class CompanyData(IdentifiableElement):
23
23
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "CompanyData":
24
24
 
25
25
  kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, doc_frags))
26
+
26
27
  roles = []
27
28
  if (roles_elem := et_element.find("ROLES")) is not None:
28
29
  roles = [odxrequire(role.text) for role in roles_elem.iterfind("ROLE")]
29
-
30
30
  team_members = [
31
31
  TeamMember.from_et(tm, doc_frags)
32
32
  for tm in et_element.iterfind("TEAM-MEMBERS/TEAM-MEMBER")
@@ -46,7 +46,6 @@ class CompanyData(IdentifiableElement):
46
46
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
47
47
  result = {self.odx_id: self}
48
48
 
49
- # team members
50
49
  for tm in self.team_members:
51
50
  result.update(tm._build_odxlinks())
52
51
 
@@ -31,6 +31,9 @@ class CompanySpecificInfo:
31
31
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
32
32
  result = {}
33
33
 
34
+ for rd in self.related_docs:
35
+ result.update(rd._build_odxlinks())
36
+
34
37
  for sdg in self.sdgs:
35
38
  result.update(sdg._build_odxlinks())
36
39
 
odxtools/comparam.py CHANGED
@@ -7,28 +7,34 @@ from .basecomparam import BaseComparam
7
7
  from .dataobjectproperty import DataObjectProperty
8
8
  from .exceptions import odxrequire
9
9
  from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId, OdxLinkRef
10
+ from .odxtypes import AtomicOdxType
10
11
  from .snrefcontext import SnRefContext
11
12
  from .utils import dataclass_fields_asdict
12
13
 
13
14
 
14
15
  @dataclass
15
16
  class Comparam(BaseComparam):
17
+ physical_default_value_raw: str
16
18
  dop_ref: OdxLinkRef
17
- physical_default_value: str
19
+
20
+ @property
21
+ def physical_default_value(self) -> AtomicOdxType:
22
+ return self._physical_default_value
23
+
24
+ @property
25
+ def dop(self) -> DataObjectProperty:
26
+ """The data object property applicable to this parameter."""
27
+ return self._dop
18
28
 
19
29
  @staticmethod
20
30
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "Comparam":
21
31
  kwargs = dataclass_fields_asdict(BaseComparam.from_et(et_element, doc_frags))
22
32
 
33
+ physical_default_value_raw = odxrequire(et_element.findtext("PHYSICAL-DEFAULT-VALUE"))
23
34
  dop_ref = odxrequire(OdxLinkRef.from_et(et_element.find("DATA-OBJECT-PROP-REF"), doc_frags))
24
- physical_default_value = odxrequire(et_element.findtext("PHYSICAL-DEFAULT-VALUE"))
25
-
26
- return Comparam(dop_ref=dop_ref, physical_default_value=physical_default_value, **kwargs)
27
35
 
28
- @property
29
- def dop(self) -> DataObjectProperty:
30
- """The data object property describing this parameter."""
31
- return self._dop
36
+ return Comparam(
37
+ dop_ref=dop_ref, physical_default_value_raw=physical_default_value_raw, **kwargs)
32
38
 
33
39
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
34
40
  return super()._build_odxlinks()
@@ -38,6 +44,8 @@ class Comparam(BaseComparam):
38
44
  super()._resolve_odxlinks(odxlinks)
39
45
 
40
46
  self._dop = odxlinks.resolve(self.dop_ref, DataObjectProperty)
47
+ self._physical_default_value = self._dop.physical_type.base_data_type.from_string(
48
+ self.physical_default_value_raw)
41
49
 
42
50
  def _resolve_snrefs(self, context: SnRefContext) -> None:
43
51
  super()._resolve_snrefs(context)
@@ -26,6 +26,14 @@ class ComparamInstance:
26
26
  prot_stack_snref: Optional[str]
27
27
  spec_ref: OdxLinkRef
28
28
 
29
+ @property
30
+ def spec(self) -> BaseComparam:
31
+ return self._spec
32
+
33
+ @property
34
+ def short_name(self) -> str:
35
+ return self.spec.short_name
36
+
29
37
  @staticmethod
30
38
  def from_et(et_element: ElementTree.Element,
31
39
  doc_frags: List[OdxDocFragment]) -> "ComparamInstance":
@@ -44,14 +52,14 @@ class ComparamInstance:
44
52
 
45
53
  description = Description.from_et(et_element.find("DESC"), doc_frags)
46
54
 
47
- prot_stack_snref = None
48
- if (psnref_elem := et_element.find("PROT-STACK-SNREF")) is not None:
49
- prot_stack_snref = psnref_elem.get("SHORT-NAME")
50
-
51
55
  protocol_snref = None
52
56
  if (psnref_elem := et_element.find("PROTOCOL-SNREF")) is not None:
53
57
  protocol_snref = psnref_elem.get("SHORT-NAME")
54
58
 
59
+ prot_stack_snref = None
60
+ if (psnref_elem := et_element.find("PROT-STACK-SNREF")) is not None:
61
+ prot_stack_snref = psnref_elem.get("SHORT-NAME")
62
+
55
63
  return ComparamInstance(
56
64
  value=value,
57
65
  spec_ref=spec_ref,
@@ -69,10 +77,6 @@ class ComparamInstance:
69
77
  def _resolve_snrefs(self, context: SnRefContext) -> None:
70
78
  pass
71
79
 
72
- @property
73
- def spec(self) -> BaseComparam:
74
- return self._spec
75
-
76
80
  def get_value(self) -> str:
77
81
  """Retrieve the value of a simple communication parameter
78
82
 
@@ -135,7 +139,3 @@ class ComparamInstance:
135
139
  odxraise()
136
140
 
137
141
  return result
138
-
139
- @property
140
- def short_name(self) -> str:
141
- return self.spec.short_name
odxtools/comparamspec.py CHANGED
@@ -22,9 +22,10 @@ class ComparamSpec(OdxCategory):
22
22
  @staticmethod
23
23
  def from_et(et_element: ElementTree.Element, doc_frags: List[OdxDocFragment]) -> "ComparamSpec":
24
24
 
25
- cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type=DocType.COMPARAM_SPEC)
26
- doc_frags = cat.odx_id.doc_fragments
27
- kwargs = dataclass_fields_asdict(cat)
25
+ base_obj = OdxCategory.category_from_et(
26
+ et_element, doc_frags, doc_type=DocType.COMPARAM_SPEC)
27
+ doc_frags = base_obj.odx_id.doc_fragments
28
+ kwargs = dataclass_fields_asdict(base_obj)
28
29
 
29
30
  prot_stacks = NamedItemList([
30
31
  ProtStack.from_et(dl_element, doc_frags)
@@ -29,51 +29,53 @@ class ComparamSubset(OdxCategory):
29
29
  def from_et(et_element: ElementTree.Element,
30
30
  doc_frags: List[OdxDocFragment]) -> "ComparamSubset":
31
31
 
32
- category = et_element.get("CATEGORY")
32
+ category_attrib = et_element.attrib.get("CATEGORY")
33
33
 
34
- # In ODX 2.0, COMPARAM-SPEC is used, whereas in ODX 2.2, it refers to something else and has been replaced by COMPARAM-SUBSET.
35
- # - If 'category' is missing (ODX 2.0), use COMPARAM_SPEC,
34
+ # In ODX 2.0, COMPARAM-SPEC is used, whereas in ODX 2.2, it
35
+ # refers to something else and has been replaced by
36
+ # COMPARAM-SUBSET.
37
+ # - If the 'CATEGORY' attribute is missing (ODX 2.0), use
38
+ # COMPARAM_SPEC,
36
39
  # - else (ODX 2.2), use COMPARAM_SUBSET.
37
- doc_type = DocType.COMPARAM_SUBSET if category else DocType.COMPARAM_SPEC
38
- cat = OdxCategory.category_from_et(et_element, doc_frags, doc_type=doc_type)
39
- doc_frags = cat.odx_id.doc_fragments
40
- kwargs = dataclass_fields_asdict(cat)
40
+ doc_type = DocType.COMPARAM_SUBSET if category_attrib is not None else DocType.COMPARAM_SPEC
41
+ base_obj = OdxCategory.category_from_et(et_element, doc_frags, doc_type=doc_type)
42
+ doc_frags = base_obj.odx_id.doc_fragments
43
+ kwargs = dataclass_fields_asdict(base_obj)
41
44
 
42
- data_object_props = NamedItemList([
43
- DataObjectProperty.from_et(el, doc_frags)
44
- for el in et_element.iterfind("DATA-OBJECT-PROPS/DATA-OBJECT-PROP")
45
- ])
46
45
  comparams = NamedItemList(
47
46
  [Comparam.from_et(el, doc_frags) for el in et_element.iterfind("COMPARAMS/COMPARAM")])
48
47
  complex_comparams = NamedItemList([
49
48
  ComplexComparam.from_et(el, doc_frags)
50
49
  for el in et_element.iterfind("COMPLEX-COMPARAMS/COMPLEX-COMPARAM")
51
50
  ])
51
+ data_object_props = NamedItemList([
52
+ DataObjectProperty.from_et(el, doc_frags)
53
+ for el in et_element.iterfind("DATA-OBJECT-PROPS/DATA-OBJECT-PROP")
54
+ ])
55
+ unit_spec = None
52
56
  if (unit_spec_elem := et_element.find("UNIT-SPEC")) is not None:
53
57
  unit_spec = UnitSpec.from_et(unit_spec_elem, doc_frags)
54
- else:
55
- unit_spec = None
56
58
 
57
59
  return ComparamSubset(
58
- category=category,
59
- data_object_props=data_object_props,
60
+ category=category_attrib,
60
61
  comparams=comparams,
61
62
  complex_comparams=complex_comparams,
63
+ data_object_props=data_object_props,
62
64
  unit_spec=unit_spec,
63
65
  **kwargs)
64
66
 
65
67
  def _build_odxlinks(self) -> Dict[OdxLinkId, Any]:
66
68
  odxlinks = super()._build_odxlinks()
67
69
 
68
- for dop in self.data_object_props:
69
- odxlinks[dop.odx_id] = dop
70
-
71
70
  for comparam in self.comparams:
72
71
  odxlinks.update(comparam._build_odxlinks())
73
72
 
74
73
  for ccomparam in self.complex_comparams:
75
74
  odxlinks.update(ccomparam._build_odxlinks())
76
75
 
76
+ for dop in self.data_object_props:
77
+ odxlinks[dop.odx_id] = dop
78
+
77
79
  if self.unit_spec:
78
80
  odxlinks.update(self.unit_spec._build_odxlinks())
79
81
 
@@ -82,15 +84,15 @@ class ComparamSubset(OdxCategory):
82
84
  def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
83
85
  super()._resolve_odxlinks(odxlinks)
84
86
 
85
- for dop in self.data_object_props:
86
- dop._resolve_odxlinks(odxlinks)
87
-
88
87
  for comparam in self.comparams:
89
88
  comparam._resolve_odxlinks(odxlinks)
90
89
 
91
90
  for ccomparam in self.complex_comparams:
92
91
  ccomparam._resolve_odxlinks(odxlinks)
93
92
 
93
+ for dop in self.data_object_props:
94
+ dop._resolve_odxlinks(odxlinks)
95
+
94
96
  if self.unit_spec:
95
97
  self.unit_spec._resolve_odxlinks(odxlinks)
96
98
 
@@ -100,14 +102,14 @@ class ComparamSubset(OdxCategory):
100
102
  def _resolve_snrefs(self, context: SnRefContext) -> None:
101
103
  super()._resolve_snrefs(context)
102
104
 
103
- for dop in self.data_object_props:
104
- dop._resolve_snrefs(context)
105
-
106
105
  for comparam in self.comparams:
107
106
  comparam._resolve_snrefs(context)
108
107
 
109
108
  for ccomparam in self.complex_comparams:
110
109
  ccomparam._resolve_snrefs(context)
111
110
 
111
+ for dop in self.data_object_props:
112
+ dop._resolve_snrefs(context)
113
+
112
114
  if self.unit_spec:
113
115
  self.unit_spec._resolve_snrefs(context)
@@ -13,6 +13,10 @@ class CompuConst:
13
13
 
14
14
  data_type: DataType
15
15
 
16
+ @property
17
+ def value(self) -> Optional[AtomicOdxType]:
18
+ return self._value
19
+
16
20
  @staticmethod
17
21
  def compuvalue_from_et(et_element: ElementTree.Element, *, data_type: DataType) -> "CompuConst":
18
22
 
@@ -25,7 +29,3 @@ class CompuConst:
25
29
  self._value: Optional[AtomicOdxType] = self.vt
26
30
  if self.v is not None:
27
31
  self._value = self.data_type.from_string(self.v)
28
-
29
- @property
30
- def value(self) -> Optional[AtomicOdxType]:
31
- return self._value
@@ -21,11 +21,9 @@ class Limit:
21
21
  value_type: Optional[DataType]
22
22
  interval_type: Optional[IntervalType]
23
23
 
24
- def __post_init__(self) -> None:
25
- self._value: Optional[AtomicOdxType] = None
26
-
27
- if self.value_type is not None:
28
- self.set_value_type(self.value_type)
24
+ @property
25
+ def value(self) -> Optional[AtomicOdxType]:
26
+ return self._value
29
27
 
30
28
  @staticmethod
31
29
  @overload
@@ -57,15 +55,17 @@ class Limit:
57
55
 
58
56
  return Limit(value_raw=value_raw, interval_type=interval_type, value_type=value_type)
59
57
 
58
+ def __post_init__(self) -> None:
59
+ self._value: Optional[AtomicOdxType] = None
60
+
61
+ if self.value_type is not None:
62
+ self.set_value_type(self.value_type)
63
+
60
64
  def set_value_type(self, value_type: DataType) -> None:
61
65
  self.value_type = value_type
62
66
  if self.value_raw is not None:
63
67
  self._value = value_type.from_string(self.value_raw)
64
68
 
65
- @property
66
- def value(self) -> Optional[AtomicOdxType]:
67
- return self._value
68
-
69
69
  def complies_to_upper(self, value: AtomicOdxType) -> bool:
70
70
  """Checks if the value is in the range w.r.t. the upper limit.
71
71
 
@@ -32,6 +32,14 @@ class LinearSegment:
32
32
  internal_type: DataType
33
33
  physical_type: DataType
34
34
 
35
+ @property
36
+ def physical_lower_limit(self) -> Optional[Limit]:
37
+ return self._physical_lower_limit
38
+
39
+ @property
40
+ def physical_upper_limit(self) -> Optional[Limit]:
41
+ return self._physical_upper_limit
42
+
35
43
  @staticmethod
36
44
  def from_compu_scale(scale: CompuScale, *, internal_type: DataType,
37
45
  physical_type: DataType) -> "LinearSegment":
@@ -64,14 +72,6 @@ class LinearSegment:
64
72
  internal_type=internal_type,
65
73
  physical_type=physical_type)
66
74
 
67
- @property
68
- def physical_lower_limit(self) -> Optional[Limit]:
69
- return self._physical_lower_limit
70
-
71
- @property
72
- def physical_upper_limit(self) -> Optional[Limit]:
73
- return self._physical_upper_limit
74
-
75
75
  def __post_init__(self) -> None:
76
76
  self.__compute_physical_limits()
77
77