MTPPy2.0 0.1.5__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.
- examples/__init__.py +0 -0
- examples/minimal+pid.py +82 -0
- examples/minimal.py +32 -0
- examples/minimal_recipe.py +117 -0
- examples/pea_alarm_base.py +47 -0
- examples/pea_minimal.py +258 -0
- mtppy/__init__.py +1 -0
- mtppy/part1/__init__.py +4 -0
- mtppy/part1/empty_folder_test.py +7 -0
- mtppy/part3/__init__.py +4 -0
- mtppy/part3/data_assembly_set/__init__.py +4 -0
- mtppy/part3/data_assembly_set/active_elements/__init__.py +4 -0
- mtppy/part3/data_assembly_set/active_elements/active_element.py +22 -0
- mtppy/part3/data_assembly_set/active_elements/drives/__init__.py +4 -0
- mtppy/part3/data_assembly_set/active_elements/drives/ana_drv.py +446 -0
- mtppy/part3/data_assembly_set/active_elements/drives/ana_drv_test.py +567 -0
- mtppy/part3/data_assembly_set/active_elements/drives/bin_drv.py +365 -0
- mtppy/part3/data_assembly_set/active_elements/drives/bin_drv_test.py +503 -0
- mtppy/part3/data_assembly_set/active_elements/drives/mon_ana_drv.py +469 -0
- mtppy/part3/data_assembly_set/active_elements/drives/mon_ana_drv_test.py +418 -0
- mtppy/part3/data_assembly_set/active_elements/drives/mon_bin_drv.py +295 -0
- mtppy/part3/data_assembly_set/active_elements/drives/mon_bin_drv_test.py +265 -0
- mtppy/part3/data_assembly_set/active_elements/pid/__init__.py +4 -0
- mtppy/part3/data_assembly_set/active_elements/pid/pid_ctrl.py +333 -0
- mtppy/part3/data_assembly_set/active_elements/pid/pid_ctrl_test.py +156 -0
- mtppy/part3/data_assembly_set/active_elements/valves/__init__.py +4 -0
- mtppy/part3/data_assembly_set/active_elements/valves/ana_vlv.py +402 -0
- mtppy/part3/data_assembly_set/active_elements/valves/ana_vlv_test.py +732 -0
- mtppy/part3/data_assembly_set/active_elements/valves/bin_vlv.py +279 -0
- mtppy/part3/data_assembly_set/active_elements/valves/bin_vlv_test.py +585 -0
- mtppy/part3/data_assembly_set/active_elements/valves/mon_ana_vlv.py +402 -0
- mtppy/part3/data_assembly_set/active_elements/valves/mon_ana_vlv_test.py +270 -0
- mtppy/part3/data_assembly_set/active_elements/valves/mon_bin_vlv.py +286 -0
- mtppy/part3/data_assembly_set/active_elements/valves/mon_bin_vlv_test.py +224 -0
- mtppy/part3/data_assembly_set/base_functions/__init__.py +4 -0
- mtppy/part3/data_assembly_set/base_functions/operation_mode.py +252 -0
- mtppy/part3/data_assembly_set/base_functions/operation_mode_test.py +260 -0
- mtppy/part3/data_assembly_set/base_functions/oslevel.py +35 -0
- mtppy/part3/data_assembly_set/base_functions/source_mode.py +189 -0
- mtppy/part3/data_assembly_set/base_functions/source_mode_test.py +112 -0
- mtppy/part3/data_assembly_set/base_functions/wqc.py +75 -0
- mtppy/part3/data_assembly_set/base_functions/wqc_test.py +86 -0
- mtppy/part3/data_assembly_set/data_assembly.py +65 -0
- mtppy/part3/data_assembly_set/diagnostic_elements/__init__.py +4 -0
- mtppy/part3/data_assembly_set/diagnostic_elements/diagnostic_element.py +19 -0
- mtppy/part3/data_assembly_set/indicator_elements/__init__.py +4 -0
- mtppy/part3/data_assembly_set/indicator_elements/indicator_element.py +22 -0
- mtppy/part3/data_assembly_set/indicator_elements/views/__init__.py +4 -0
- mtppy/part3/data_assembly_set/indicator_elements/views/ana_view.py +68 -0
- mtppy/part3/data_assembly_set/indicator_elements/views/bin_view.py +73 -0
- mtppy/part3/data_assembly_set/indicator_elements/views/dint_view.py +76 -0
- mtppy/part3/data_assembly_set/indicator_elements/views/string_view.py +55 -0
- mtppy/part3/data_assembly_set/operation_elements/__init__.py +4 -0
- mtppy/part3/data_assembly_set/operation_elements/operation_element.py +19 -0
- mtppy/part3/data_assembly_set/pea_elements/__init__.py +4 -0
- mtppy/part3/data_assembly_set/pea_elements/pea_element.py +28 -0
- mtppy/part3/data_assembly_set/pea_elements/pea_information_label/__init__.py +4 -0
- mtppy/part3/data_assembly_set/pea_elements/pea_information_label/pea_information_label.py +231 -0
- mtppy/part3/data_assembly_set/pea_elements/web_server_url_info/__init__.py +4 -0
- mtppy/part3/data_assembly_set/pea_elements/web_server_url_info/web_server_url_info.py +42 -0
- mtppy/part3/definitions/__init__.py +4 -0
- mtppy/part3/definitions/mtp_access.py +15 -0
- mtppy/part4/__init__.py +4 -0
- mtppy/part4/automation_services/__init__.py +4 -0
- mtppy/part4/automation_services/base_functions/__init__.py +4 -0
- mtppy/part4/automation_services/base_functions/service_operation_mode.py +368 -0
- mtppy/part4/automation_services/base_functions/service_operation_mode_test.py +242 -0
- mtppy/part4/automation_services/base_functions/service_operator_interaction.py +62 -0
- mtppy/part4/automation_services/base_functions/service_source_mode.py +138 -0
- mtppy/part4/automation_services/base_functions/service_source_mode_test.py +179 -0
- mtppy/part4/automation_services/helpers/__init__.py +4 -0
- mtppy/part4/automation_services/helpers/command_en_control.py +330 -0
- mtppy/part4/automation_services/helpers/command_en_control_test.py +302 -0
- mtppy/part4/automation_services/helpers/state_machine.py +167 -0
- mtppy/part4/automation_services/helpers/state_machine_test.py +294 -0
- mtppy/part4/automation_services/helpers/thread_control.py +39 -0
- mtppy/part4/automation_services/helpers/thread_control_test.py +80 -0
- mtppy/part4/automation_services/procedure.py +111 -0
- mtppy/part4/automation_services/procedure_test.py +185 -0
- mtppy/part4/automation_services/service.py +463 -0
- mtppy/part4/automation_services/service_elements/__init__.py +4 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/__init__.py +4 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/ana_serv_param.py +108 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/ana_serv_param_test.py +59 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/bin_serv_param.py +70 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/bin_serv_param_test.py +39 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/common_serv_param.py +111 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/dint_serv_param.py +77 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/dint_serv_param_test.py +58 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/parameter_element.py +175 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/parameter_element_test.py +246 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/string_serv_param.py +48 -0
- mtppy/part4/automation_services/service_elements/parameter_elements/string_serv_param_test.py +37 -0
- mtppy/part4/automation_services/service_elements/procedure_health_view.py +36 -0
- mtppy/part4/automation_services/service_elements/service_control.py +473 -0
- mtppy/part4/automation_services/service_elements/service_control_test.py +150 -0
- mtppy/part4/automation_services/service_elements/service_element.py +20 -0
- mtppy/part4/automation_services/service_test.py +407 -0
- mtppy/part4/definitions/__init__.py +4 -0
- mtppy/part4/definitions/command_codes.py +58 -0
- mtppy/part4/definitions/command_codes_test.py +44 -0
- mtppy/part4/definitions/state_codes.py +65 -0
- mtppy/part4/definitions/state_codes_test.py +44 -0
- mtppy/part4/process_values/__init__.py +4 -0
- mtppy/part4/process_values/base_functions/__init__.py +4 -0
- mtppy/part4/process_values/base_functions/vqc.py +48 -0
- mtppy/part4/process_values/input_elements/__init__.py +4 -0
- mtppy/part4/process_values/input_elements/ana_process_value_in.py +160 -0
- mtppy/part4/process_values/input_elements/bin_process_value_in.py +83 -0
- mtppy/part4/process_values/input_elements/dint_process_value_in.py +159 -0
- mtppy/part4/process_values/input_elements/input_element.py +40 -0
- mtppy/part4/process_values/input_elements/string_process_value_in.py +45 -0
- mtppy/part5/__init__.py +4 -0
- mtppy/part5/communication_object.py +99 -0
- mtppy/part5/communication_object_test.py +59 -0
- mtppy/part5/definitions/__init__.py +4 -0
- mtppy/part5/definitions/iec61131_data_types.py +31 -0
- mtppy/part5/definitions/iec61131_data_types_test.py +82 -0
- mtppy/part5/definitions/opcua_data_types.py +36 -0
- mtppy/part5/definitions/opcua_data_types_test.py +90 -0
- mtppy/part5/definitions/w3c_xml_data_types.py +177 -0
- mtppy/part5/definitions/w3c_xml_data_types_test.py +143 -0
- mtppy/part5/server_assembly_set/__init__.py +5 -0
- mtppy/part6/__init__.py +4 -0
- mtppy/part6/alarm_set/__init__.py +4 -0
- mtppy/part6/alarm_set/alarm.py +132 -0
- mtppy/part6/alarm_set/alarm_test.py +265 -0
- mtppy/pea/__init__.py +19 -0
- mtppy/pea/data_assembly_factory.py +124 -0
- mtppy/pea/data_assembly_factory_test.py +229 -0
- mtppy/pea/mtp_generator/__init__.py +4 -0
- mtppy/pea/mtp_generator/mtp_generator.py +1183 -0
- mtppy/pea/mtp_generator/mtp_generator_test.py +518 -0
- mtppy/pea/pea.py +139 -0
- mtppy/pea/pea_opcua_server/__init__.py +4 -0
- mtppy/pea/pea_opcua_server/marshalling.py +60 -0
- mtppy/pea/pea_opcua_server/opcua_options_provider/__init__.py +4 -0
- mtppy/pea/pea_opcua_server/opcua_options_provider/instances/basic_opcua_options_provider.py +50 -0
- mtppy/pea/pea_opcua_server/opcua_options_provider/opcua_options_provider.py +103 -0
- mtppy/pea/pea_opcua_server/pea_opcua_server.py +492 -0
- mtppy/pea/pea_opcua_server/subscription_list.py +55 -0
- mtppy/pea/pea_test.py +59 -0
- mtppy/pea/rmtp_pea.py +155 -0
- mtppy/pea/rmtp_pea_test.py +27 -0
- mtppy/pea/service_factory.py +178 -0
- mtppy/pea/service_factory_test.py +156 -0
- mtppy/pea/user_logic/__init__.py +4 -0
- mtppy/pea/user_logic/user_logic_pea.py +72 -0
- mtppy/pea/user_logic/user_logic_registry.py +106 -0
- mtppy/pea/user_logic/user_logic_registry_test.py +167 -0
- mtppy/pea/user_logic/user_logic_service.py +228 -0
- mtppy/pea/user_logic/user_logic_service_test.py +289 -0
- mtppy/utils/__init__.py +4 -0
- mtppy/utils/data_assembly_dict.py +61 -0
- mtppy/utils/data_assembly_dict_test.py +107 -0
- mtppy/utils/data_item.py +446 -0
- mtppy/utils/data_item_com_test.py +82 -0
- mtppy/utils/data_item_test.py +325 -0
- mtppy/utils/logging.py +23 -0
- mtppy/utils/logging_test.py +26 -0
- mtppy/utils/mtp_file_handling/__init__.py +4 -0
- mtppy/utils/mtp_file_handling/extract_manifest_from_mtp_file.py +22 -0
- mtppy/utils/mtp_file_handling/extract_mtp_file.py +22 -0
- mtppy/utils/mtp_file_handling/is_valid_mtp.py +22 -0
- mtppy/utils/mtp_file_handling/is_valid_path_for_manifest.py +15 -0
- mtppy/utils/mtp_file_handling/is_valid_path_to_manifest.py +17 -0
- mtppy/utils/mtp_file_handling/is_valid_path_to_mtp.py +17 -0
- mtppy/utils/mtp_file_handling/load_manifest_file.py +24 -0
- mtppy/utils/mtp_file_handling/mtp_reader/__init__.py +4 -0
- mtppy/utils/mtp_file_handling/mtp_reader/mtp_reader.py +103 -0
- mtppy/utils/mtp_file_handling/mtp_reader/mtp_reader_test.py +96 -0
- mtppy/utils/mtp_file_handling/mtp_reader/mtp_xml.py +226 -0
- mtppy/utils/mtp_file_handling/mtp_reader/mtp_xml_test.py +108 -0
- mtppy/utils/mtp_file_handling/mtp_writer/__init__.py +4 -0
- mtppy/utils/mtp_file_handling/mtp_writer/mtp_writer.py +77 -0
- mtppy/utils/mtp_file_handling/mtp_writer/ressources/get_content_types.py +10 -0
- mtppy/utils/mtp_file_handling/mtp_writer/ressources/get_rels.py +11 -0
- mtppy/utils/mtp_file_handling/mtp_writer/test_mtp_writer.py +25 -0
- mtppy/utils/mtp_file_handling/write_manifest_file.py +29 -0
- mtppy/utils/mtp_file_handling/write_manifest_file_test.py +22 -0
- mtppy/utils/mtp_file_handling/write_mtp_file.py +43 -0
- mtppy/utils/mtp_file_handling/write_mtp_file_test.py +22 -0
- mtppy/utils/testing.py +31 -0
- mtppy2_0-0.1.5.dist-info/METADATA +75 -0
- mtppy2_0-0.1.5.dist-info/RECORD +214 -0
- mtppy2_0-0.1.5.dist-info/WHEEL +5 -0
- mtppy2_0-0.1.5.dist-info/entry_points.txt +3 -0
- mtppy2_0-0.1.5.dist-info/licenses/LICENSE +21 -0
- mtppy2_0-0.1.5.dist-info/top_level.txt +4 -0
- tools/__init__.py +0 -0
- tools/create_bugreport.py +150 -0
- tools/inspect_mtp.py +110 -0
- utils/__init__.py +1 -0
- utils/file_handling/__init__.py +4 -0
- utils/file_handling/cleanup_folder.py +9 -0
- utils/file_handling/get_utc_foldername_with_ms.py +15 -0
- utils/file_handling/get_work_dir.py +9 -0
- utils/file_handling/is_valid_path_for_json.py +11 -0
- utils/file_handling/is_valid_path_to_json.py +17 -0
- utils/file_handling/load_json_file.py +18 -0
- utils/file_handling/read_file_from_file_archive.py +43 -0
- utils/file_handling/read_file_string.py +10 -0
- utils/file_handling/validate_json_data.py +28 -0
- utils/file_handling/write_json_file.py +23 -0
- utils/get_uuid.py +18 -0
- utils/get_uuid_test.py +17 -0
- utils/logging.py +100 -0
- utils/logging_test.py +67 -0
- utils/opcua/check_node.py +79 -0
- utils/resolve_unit/resolve_unit.py +11 -0
- utils/resolve_unit/unit_lib.py +2101 -0
- utils/resolve_unit/unit_lib_test.py +36 -0
- utils/type_conversion.py +236 -0
- utils/type_conversion_test.py +114 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
"""test suite for service."""
|
|
2
|
+
|
|
3
|
+
__copyright__ = (
|
|
4
|
+
"Copyright (c) 2026 Dresden University of Technology, Process-to-Order Group"
|
|
5
|
+
)
|
|
6
|
+
__license__ = "MIT"
|
|
7
|
+
from unittest.mock import Mock
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from mtppy.part4.automation_services.base_functions.service_operation_mode import (
|
|
12
|
+
ServiceOperationMode as SOM,
|
|
13
|
+
)
|
|
14
|
+
from mtppy.part4.automation_services.base_functions.service_source_mode import (
|
|
15
|
+
ServiceSourceMode as SSM,
|
|
16
|
+
)
|
|
17
|
+
from mtppy.part4.automation_services.procedure import Procedure
|
|
18
|
+
from mtppy.part4.automation_services.service import Service, _has_zero_id
|
|
19
|
+
from mtppy.part4.automation_services.service_elements.parameter_elements.parameter_element import (
|
|
20
|
+
ParameterElement,
|
|
21
|
+
)
|
|
22
|
+
from mtppy.part4.automation_services.service_elements.service_control import (
|
|
23
|
+
ServiceControl as SC,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MockService(Service):
|
|
28
|
+
def idle(self):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
def starting(self):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
def execute(self):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
def completing(self):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
def completed(self):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def pausing(self):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
def paused(self):
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
def resuming(self):
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def holding(self):
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def held(self):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
def unholding(self):
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
def stopping(self):
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
def stopped(self):
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def aborting(self):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def aborted(self):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
def resetting(self):
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def init_service_with_procedures(service_op_mode="off", service_src_mode="int"):
|
|
78
|
+
service = MockService("mock", "my fancy mock service")
|
|
79
|
+
|
|
80
|
+
dummy_procedures = [
|
|
81
|
+
Procedure(1, "first"),
|
|
82
|
+
Procedure(2, "second"),
|
|
83
|
+
Procedure(3, "third"),
|
|
84
|
+
Procedure(4, "forth"),
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
service.add_procedure(dummy_procedures)
|
|
88
|
+
|
|
89
|
+
if service_op_mode == "off":
|
|
90
|
+
service.service_control.service_op_mode[SOM.STATE_OFF_ACT] = True
|
|
91
|
+
elif service_op_mode == "op":
|
|
92
|
+
service.service_control.service_op_mode[SOM.STATE_OFF_ACT] = False
|
|
93
|
+
service.service_control.service_op_mode[SOM.STATE_OP_ACT] = True
|
|
94
|
+
elif service_op_mode == "aut":
|
|
95
|
+
service.service_control.service_op_mode[SOM.STATE_OFF_ACT] = False
|
|
96
|
+
service.service_control.service_op_mode[SOM.STATE_AUT_ACT] = True
|
|
97
|
+
else:
|
|
98
|
+
raise ValueError(f"ServiceOperationMode {service_op_mode} is unknown")
|
|
99
|
+
|
|
100
|
+
if service_src_mode == "int":
|
|
101
|
+
service.service_control.service_src_mode[SSM.SRC_INT_ACT] = True
|
|
102
|
+
elif service_src_mode == "ext":
|
|
103
|
+
service.service_control.service_src_mode[SSM.SRC_EXT_ACT] = True
|
|
104
|
+
else:
|
|
105
|
+
raise ValueError(f"ServiceSourceMode {service_src_mode} is unknown")
|
|
106
|
+
|
|
107
|
+
return service
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_service_initialization():
|
|
111
|
+
service = MockService("TestService", "Test Description")
|
|
112
|
+
assert service.name == "TestService"
|
|
113
|
+
assert service.service_control is not None
|
|
114
|
+
assert service.state_machine is not None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_service_name_can_be_updated():
|
|
118
|
+
service = MockService("TestService")
|
|
119
|
+
|
|
120
|
+
service.name = "RenamedService"
|
|
121
|
+
|
|
122
|
+
assert service.name == "RenamedService"
|
|
123
|
+
assert service.tag_name == "RenamedService"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_add_procedure_single():
|
|
127
|
+
service = MockService("TestService")
|
|
128
|
+
proc = Procedure(1, "Proc1")
|
|
129
|
+
service.add_procedure(proc)
|
|
130
|
+
assert 1 in service.procedures
|
|
131
|
+
assert service.procedures[1].name == "Proc1"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_add_procedure_list():
|
|
135
|
+
service = MockService("TestService")
|
|
136
|
+
procs = [Procedure(1, "Proc1"), Procedure(2, "Proc2")]
|
|
137
|
+
service.add_procedure(procs)
|
|
138
|
+
assert 1 in service.procedures
|
|
139
|
+
assert 2 in service.procedures
|
|
140
|
+
assert len(service.procedures) == 2
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_add_procedure_dict_and_none_values():
|
|
144
|
+
service = MockService("TestService")
|
|
145
|
+
first = Procedure(1, "Proc1")
|
|
146
|
+
second = Procedure(2, "Proc2")
|
|
147
|
+
|
|
148
|
+
service.add_procedure({"first": first, "missing": None, "second": second})
|
|
149
|
+
service.add_procedure(None)
|
|
150
|
+
|
|
151
|
+
assert service.procedures == {1: first, 2: second}
|
|
152
|
+
assert service.service_control.procedure_keys == [1, 2]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_create_procedure_invalid_id():
|
|
156
|
+
with pytest.raises(ValueError, match="ProcedureId must be bigger than 0"):
|
|
157
|
+
Procedure(0, "InvalidProc")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_add_configuration_parameter():
|
|
161
|
+
service = MockService("TestService")
|
|
162
|
+
param = ParameterElement("Param1", "Desc1")
|
|
163
|
+
service.add_configuration_parameter(param)
|
|
164
|
+
assert "Param1" in service.configuration_parameters
|
|
165
|
+
assert service.configuration_parameters["Param1"] == param
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_apply_configuration_parameters(monkeypatch):
|
|
169
|
+
service = MockService("TestService")
|
|
170
|
+
param = ParameterElement("Param1", "Desc1")
|
|
171
|
+
update_calls = []
|
|
172
|
+
monkeypatch.setattr(param, "update_v_out", lambda: update_calls.append(param))
|
|
173
|
+
service.add_configuration_parameter(param)
|
|
174
|
+
|
|
175
|
+
service.apply_configuration_parameters()
|
|
176
|
+
|
|
177
|
+
assert update_calls == [param]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_apply_procedure_parameters_for_current_procedure(monkeypatch):
|
|
181
|
+
service = MockService("TestService")
|
|
182
|
+
procedure = Procedure(1, "Proc1")
|
|
183
|
+
apply_calls = []
|
|
184
|
+
monkeypatch.setattr(
|
|
185
|
+
procedure,
|
|
186
|
+
"apply_procedure_parameters",
|
|
187
|
+
lambda: apply_calls.append(procedure),
|
|
188
|
+
)
|
|
189
|
+
service.add_procedure(procedure)
|
|
190
|
+
service.service_control[SC.PROCEDURE_CUR] = 1
|
|
191
|
+
|
|
192
|
+
service.apply_procedure_parameters()
|
|
193
|
+
|
|
194
|
+
assert apply_calls == [procedure]
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_current_procedure_lookup():
|
|
198
|
+
service = MockService("TestService")
|
|
199
|
+
procedure = Procedure(1, "Proc1")
|
|
200
|
+
service.add_procedure(procedure)
|
|
201
|
+
service.service_control[SC.PROCEDURE_CUR] = 1
|
|
202
|
+
|
|
203
|
+
assert service.get_current_procedure() is procedure
|
|
204
|
+
assert service._lookup_procedure_cur_name() == "Proc1"
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def test_lookup_procedure_name_without_current_procedure():
|
|
208
|
+
service = MockService("TestService")
|
|
209
|
+
service.service_control[SC.PROCEDURE_CUR] = 0
|
|
210
|
+
|
|
211
|
+
assert service._lookup_procedure_cur_name() == "undefined"
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def test_get_procedures_returns_service_procedures():
|
|
215
|
+
service = MockService("TestService")
|
|
216
|
+
|
|
217
|
+
assert service._get_procedures() is service.procedures
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def test_get_param_returns_current_procedure_parameter(monkeypatch):
|
|
221
|
+
service = MockService("TestService")
|
|
222
|
+
procedure = Mock()
|
|
223
|
+
parameter = Mock()
|
|
224
|
+
procedure.procedure_parameters = {"param1": parameter}
|
|
225
|
+
procedure.process_value_ins = {}
|
|
226
|
+
procedure.process_value_outs = {}
|
|
227
|
+
procedure.report_values = {}
|
|
228
|
+
procedure.required_equipment = {}
|
|
229
|
+
monkeypatch.setattr(service, "get_current_procedure", lambda: procedure)
|
|
230
|
+
|
|
231
|
+
assert service.get_param("param1") is parameter
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_get_param_returns_none_when_parameter_is_not_found(monkeypatch):
|
|
235
|
+
service = MockService("TestService")
|
|
236
|
+
procedure = Mock()
|
|
237
|
+
procedure.procedure_parameters = {}
|
|
238
|
+
procedure.process_value_ins = {}
|
|
239
|
+
procedure.process_value_outs = {}
|
|
240
|
+
procedure.report_values = {}
|
|
241
|
+
procedure.required_equipment = {}
|
|
242
|
+
monkeypatch.setattr(service, "get_current_procedure", lambda: procedure)
|
|
243
|
+
|
|
244
|
+
assert service.get_param("missing") is None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def test_is_state_reallocates_when_state_does_not_match(monkeypatch):
|
|
248
|
+
service = MockService("TestService")
|
|
249
|
+
reallocate_calls = []
|
|
250
|
+
monkeypatch.setattr(
|
|
251
|
+
service.thread_ctrl,
|
|
252
|
+
"reallocate_running_thread",
|
|
253
|
+
lambda: reallocate_calls.append(True),
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
assert service.is_state("idle") is True
|
|
257
|
+
assert service.is_state("execute") is False
|
|
258
|
+
assert reallocate_calls == [True]
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_state_change_delegates_to_state_machine(monkeypatch):
|
|
262
|
+
service = MockService("TestService")
|
|
263
|
+
state_change_calls = []
|
|
264
|
+
monkeypatch.setattr(
|
|
265
|
+
service.state_machine,
|
|
266
|
+
"state_change",
|
|
267
|
+
lambda: state_change_calls.append(True),
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
service.state_change()
|
|
271
|
+
|
|
272
|
+
assert state_change_calls == [True]
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def test_get_current_procedure_none():
|
|
276
|
+
service = MockService("TestService")
|
|
277
|
+
service.service_control[SC.PROCEDURE_REQ] = 0
|
|
278
|
+
with pytest.raises(RuntimeError, match="No current procedure"):
|
|
279
|
+
service.get_current_procedure()
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def test_service_state_callback_returns_while_offline(monkeypatch):
|
|
283
|
+
service = MockService("TestService")
|
|
284
|
+
state_calls = []
|
|
285
|
+
monkeypatch.setattr(
|
|
286
|
+
service.state_machine,
|
|
287
|
+
"get_current_state_str",
|
|
288
|
+
lambda: state_calls.append(True) or "idle",
|
|
289
|
+
)
|
|
290
|
+
service.service_control.service_op_mode[SOM.STATE_OFF_ACT] = True
|
|
291
|
+
|
|
292
|
+
service._state_change_callback()
|
|
293
|
+
|
|
294
|
+
assert state_calls == []
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def test_service_state_callback_handles_undefined_state(monkeypatch):
|
|
298
|
+
service = MockService("TestService")
|
|
299
|
+
requested_states = []
|
|
300
|
+
monkeypatch.setattr(
|
|
301
|
+
service.state_machine,
|
|
302
|
+
"get_current_state_str",
|
|
303
|
+
lambda: "undefined",
|
|
304
|
+
)
|
|
305
|
+
monkeypatch.setattr(
|
|
306
|
+
service.service_control.service_op_mode,
|
|
307
|
+
"allow_switch_to_offline_mode",
|
|
308
|
+
lambda allow_flag: requested_states.append(allow_flag),
|
|
309
|
+
)
|
|
310
|
+
service.service_control.service_op_mode[SOM.STATE_OFF_ACT] = False
|
|
311
|
+
|
|
312
|
+
service._state_change_callback()
|
|
313
|
+
|
|
314
|
+
assert requested_states == [False]
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def test_service_state_callback_applies_starting_procedure_parameters(monkeypatch):
|
|
318
|
+
service = MockService("TestService")
|
|
319
|
+
procedure = Procedure(1, "Proc1")
|
|
320
|
+
service.add_procedure(procedure)
|
|
321
|
+
service.service_control[SC.PROCEDURE_CUR] = 1
|
|
322
|
+
apply_calls = []
|
|
323
|
+
thread_calls = []
|
|
324
|
+
monkeypatch.setattr(
|
|
325
|
+
service,
|
|
326
|
+
"apply_procedure_parameters",
|
|
327
|
+
lambda: apply_calls.append(True),
|
|
328
|
+
)
|
|
329
|
+
monkeypatch.setattr(
|
|
330
|
+
service.state_machine,
|
|
331
|
+
"get_current_state_str",
|
|
332
|
+
lambda: "starting",
|
|
333
|
+
)
|
|
334
|
+
monkeypatch.setattr(
|
|
335
|
+
service.thread_ctrl,
|
|
336
|
+
"request_state",
|
|
337
|
+
lambda state, callback: thread_calls.append((state, callback)),
|
|
338
|
+
)
|
|
339
|
+
monkeypatch.setattr(
|
|
340
|
+
service.thread_ctrl,
|
|
341
|
+
"reallocate_running_thread",
|
|
342
|
+
lambda: thread_calls.append("reallocate"),
|
|
343
|
+
)
|
|
344
|
+
monkeypatch.setattr(
|
|
345
|
+
service.service_control.service_op_mode,
|
|
346
|
+
"allow_switch_to_offline_mode",
|
|
347
|
+
lambda allow_flag: thread_calls.append(("offline", allow_flag)),
|
|
348
|
+
)
|
|
349
|
+
service.service_control.service_op_mode[SOM.STATE_OFF_ACT] = False
|
|
350
|
+
|
|
351
|
+
service._state_change_callback()
|
|
352
|
+
|
|
353
|
+
assert apply_calls == [True]
|
|
354
|
+
assert thread_calls[0][0] == "starting"
|
|
355
|
+
assert thread_calls[1] == "reallocate"
|
|
356
|
+
assert thread_calls[2] == ("offline", False)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def test_service_state_callback_allows_offline_only_in_idle(monkeypatch):
|
|
360
|
+
service = MockService("TestService")
|
|
361
|
+
offline_requests = []
|
|
362
|
+
monkeypatch.setattr(
|
|
363
|
+
service.state_machine,
|
|
364
|
+
"get_current_state_str",
|
|
365
|
+
lambda: "idle",
|
|
366
|
+
)
|
|
367
|
+
monkeypatch.setattr(
|
|
368
|
+
service.thread_ctrl,
|
|
369
|
+
"request_state",
|
|
370
|
+
lambda state, callback: None,
|
|
371
|
+
)
|
|
372
|
+
monkeypatch.setattr(
|
|
373
|
+
service.thread_ctrl,
|
|
374
|
+
"reallocate_running_thread",
|
|
375
|
+
lambda: None,
|
|
376
|
+
)
|
|
377
|
+
monkeypatch.setattr(
|
|
378
|
+
service.service_control.service_op_mode,
|
|
379
|
+
"allow_switch_to_offline_mode",
|
|
380
|
+
lambda allow_flag: offline_requests.append(allow_flag),
|
|
381
|
+
)
|
|
382
|
+
service.service_control.service_op_mode[SOM.STATE_OFF_ACT] = False
|
|
383
|
+
|
|
384
|
+
service._state_change_callback()
|
|
385
|
+
|
|
386
|
+
assert offline_requests == [True]
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
class ProcedureIdDouble:
|
|
390
|
+
def __init__(self, procedure_id):
|
|
391
|
+
self.procedure_id = procedure_id
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
@pytest.mark.parametrize(
|
|
395
|
+
("procedure", "expected"),
|
|
396
|
+
[
|
|
397
|
+
(None, False),
|
|
398
|
+
(ProcedureIdDouble(1), False),
|
|
399
|
+
(ProcedureIdDouble(0), True),
|
|
400
|
+
([None, ProcedureIdDouble(1)], False),
|
|
401
|
+
([None, ProcedureIdDouble(0)], True),
|
|
402
|
+
({"missing": None, "valid": ProcedureIdDouble(1)}, False),
|
|
403
|
+
({"missing": None, "zero": ProcedureIdDouble(0)}, True),
|
|
404
|
+
],
|
|
405
|
+
)
|
|
406
|
+
def test_has_zero_id_supports_procedure_shapes(procedure, expected):
|
|
407
|
+
assert _has_zero_id(procedure) is expected
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Definition of CommandCodes."""
|
|
2
|
+
|
|
3
|
+
__copyright__ = (
|
|
4
|
+
"Copyright (c) 2026 Dresden University of Technology, Process-to-Order Group"
|
|
5
|
+
)
|
|
6
|
+
__license__ = "MIT"
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CommandCodes(Enum):
|
|
12
|
+
"""
|
|
13
|
+
List of commands defined for MTP services
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
RESET = ("reset", 2)
|
|
17
|
+
START = ("start", 4)
|
|
18
|
+
STOP = ("stop", 8)
|
|
19
|
+
HOLD = ("hold", 16)
|
|
20
|
+
UNHOLD = ("unhold", 32)
|
|
21
|
+
PAUSE = ("pause", 64)
|
|
22
|
+
RESUME = ("resume", 128)
|
|
23
|
+
ABORT = ("abort", 256)
|
|
24
|
+
RESTART = ("restart", 512)
|
|
25
|
+
COMPLETE = ("complete", 1024)
|
|
26
|
+
|
|
27
|
+
def __init__(self, string: str, code: int):
|
|
28
|
+
self.string = string
|
|
29
|
+
self.code = code
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def list_of_strings(cls) -> list[str]:
|
|
33
|
+
return [c.string for c in CommandCodes]
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def list_of_codes(cls) -> list[int]:
|
|
37
|
+
return [c.code for c in CommandCodes]
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_code(cls, code: int) -> str:
|
|
41
|
+
for member in cls:
|
|
42
|
+
if member.code == code:
|
|
43
|
+
return member.string
|
|
44
|
+
raise ValueError(f"Unknown command code: {code}")
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_string(cls, string: str) -> int:
|
|
48
|
+
search_string = string.lower()
|
|
49
|
+
for member in cls:
|
|
50
|
+
if member.string == search_string:
|
|
51
|
+
return member.code
|
|
52
|
+
raise ValueError(f"Unknown command string: {string}")
|
|
53
|
+
|
|
54
|
+
def __str__(self):
|
|
55
|
+
return self.string
|
|
56
|
+
|
|
57
|
+
def __int__(self):
|
|
58
|
+
return self.code
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Test suite for CommandCodes."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from mtppy.part4.definitions.command_codes import CommandCodes
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_command_metadata_and_conversions():
|
|
9
|
+
assert CommandCodes.START.string == "start"
|
|
10
|
+
assert CommandCodes.START.code == 4
|
|
11
|
+
assert str(CommandCodes.START) == "start"
|
|
12
|
+
assert int(CommandCodes.START) == 4
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_list_helpers_return_all_commands_in_enum_order():
|
|
16
|
+
assert CommandCodes.list_of_strings() == [member.string for member in CommandCodes]
|
|
17
|
+
assert CommandCodes.list_of_codes() == [member.code for member in CommandCodes]
|
|
18
|
+
assert len(CommandCodes.list_of_codes()) == len(CommandCodes)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.parametrize("code", [member.code for member in CommandCodes])
|
|
22
|
+
def test_from_code_returns_command_string(code):
|
|
23
|
+
member = next(member for member in CommandCodes if member.code == code)
|
|
24
|
+
|
|
25
|
+
assert CommandCodes.from_code(code) == member.string
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.mark.parametrize("string", ["RESET", "Start", "complete"])
|
|
29
|
+
def test_from_string_is_case_insensitive(string):
|
|
30
|
+
expected = next(
|
|
31
|
+
member.code for member in CommandCodes if member.string == string.lower()
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
assert CommandCodes.from_string(string) == expected
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_invalid_command_code_is_rejected():
|
|
38
|
+
with pytest.raises(ValueError, match="Unknown command code: 999"):
|
|
39
|
+
CommandCodes.from_code(999)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_invalid_command_string_is_rejected():
|
|
43
|
+
with pytest.raises(ValueError, match="Unknown command string: launch"):
|
|
44
|
+
CommandCodes.from_string("launch")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Definition of StateCodes."""
|
|
2
|
+
|
|
3
|
+
__copyright__ = (
|
|
4
|
+
"Copyright (c) 2026 Dresden University of Technology, Process-to-Order Group"
|
|
5
|
+
)
|
|
6
|
+
__license__ = "MIT"
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class StateCodes(Enum):
|
|
12
|
+
"""
|
|
13
|
+
List of states defined for MTP services
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
UNDEFINED = ("undefined", 0)
|
|
17
|
+
STOPPED = ("stopped", 4)
|
|
18
|
+
STARTING = ("starting", 8)
|
|
19
|
+
IDLE = ("idle", 16)
|
|
20
|
+
PAUSED = ("paused", 32)
|
|
21
|
+
EXECUTE = ("execute", 64)
|
|
22
|
+
STOPPING = ("stopping", 128)
|
|
23
|
+
ABORTING = ("aborting", 256)
|
|
24
|
+
ABORTED = ("aborted", 512)
|
|
25
|
+
HOLDING = ("holding", 1024)
|
|
26
|
+
HELD = ("held", 2048)
|
|
27
|
+
UNHOLDING = ("unholding", 4096)
|
|
28
|
+
PAUSING = ("pausing", 8192)
|
|
29
|
+
RESUMING = ("resuming", 16384)
|
|
30
|
+
RESETTING = ("resetting", 32678)
|
|
31
|
+
COMPLETING = ("completing", 65536)
|
|
32
|
+
COMPLETED = ("completed", 131072)
|
|
33
|
+
|
|
34
|
+
def __init__(self, string: str, code: int):
|
|
35
|
+
self.string = string
|
|
36
|
+
self.code = code
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def list_of_strings(cls) -> list[str]:
|
|
40
|
+
return [c.string for c in StateCodes]
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def list_of_codes(cls) -> list[int]:
|
|
44
|
+
return [c.code for c in StateCodes]
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_code(cls, code: int) -> str:
|
|
48
|
+
for member in cls:
|
|
49
|
+
if member.code == code:
|
|
50
|
+
return member.string
|
|
51
|
+
raise ValueError(f"Unknown state: {code}")
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def from_string(cls, string: str) -> int:
|
|
55
|
+
search_string = string.lower()
|
|
56
|
+
for member in cls:
|
|
57
|
+
if member.string == search_string:
|
|
58
|
+
return member.code
|
|
59
|
+
raise ValueError(f"Unknown state string: {string}")
|
|
60
|
+
|
|
61
|
+
def __str__(self):
|
|
62
|
+
return self.string
|
|
63
|
+
|
|
64
|
+
def __int__(self):
|
|
65
|
+
return self.code
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Test suite for StateCodes."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from mtppy.part4.definitions.state_codes import StateCodes
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_state_metadata_and_conversions():
|
|
9
|
+
assert StateCodes.IDLE.string == "idle"
|
|
10
|
+
assert StateCodes.IDLE.code == 16
|
|
11
|
+
assert str(StateCodes.IDLE) == "idle"
|
|
12
|
+
assert int(StateCodes.IDLE) == 16
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_list_helpers_return_all_states_in_enum_order():
|
|
16
|
+
assert StateCodes.list_of_strings() == [member.string for member in StateCodes]
|
|
17
|
+
assert StateCodes.list_of_codes() == [member.code for member in StateCodes]
|
|
18
|
+
assert len(StateCodes.list_of_codes()) == len(StateCodes)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.mark.parametrize("code", [member.code for member in StateCodes])
|
|
22
|
+
def test_from_code_returns_state_string(code):
|
|
23
|
+
member = next(member for member in StateCodes if member.code == code)
|
|
24
|
+
|
|
25
|
+
assert StateCodes.from_code(code) == member.string
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.mark.parametrize("string", ["UNDEFINED", "Idle", "COMPLETED"])
|
|
29
|
+
def test_from_string_is_case_insensitive(string):
|
|
30
|
+
expected = next(
|
|
31
|
+
member.code for member in StateCodes if member.string == string.lower()
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
assert StateCodes.from_string(string) == expected
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_invalid_state_code_is_rejected():
|
|
38
|
+
with pytest.raises(ValueError, match="Unknown state: 999"):
|
|
39
|
+
StateCodes.from_code(999)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_invalid_state_string_is_rejected():
|
|
43
|
+
with pytest.raises(ValueError, match="Unknown state string: launch"):
|
|
44
|
+
StateCodes.from_string("launch")
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Implementation of the VQC Base Function."""
|
|
2
|
+
|
|
3
|
+
__copyright__ = (
|
|
4
|
+
"Copyright (c) 2026 Dresden University of Technology, Process-to-Order Group"
|
|
5
|
+
)
|
|
6
|
+
__license__ = "MIT"
|
|
7
|
+
|
|
8
|
+
from typing import ClassVar
|
|
9
|
+
|
|
10
|
+
import utils.type_conversion as tc
|
|
11
|
+
from mtppy.part3.definitions.mtp_access import MTPAccess
|
|
12
|
+
from mtppy.part5.definitions.w3c_xml_data_types import W3cXmlDataTypes
|
|
13
|
+
from mtppy.utils.data_item import DataItem, DataItemCollection
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class VQCBaseFunction(DataItemCollection):
|
|
17
|
+
"""Provide the VQC process value base function.
|
|
18
|
+
|
|
19
|
+
This base function stores the VQC value and exposes it through a
|
|
20
|
+
read/write data item.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
VQC_ = "VQC"
|
|
24
|
+
|
|
25
|
+
CLASS_DATA_ITEMS: ClassVar = {
|
|
26
|
+
VQC_: DataItem(
|
|
27
|
+
VQC_,
|
|
28
|
+
W3cXmlDataTypes.UNSIGNED_BYTE,
|
|
29
|
+
MTPAccess.ReadWriteAccess,
|
|
30
|
+
255,
|
|
31
|
+
),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def __init__(self) -> None:
|
|
35
|
+
"""Initialize the VQC BaseFunction.
|
|
36
|
+
|
|
37
|
+
Sets up the VQC data item with the appropriate write callback.
|
|
38
|
+
"""
|
|
39
|
+
super().__init__()
|
|
40
|
+
|
|
41
|
+
self.get_item(VQCBaseFunction.VQC_).ext_wrt_cb = self._set_vqc
|
|
42
|
+
|
|
43
|
+
def _set_vqc(self, value: tc.ANY_TYPE) -> None:
|
|
44
|
+
self[VQCBaseFunction.VQC_] = value
|
|
45
|
+
|
|
46
|
+
def get_vqc(self) -> int:
|
|
47
|
+
"""Return the current VQC value."""
|
|
48
|
+
return tc.cast_to_int(self[VQCBaseFunction.VQC_])
|