odxtools 10.1.0__py3-none-any.whl → 10.2.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.
- odxtools/addrdeffilter.py +33 -0
- odxtools/addrdefphyssegment.py +33 -0
- odxtools/checksum.py +67 -0
- odxtools/checksumresult.py +7 -0
- odxtools/cli/compare.py +143 -170
- odxtools/database.py +24 -4
- odxtools/datablock.py +153 -0
- odxtools/datafile.py +23 -0
- odxtools/dataformat.py +39 -0
- odxtools/dataformatselection.py +9 -0
- odxtools/description.py +2 -5
- odxtools/diagdatadictionaryspec.py +1 -3
- odxtools/direction.py +7 -0
- odxtools/ecumem.py +71 -0
- odxtools/ecumemconnector.py +136 -0
- odxtools/encryptcompressmethod.py +39 -0
- odxtools/encryptcompressmethodtype.py +13 -0
- odxtools/expectedident.py +40 -0
- odxtools/externflashdata.py +34 -0
- odxtools/filter.py +32 -0
- odxtools/flash.py +88 -0
- odxtools/flashclass.py +32 -0
- odxtools/flashdata.py +70 -0
- odxtools/fwchecksum.py +7 -0
- odxtools/fwsignature.py +7 -0
- odxtools/identdesc.py +54 -0
- odxtools/identvalue.py +32 -0
- odxtools/identvaluetype.py +14 -0
- odxtools/internflashdata.py +33 -0
- odxtools/loadfile.py +1 -1
- odxtools/mem.py +80 -0
- odxtools/modification.py +3 -2
- odxtools/negoffset.py +21 -0
- odxtools/ownident.py +38 -0
- odxtools/physicaltype.py +12 -10
- odxtools/physmem.py +52 -0
- odxtools/physsegment.py +42 -0
- odxtools/posoffset.py +21 -0
- odxtools/security.py +42 -0
- odxtools/securitymethod.py +7 -0
- odxtools/segment.py +63 -0
- odxtools/session.py +88 -0
- odxtools/sessiondesc.py +101 -0
- odxtools/sessionsubelemtype.py +14 -0
- odxtools/sizedeffilter.py +33 -0
- odxtools/sizedefphyssegment.py +33 -0
- odxtools/specialdata.py +2 -1
- odxtools/targetaddroffset.py +13 -0
- odxtools/templates/comparam-spec.odx-c.xml.jinja2 +1 -0
- odxtools/templates/comparam-subset.odx-cs.xml.jinja2 +1 -0
- odxtools/templates/diag_layer_container.odx-d.xml.jinja2 +2 -1
- odxtools/templates/flash.odx-f.xml.jinja2 +42 -0
- odxtools/templates/macros/printAdminData.xml.jinja2 +4 -4
- odxtools/templates/macros/printAudience.xml.jinja2 +3 -3
- odxtools/templates/macros/printChecksum.xml.jinja2 +36 -0
- odxtools/templates/macros/printComparam.xml.jinja2 +1 -1
- odxtools/templates/macros/printComparamRef.xml.jinja2 +1 -3
- odxtools/templates/macros/printCompuMethod.xml.jinja2 +1 -1
- odxtools/templates/macros/printDOP.xml.jinja2 +3 -3
- odxtools/templates/macros/printDatablock.xml.jinja2 +78 -0
- odxtools/templates/macros/printDiagComm.xml.jinja2 +2 -2
- odxtools/templates/macros/printDiagLayer.xml.jinja2 +2 -1
- odxtools/templates/macros/printDiagVariable.xml.jinja2 +4 -4
- odxtools/templates/macros/printDynDefinedSpec.xml.jinja2 +3 -3
- odxtools/templates/macros/printDynamicEndmarkerField.xml.jinja2 +2 -2
- odxtools/templates/macros/printDynamicLengthField.xml.jinja2 +2 -2
- odxtools/templates/macros/printEcuMem.xml.jinja2 +24 -0
- odxtools/templates/macros/printEcuMemConnector.xml.jinja2 +58 -0
- odxtools/templates/macros/printEndOfPdu.xml.jinja2 +1 -1
- odxtools/templates/macros/printEnvDataDesc.xml.jinja2 +1 -1
- odxtools/templates/macros/printExpectedIdent.xml.jinja2 +21 -0
- odxtools/templates/macros/printFlashdata.xml.jinja2 +43 -0
- odxtools/templates/macros/printIdentDesc.xml.jinja2 +17 -0
- odxtools/templates/macros/printMem.xml.jinja2 +35 -0
- odxtools/templates/macros/printMux.xml.jinja2 +3 -3
- odxtools/templates/macros/printOdxCategory.xml.jinja2 +4 -4
- odxtools/templates/macros/printOwnIdent.xml.jinja2 +17 -0
- odxtools/templates/macros/printParam.xml.jinja2 +4 -4
- odxtools/templates/macros/printParentRef.xml.jinja2 +1 -5
- odxtools/templates/macros/printPhysMem.xml.jinja2 +20 -0
- odxtools/templates/macros/printPhysSegment.xml.jinja2 +33 -0
- odxtools/templates/macros/printPreConditionStateRef.xml.jinja2 +1 -1
- odxtools/templates/macros/printProtStack.xml.jinja2 +1 -1
- odxtools/templates/macros/printProtocol.xml.jinja2 +1 -1
- odxtools/templates/macros/printSecurity.xml.jinja2 +37 -0
- odxtools/templates/macros/printSegment.xml.jinja2 +31 -0
- odxtools/templates/macros/printService.xml.jinja2 +3 -3
- odxtools/templates/macros/printSession.xml.jinja2 +45 -0
- odxtools/templates/macros/printSessionDesc.xml.jinja2 +40 -0
- odxtools/templates/macros/printSingleEcuJob.xml.jinja2 +3 -3
- odxtools/templates/macros/printSpecialData.xml.jinja2 +2 -2
- odxtools/templates/macros/printStateTransitionRef.xml.jinja2 +1 -1
- odxtools/templates/macros/printStaticField.xml.jinja2 +1 -1
- odxtools/templates/macros/printSubComponent.xml.jinja2 +3 -3
- odxtools/templates/macros/printTable.xml.jinja2 +6 -6
- odxtools/templates/macros/printUnitSpec.xml.jinja2 +2 -2
- odxtools/text.py +2 -6
- odxtools/utils.py +22 -1
- odxtools/validityfor.py +30 -0
- odxtools/version.py +2 -2
- odxtools/writepdxfile.py +70 -21
- {odxtools-10.1.0.dist-info → odxtools-10.2.0.dist-info}/METADATA +1 -1
- {odxtools-10.1.0.dist-info → odxtools-10.2.0.dist-info}/RECORD +107 -50
- {odxtools-10.1.0.dist-info → odxtools-10.2.0.dist-info}/WHEEL +1 -1
- {odxtools-10.1.0.dist-info → odxtools-10.2.0.dist-info}/entry_points.txt +0 -0
- {odxtools-10.1.0.dist-info → odxtools-10.2.0.dist-info}/licenses/LICENSE +0 -0
- {odxtools-10.1.0.dist-info → odxtools-10.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .exceptions import odxrequire
|
7
|
+
from .filter import Filter
|
8
|
+
from .odxdoccontext import OdxDocContext
|
9
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId
|
10
|
+
from .snrefcontext import SnRefContext
|
11
|
+
from .utils import dataclass_fields_asdict, read_hex_binary
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass(kw_only=True)
|
15
|
+
class AddrdefFilter(Filter):
|
16
|
+
filter_end: int
|
17
|
+
|
18
|
+
@staticmethod
|
19
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "AddrdefFilter":
|
20
|
+
kwargs = dataclass_fields_asdict(Filter.from_et(et_element, context))
|
21
|
+
|
22
|
+
filter_end = odxrequire(read_hex_binary(et_element.find("FILTER-END")))
|
23
|
+
|
24
|
+
return AddrdefFilter(filter_end=filter_end, **kwargs)
|
25
|
+
|
26
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
27
|
+
return super()._build_odxlinks()
|
28
|
+
|
29
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
30
|
+
super()._resolve_odxlinks(odxlinks)
|
31
|
+
|
32
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
33
|
+
super()._resolve_snrefs(context)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .exceptions import odxrequire
|
7
|
+
from .odxdoccontext import OdxDocContext
|
8
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId
|
9
|
+
from .physsegment import PhysSegment
|
10
|
+
from .snrefcontext import SnRefContext
|
11
|
+
from .utils import dataclass_fields_asdict, read_hex_binary
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass(kw_only=True)
|
15
|
+
class AddrdefPhysSegment(PhysSegment):
|
16
|
+
end_address: int
|
17
|
+
|
18
|
+
@staticmethod
|
19
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "AddrdefPhysSegment":
|
20
|
+
kwargs = dataclass_fields_asdict(PhysSegment.from_et(et_element, context))
|
21
|
+
|
22
|
+
end_address = odxrequire(read_hex_binary(et_element.find("END-ADDRESS")))
|
23
|
+
|
24
|
+
return AddrdefPhysSegment(end_address=end_address, **kwargs)
|
25
|
+
|
26
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
27
|
+
return super()._build_odxlinks()
|
28
|
+
|
29
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
30
|
+
super()._resolve_odxlinks(odxlinks)
|
31
|
+
|
32
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
33
|
+
super()._resolve_snrefs(context)
|
odxtools/checksum.py
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Any
|
4
|
+
from xml.etree import ElementTree
|
5
|
+
|
6
|
+
from .checksumresult import ChecksumResult
|
7
|
+
from .element import IdentifiableElement
|
8
|
+
from .exceptions import odxrequire
|
9
|
+
from .odxdoccontext import OdxDocContext
|
10
|
+
from .odxlink import OdxLinkDatabase, OdxLinkId
|
11
|
+
from .snrefcontext import SnRefContext
|
12
|
+
from .utils import dataclass_fields_asdict, read_hex_binary
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass(kw_only=True)
|
16
|
+
class Checksum(IdentifiableElement):
|
17
|
+
fillbyte: int | None = None
|
18
|
+
source_start_address: int
|
19
|
+
compressed_size: int | None = None
|
20
|
+
checksum_alg: str | None = None
|
21
|
+
|
22
|
+
# exactly one of the two next fields must be not None
|
23
|
+
source_end_address: int | None = None
|
24
|
+
uncompressed_size: int | None = None
|
25
|
+
|
26
|
+
checksum_result: ChecksumResult
|
27
|
+
|
28
|
+
@staticmethod
|
29
|
+
def from_et(et_element: ElementTree.Element, context: OdxDocContext) -> "Checksum":
|
30
|
+
|
31
|
+
kwargs = dataclass_fields_asdict(IdentifiableElement.from_et(et_element, context))
|
32
|
+
|
33
|
+
fillbyte = read_hex_binary(et_element.find("FILLBYTE"))
|
34
|
+
source_start_address = odxrequire(read_hex_binary(et_element.find("SOURCE-START-ADDRESS")))
|
35
|
+
compressed_size = None
|
36
|
+
if (cs_elem := et_element.find("COMPRESSED-SIZE")) is not None:
|
37
|
+
compressed_size = int(odxrequire(cs_elem.text) or "0")
|
38
|
+
checksum_alg = et_element.findtext("CHECKSUM-ALG")
|
39
|
+
|
40
|
+
# exactly one of the two next fields must be not None
|
41
|
+
source_end_address = read_hex_binary(et_element.find("SOURCE-END-ADDRESS"))
|
42
|
+
uncompressed_size = None
|
43
|
+
if (ucs_elem := et_element.find("UNCOMPRESSED-SIZE")) is not None:
|
44
|
+
uncompressed_size = int(odxrequire(ucs_elem.text) or "0")
|
45
|
+
checksum_result = ChecksumResult.from_et(
|
46
|
+
odxrequire(et_element.find("CHECKSUM-RESULT")), context)
|
47
|
+
|
48
|
+
return Checksum(
|
49
|
+
fillbyte=fillbyte,
|
50
|
+
source_start_address=source_start_address,
|
51
|
+
compressed_size=compressed_size,
|
52
|
+
checksum_alg=checksum_alg,
|
53
|
+
source_end_address=source_end_address,
|
54
|
+
uncompressed_size=uncompressed_size,
|
55
|
+
checksum_result=checksum_result,
|
56
|
+
**kwargs)
|
57
|
+
|
58
|
+
def _build_odxlinks(self) -> dict[OdxLinkId, Any]:
|
59
|
+
odxlinks = {self.odx_id: self}
|
60
|
+
|
61
|
+
return odxlinks
|
62
|
+
|
63
|
+
def _resolve_odxlinks(self, odxlinks: OdxLinkDatabase) -> None:
|
64
|
+
pass
|
65
|
+
|
66
|
+
def _resolve_snrefs(self, context: SnRefContext) -> None:
|
67
|
+
pass
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
2
|
+
from .validityfor import ValidityFor
|
3
|
+
|
4
|
+
# Note that the ODX specification specifies a separate tag for this,
|
5
|
+
# but this tag is identical to VALIDITY-FOR, so let's use a type alias
|
6
|
+
# to reduce the amount of copy-and-pasted code
|
7
|
+
ChecksumResult = ValidityFor
|
odxtools/cli/compare.py
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
|
4
4
|
import argparse
|
5
5
|
import os
|
6
|
-
from
|
6
|
+
from dataclasses import dataclass, field
|
7
|
+
from typing import Any
|
7
8
|
|
8
9
|
from rich import print as rich_print
|
9
10
|
from rich.padding import Padding as RichPadding
|
@@ -27,134 +28,134 @@ from ._print_utils import (extract_service_tabulation_data, print_dl_metrics,
|
|
27
28
|
# name of the tool
|
28
29
|
_odxtools_tool_name_ = "compare"
|
29
30
|
|
30
|
-
VariantName = str
|
31
|
-
VariantType = str
|
32
|
-
NewServices = list[DiagService]
|
33
|
-
DeletedServices = list[DiagService]
|
34
|
-
RenamedServices = list[list[str | DiagService]]
|
35
|
-
ServicesWithParamChanges = list[list[str | DiagService]]
|
36
31
|
|
37
|
-
|
38
|
-
|
32
|
+
@dataclass
|
33
|
+
class ChangedParameterDetails:
|
34
|
+
service: DiagService # The service whose parameters changed
|
35
|
+
changed_parameters: list[DiagService] = field(
|
36
|
+
default_factory=list) # list of changed parameter names
|
37
|
+
change_details: list[DiagService] = field(default_factory=list) # Detailed change information
|
39
38
|
|
40
|
-
NewVariants = list[DiagLayer]
|
41
|
-
DeletedVariants = list[DiagLayer]
|
42
39
|
|
43
|
-
|
40
|
+
@dataclass
|
41
|
+
class ServiceDiff:
|
42
|
+
diag_layer: str
|
43
|
+
diag_layer_type: str
|
44
|
+
new_services: list[DiagService] = field(default_factory=list)
|
45
|
+
deleted_services: list[DiagService] = field(default_factory=list)
|
46
|
+
changed_name_of_service: list[list[str | DiagService]] = field(default_factory=list)
|
47
|
+
changed_parameters_of_service: list[ChangedParameterDetails] = field(default_factory=list)
|
48
|
+
|
49
|
+
|
50
|
+
@dataclass
|
51
|
+
class SpecsChangesVariants:
|
52
|
+
new_diagnostic_layers: list[DiagLayer] = field(default_factory=list)
|
53
|
+
deleted_diagnostic_layers: list[DiagLayer] = field(default_factory=list)
|
54
|
+
service_changes: dict[str, list[DiagLayer] | ServiceDiff] = field(default_factory=dict)
|
44
55
|
|
45
56
|
|
46
57
|
class Display:
|
47
|
-
# class with variables and functions to display the result of the comparison
|
48
58
|
|
49
|
-
# TODO
|
50
|
-
# - Idea: results as json export
|
51
|
-
# - write results of comparison in json structure
|
52
|
-
# - use odxlinks to refer to dignostic services / objects if
|
53
|
-
# changes have already been detected (e.g. in another ecu
|
54
|
-
# variant / diagnostic layer)
|
55
|
-
# - print all information about parameter properties (request,
|
56
|
-
# pos. response & neg. response parameters) for changed diagnostic
|
57
|
-
# services
|
58
59
|
param_detailed: bool
|
59
60
|
obj_detailed: bool
|
60
61
|
|
61
62
|
def __init__(self) -> None:
|
62
63
|
pass
|
63
64
|
|
64
|
-
def print_dl_changes(self,
|
65
|
-
|
66
|
-
|
67
|
-
"changed_name_of_service"][0] or service_dict["changed_parameters_of_service"][0]:
|
68
|
-
assert isinstance(service_dict["diag_layer"], str)
|
65
|
+
def print_dl_changes(self, service_spec: ServiceDiff) -> None:
|
66
|
+
if service_spec.new_services or service_spec.deleted_services or service_spec.changed_name_of_service or service_spec.changed_parameters_of_service:
|
67
|
+
assert isinstance(service_spec.diag_layer, str)
|
69
68
|
rich_print()
|
70
69
|
rich_print(
|
71
|
-
f"Changed diagnostic services for diagnostic layer '{
|
70
|
+
f"Changed diagnostic services for diagnostic layer '{service_spec.diag_layer}' ({service_spec.diag_layer_type}):"
|
72
71
|
)
|
73
|
-
if
|
74
|
-
assert isinstance(
|
72
|
+
if service_spec.new_services:
|
73
|
+
assert isinstance(service_spec.new_services, list)
|
75
74
|
rich_print()
|
76
75
|
rich_print(" [blue]New services[/blue]")
|
77
|
-
rich_print(extract_service_tabulation_data(
|
78
|
-
|
79
|
-
|
80
|
-
assert isinstance(service_dict["deleted_services"], list)
|
76
|
+
rich_print(extract_service_tabulation_data(service_spec.new_services))
|
77
|
+
if service_spec.deleted_services:
|
78
|
+
assert isinstance(service_spec.deleted_services, list)
|
81
79
|
rich_print()
|
82
80
|
rich_print(" [blue]Deleted services[/blue]")
|
83
|
-
rich_print(extract_service_tabulation_data(
|
84
|
-
|
85
|
-
if service_dict["changed_name_of_service"][0]:
|
81
|
+
rich_print(extract_service_tabulation_data(service_spec.deleted_services))
|
82
|
+
if service_spec.changed_name_of_service[0]:
|
86
83
|
rich_print()
|
87
84
|
rich_print(" [blue]Renamed services[/blue]")
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
]
|
98
|
-
table = extract_service_tabulation_data(
|
99
|
-
service_dict["changed_parameters_of_service"][0], # type: ignore[arg-type]
|
100
|
-
additional_columns=[("Changed Parameters", changed_param_column)])
|
101
|
-
rich_print(table)
|
102
|
-
|
103
|
-
for service_idx, service in enumerate(
|
104
|
-
service_dict["changed_parameters_of_service"][0]): # type: ignore[arg-type]
|
105
|
-
assert isinstance(service, DiagService)
|
85
|
+
tmp: list[DiagService] = []
|
86
|
+
for sublist in service_spec.changed_name_of_service:
|
87
|
+
for item in sublist:
|
88
|
+
if isinstance(item, DiagService):
|
89
|
+
tmp.append(item)
|
90
|
+
rich_print(extract_service_tabulation_data(tmp))
|
91
|
+
if service_spec.changed_parameters_of_service:
|
92
|
+
first_change_details = service_spec.changed_parameters_of_service[0]
|
93
|
+
if first_change_details:
|
106
94
|
rich_print()
|
107
|
-
rich_print(
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
95
|
+
rich_print(" [blue]Services with parameter changes[/blue]")
|
96
|
+
changed_param_column = [
|
97
|
+
str(param_details.changed_parameters)
|
98
|
+
for param_details in service_spec.changed_parameters_of_service
|
99
|
+
]
|
100
|
+
services = [
|
101
|
+
param_detail.service
|
102
|
+
for param_detail in service_spec.changed_parameters_of_service
|
103
|
+
]
|
104
|
+
table = extract_service_tabulation_data(
|
105
|
+
services, additional_columns=[("Changed Parameters", changed_param_column)])
|
106
|
+
rich_print(table)
|
107
|
+
for service_idx, param_detail in enumerate(
|
108
|
+
service_spec.changed_parameters_of_service):
|
109
|
+
service = param_detail.service
|
110
|
+
|
111
|
+
assert isinstance(service, DiagService)
|
112
|
+
rich_print()
|
113
|
+
rich_print(
|
114
|
+
f" Detailed changes of diagnostic service [u cyan]{service.short_name}[/u cyan]"
|
115
|
+
)
|
116
|
+
|
117
|
+
info_list = service_spec.changed_parameters_of_service[
|
118
|
+
service_idx].change_details
|
119
|
+
for detailed_info in info_list:
|
120
|
+
if isinstance(detailed_info, str):
|
121
|
+
rich_print()
|
122
|
+
rich_print(detailed_info)
|
123
|
+
elif isinstance(detailed_info, dict):
|
124
|
+
table = RichTable(
|
125
|
+
show_header=True,
|
126
|
+
header_style="bold cyan",
|
127
|
+
border_style="blue",
|
128
|
+
show_lines=True)
|
129
|
+
for header in detailed_info:
|
130
|
+
table.add_column(header)
|
131
|
+
rows = zip(*detailed_info.values(), strict=True)
|
132
|
+
for row in rows:
|
133
|
+
table.add_row(*map(str, row))
|
134
|
+
|
135
|
+
rich_print(RichPadding(table, pad=(0, 0, 0, 4)))
|
136
|
+
rich_print()
|
137
|
+
if self.param_detailed:
|
138
|
+
print_service_parameters(service, allow_unknown_bit_lengths=True)
|
135
139
|
|
136
140
|
def print_database_changes(self, changes_variants: SpecsChangesVariants) -> None:
|
137
|
-
# prints result of database comparison (input variable: dictionary: changes_variants)
|
138
141
|
|
139
|
-
|
140
|
-
if changes_variants["new_diagnostic_layers"] or changes_variants[
|
141
|
-
"deleted_diagnostic_layers"]:
|
142
|
+
if changes_variants.new_diagnostic_layers or changes_variants.deleted_diagnostic_layers:
|
142
143
|
rich_print()
|
143
144
|
rich_print("[bright_blue]Changed diagnostic layers[/bright_blue]: ")
|
144
145
|
rich_print(" New diagnostic layers: ")
|
145
|
-
for variant in changes_variants
|
146
|
+
for variant in changes_variants.new_diagnostic_layers:
|
146
147
|
assert isinstance(variant, DiagLayer)
|
147
148
|
rich_print(
|
148
149
|
f" [magenta]{variant.short_name}[/magenta] ({variant.variant_type.value})")
|
149
150
|
rich_print(" Deleted diagnostic layers: ")
|
150
|
-
for variant in changes_variants
|
151
|
+
for variant in changes_variants.deleted_diagnostic_layers:
|
151
152
|
assert isinstance(variant, DiagLayer)
|
152
153
|
rich_print(
|
153
154
|
f" [magenta]{variant.short_name}[/magenta] ({variant.variant_type.value})")
|
154
155
|
|
155
156
|
# diagnostic services
|
156
|
-
for _, value in changes_variants.items():
|
157
|
-
if isinstance(value,
|
157
|
+
for _, value in changes_variants.service_changes.items():
|
158
|
+
if isinstance(value, ServiceDiff):
|
158
159
|
self.print_dl_changes(value)
|
159
160
|
|
160
161
|
|
@@ -276,8 +277,7 @@ class Comparison(Display):
|
|
276
277
|
|
277
278
|
return {"Property": property, "Old Value": old, "New Value": new}
|
278
279
|
|
279
|
-
def compare_services(self, service1: DiagService,
|
280
|
-
service2: DiagService) -> list[SpecsServiceDict]:
|
280
|
+
def compare_services(self, service1: DiagService, service2: DiagService) -> list[DiagService]:
|
281
281
|
# compares request, positive response and negative response parameters of two diagnostic services
|
282
282
|
|
283
283
|
information: list[str | dict[str, Any]] = [
|
@@ -405,39 +405,26 @@ class Comparison(Display):
|
|
405
405
|
|
406
406
|
return [information, changed_params] # type: ignore[list-item]
|
407
407
|
|
408
|
-
def compare_diagnostic_layers(self, dl1: DiagLayer,
|
409
|
-
dl2: DiagLayer) -> dict: # type: ignore[type-arg]
|
408
|
+
def compare_diagnostic_layers(self, dl1: DiagLayer, dl2: DiagLayer) -> ServiceDiff:
|
410
409
|
# compares diagnostic services of two diagnostic layers with each other
|
411
410
|
# save changes in dictionary (service_dict)
|
412
411
|
# TODO: add comparison of SingleECUJobs
|
413
412
|
|
414
|
-
new_services:
|
415
|
-
deleted_services:
|
416
|
-
renamed_service:
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
# list with deleted diagnostic services [service1, service2, service3, ...] Type: DiagService
|
428
|
-
"deleted_services": deleted_services,
|
429
|
-
# list with diagnostic services where the service name changed [[services], [old service names]]
|
430
|
-
"changed_name_of_service": renamed_service,
|
431
|
-
# list with diagnostic services where the service parameter changed [[services], [changed_parameters], [information_texts]]
|
432
|
-
"changed_parameters_of_service": services_with_param_changes
|
433
|
-
}
|
434
|
-
# service_dict["changed_name_of_service"][{0 = services, 1 = old service names}][i]
|
435
|
-
# service_dict["changed_parameters_of_service"][{0 = services, 1 = changed_parameters, 2 = information_texts}][i]
|
436
|
-
|
413
|
+
new_services: list[DiagService] = []
|
414
|
+
deleted_services: list[DiagService] = []
|
415
|
+
renamed_service: list[list[str | DiagService]] = [[], []] # list of (old_name, new_name)
|
416
|
+
services_with_param_changes: list[ChangedParameterDetails] = [
|
417
|
+
] # Parameter changes # TODO: implement list of tuples (str, str, DiagService)-tuples
|
418
|
+
|
419
|
+
service_spec = ServiceDiff(
|
420
|
+
diag_layer=dl1.short_name,
|
421
|
+
diag_layer_type=dl1.variant_type.value,
|
422
|
+
new_services=new_services,
|
423
|
+
deleted_services=deleted_services,
|
424
|
+
changed_name_of_service=renamed_service,
|
425
|
+
changed_parameters_of_service=services_with_param_changes)
|
437
426
|
dl1_service_names = [service.short_name for service in dl1.services]
|
438
427
|
|
439
|
-
# extract the constant prefixes for the requests of all
|
440
|
-
# services (used for duck-typed rename detection)
|
441
428
|
dl1_request_prefixes: list[bytes | None] = [
|
442
429
|
None if s.request is None else s.request.coded_const_prefix() for s in dl1.services
|
443
430
|
]
|
@@ -449,7 +436,7 @@ class Comparison(Display):
|
|
449
436
|
for service1 in dl1.services:
|
450
437
|
|
451
438
|
# check for added diagnostic services
|
452
|
-
rq_prefix: bytes
|
439
|
+
rq_prefix: bytes
|
453
440
|
if service1.request is not None:
|
454
441
|
rq_prefix = service1.request.coded_const_prefix()
|
455
442
|
|
@@ -457,11 +444,11 @@ class Comparison(Display):
|
|
457
444
|
if rq_prefix is None or rq_prefix not in dl2_request_prefixes:
|
458
445
|
# TODO: this will not work in cases where the constant
|
459
446
|
# prefix of a request was modified...
|
460
|
-
service_dict["new_services"].append( # type: ignore[union-attr]
|
461
|
-
service1) # type: ignore[arg-type]
|
462
447
|
|
448
|
+
service_spec.new_services.append(service1)
|
463
449
|
# check whether names of diagnostic services have changed
|
464
450
|
elif service1 not in dl2.services:
|
451
|
+
|
465
452
|
if rq_prefix is None or rq_prefix in dl2_request_prefixes:
|
466
453
|
# get related diagnostic service for request
|
467
454
|
service2_idx = dl2_request_prefixes.index(rq_prefix)
|
@@ -470,30 +457,23 @@ class Comparison(Display):
|
|
470
457
|
# save information about changes in dictionary
|
471
458
|
|
472
459
|
# add new service (type: DiagService)
|
473
|
-
|
474
|
-
|
460
|
+
|
461
|
+
service_spec.changed_name_of_service[0].append(service1)
|
475
462
|
# add old service name (type: String)
|
476
|
-
|
477
|
-
service2.short_name)
|
463
|
+
service_spec.changed_name_of_service[1].append(service2.short_name)
|
478
464
|
|
479
465
|
# compare request, pos. response and neg. response parameters of diagnostic services
|
480
466
|
detailed_information = self.compare_services(service1, service2)
|
481
|
-
# detailed_information = [[infotext1, table1, infotext2, table2, ...], changed_params]
|
482
467
|
|
483
468
|
# add information about changed diagnostic service parameters to dicitionary
|
484
469
|
if detailed_information[1]: # check whether string "changed_params" is empty
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
detailed_information[1]) # type: ignore[arg-type]
|
493
|
-
# add detailed information about changed service parameters (type: list) [infotext1, table1, infotext2, table2, ...]
|
494
|
-
service_dict["changed_parameters_of_service"][
|
495
|
-
2].append( # type: ignore[union-attr]
|
496
|
-
detailed_information[0]) # type: ignore[arg-type]
|
470
|
+
param_change_details = ChangedParameterDetails(
|
471
|
+
service=service1,
|
472
|
+
changed_parameters=[detailed_information[1]],
|
473
|
+
change_details=[detailed_information[0]],
|
474
|
+
)
|
475
|
+
|
476
|
+
service_spec.changed_parameters_of_service.append(param_change_details)
|
497
477
|
|
498
478
|
for service2_idx, service2 in enumerate(dl2.services):
|
499
479
|
|
@@ -501,65 +481,58 @@ class Comparison(Display):
|
|
501
481
|
if service2.short_name not in dl1_service_names and dl2_request_prefixes[
|
502
482
|
service2_idx] not in dl1_request_prefixes:
|
503
483
|
|
504
|
-
deleted_list =
|
484
|
+
deleted_list = service_spec.deleted_services
|
505
485
|
assert isinstance(deleted_list, list)
|
506
486
|
if service2 not in deleted_list:
|
507
|
-
|
508
|
-
service2) # type: ignore[arg-type]
|
487
|
+
service_spec.deleted_services.append(service2)
|
509
488
|
|
510
489
|
if service1.short_name == service2.short_name:
|
511
490
|
# compare request, pos. response and neg. response parameters of both diagnostic services
|
512
491
|
detailed_information = self.compare_services(service1, service2)
|
513
|
-
# detailed_information = [[infotext1, table1, infotext2, table2, ...], changed_params]
|
514
492
|
|
515
493
|
# add information about changed diagnostic service parameters to dicitionary
|
516
494
|
if detailed_information[1]: # check whether string "changed_params" is empty
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
service_dict["changed_parameters_of_service"][ # type: ignore[union-attr]
|
526
|
-
2].append(detailed_information[0]) # type: ignore[arg-type]
|
527
|
-
return service_dict
|
495
|
+
param_change_details = ChangedParameterDetails(
|
496
|
+
service=service1,
|
497
|
+
changed_parameters=[detailed_information[1]],
|
498
|
+
change_details=[detailed_information[0]],
|
499
|
+
)
|
500
|
+
service_spec.changed_parameters_of_service.append(param_change_details)
|
501
|
+
|
502
|
+
return service_spec
|
528
503
|
|
529
504
|
def compare_databases(self, database_new: Database,
|
530
|
-
database_old: Database) ->
|
505
|
+
database_old: Database) -> SpecsChangesVariants:
|
531
506
|
# compares two PDX-files with each other
|
532
507
|
|
533
|
-
new_variants:
|
534
|
-
deleted_variants:
|
508
|
+
new_variants: list[DiagLayer] = [] # Assuming it stores diagnostic layer names
|
509
|
+
deleted_variants: list[DiagLayer] = []
|
535
510
|
|
536
|
-
changes_variants
|
537
|
-
|
538
|
-
|
539
|
-
|
511
|
+
changes_variants = SpecsChangesVariants(
|
512
|
+
new_diagnostic_layers=new_variants,
|
513
|
+
deleted_diagnostic_layers=deleted_variants,
|
514
|
+
service_changes={})
|
540
515
|
|
541
516
|
# compare databases
|
542
517
|
for _, dl1 in enumerate(database_new.diag_layers):
|
543
518
|
# check for new diagnostic layers
|
544
519
|
if dl1.short_name not in [dl.short_name for dl in database_old.diag_layers]:
|
545
|
-
changes_variants
|
520
|
+
changes_variants.new_diagnostic_layers.append(dl1)
|
546
521
|
|
547
522
|
for _, dl2 in enumerate(database_old.diag_layers):
|
548
523
|
# check for deleted diagnostic layers
|
549
524
|
if (dl2.short_name not in [dl.short_name for dl in database_new.diag_layers] and
|
550
|
-
dl2 not in changes_variants
|
525
|
+
dl2 not in changes_variants.deleted_diagnostic_layers):
|
551
526
|
|
552
|
-
changes_variants
|
553
|
-
"deleted_diagnostic_layers"].append( # type: ignore[union-attr]
|
554
|
-
dl2)
|
527
|
+
changes_variants.deleted_diagnostic_layers.append(dl2)
|
555
528
|
|
556
529
|
if dl1.short_name == dl2.short_name and dl1.short_name in self.diagnostic_layer_names:
|
557
530
|
# compare diagnostic services of both diagnostic layers
|
558
531
|
# save diagnostic service changes in dictionary (empty if no changes)
|
559
|
-
|
560
|
-
if
|
532
|
+
service_spec: ServiceDiff = self.compare_diagnostic_layers(dl1, dl2)
|
533
|
+
if changes_variants.service_changes is not None:
|
561
534
|
# adds information about diagnostic service changes to return variable (changes_variants)
|
562
|
-
changes_variants.update({dl1.short_name:
|
535
|
+
changes_variants.service_changes.update({dl1.short_name: service_spec})
|
563
536
|
|
564
537
|
return changes_variants
|
565
538
|
|