isar 1.25.8__py3-none-any.whl → 1.26.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.

Potentially problematic release.


This version of isar might be problematic. Click here for more details.

Files changed (45) hide show
  1. isar/apis/models/start_mission_definition.py +55 -108
  2. isar/apis/robot_control/robot_controller.py +5 -4
  3. isar/apis/schedule/scheduling_controller.py +4 -32
  4. isar/apis/security/authentication.py +2 -2
  5. isar/config/settings.env +1 -3
  6. isar/config/settings.py +5 -5
  7. isar/models/communication/message.py +0 -4
  8. isar/models/communication/queues/queue_utils.py +27 -0
  9. isar/models/communication/queues/queues.py +23 -5
  10. isar/robot/robot.py +91 -0
  11. isar/robot/robot_start_mission.py +73 -0
  12. isar/robot/robot_status.py +46 -0
  13. isar/robot/robot_task_status.py +92 -0
  14. isar/script.py +7 -0
  15. isar/services/utilities/scheduling_utilities.py +15 -26
  16. isar/state_machine/state_machine.py +94 -187
  17. isar/state_machine/states/blocked_protective_stop.py +7 -19
  18. isar/state_machine/states/idle.py +12 -54
  19. isar/state_machine/states/monitor.py +43 -90
  20. isar/state_machine/states/offline.py +8 -33
  21. isar/state_machine/states/paused.py +1 -1
  22. isar/state_machine/states_enum.py +0 -2
  23. isar/state_machine/transitions/fail_mission.py +13 -0
  24. isar/state_machine/transitions/finish_mission.py +39 -0
  25. isar/state_machine/transitions/pause.py +24 -0
  26. isar/state_machine/transitions/resume.py +27 -0
  27. isar/state_machine/transitions/start_mission.py +73 -0
  28. isar/state_machine/transitions/stop.py +33 -0
  29. isar/state_machine/transitions/utils.py +10 -0
  30. isar/storage/slimm_storage.py +2 -2
  31. {isar-1.25.8.dist-info → isar-1.26.0.dist-info}/METADATA +2 -3
  32. {isar-1.25.8.dist-info → isar-1.26.0.dist-info}/RECORD +42 -33
  33. robot_interface/models/exceptions/robot_exceptions.py +0 -24
  34. robot_interface/models/mission/task.py +1 -1
  35. robot_interface/robot_interface.py +1 -6
  36. robot_interface/telemetry/mqtt_client.py +0 -1
  37. robot_interface/telemetry/payloads.py +3 -3
  38. robot_interface/utilities/json_service.py +1 -1
  39. isar/state_machine/states/initialize.py +0 -71
  40. isar/state_machine/states/initiate.py +0 -111
  41. robot_interface/models/initialize/initialize_params.py +0 -9
  42. {isar-1.25.8.dist-info → isar-1.26.0.dist-info}/LICENSE +0 -0
  43. {isar-1.25.8.dist-info → isar-1.26.0.dist-info}/WHEEL +0 -0
  44. {isar-1.25.8.dist-info → isar-1.26.0.dist-info}/entry_points.txt +0 -0
  45. {isar-1.25.8.dist-info → isar-1.26.0.dist-info}/top_level.txt +0 -0
@@ -1,23 +1,17 @@
1
1
  import logging
2
2
  import time
3
3
  from copy import deepcopy
4
- from typing import TYPE_CHECKING, Callable, Optional, Tuple, Union
4
+ from typing import TYPE_CHECKING, Callable, Optional, Tuple
5
5
 
6
6
  from injector import inject
7
7
  from transitions import State
8
8
 
9
9
  from isar.config.settings import settings
10
- from isar.services.utilities.threaded_request import (
11
- ThreadedRequest,
12
- ThreadedRequestNotFinishedError,
13
- )
10
+ from isar.services.utilities.threaded_request import ThreadedRequest
14
11
  from robot_interface.models.exceptions.robot_exceptions import (
15
12
  ErrorMessage,
16
- RobotCommunicationException,
17
- RobotCommunicationTimeoutException,
18
13
  RobotException,
19
14
  RobotRetrieveInspectionException,
20
- RobotTaskStatusException,
21
15
  )
22
16
  from robot_interface.models.inspection.inspection import Inspection
23
17
  from robot_interface.models.mission.mission import Mission
@@ -33,24 +27,19 @@ class Monitor(State):
33
27
  def __init__(self, state_machine: "StateMachine") -> None:
34
28
  super().__init__(name="monitor", on_enter=self.start, on_exit=self.stop)
35
29
  self.state_machine: "StateMachine" = state_machine
36
- self.request_status_failure_counter: int = 0
37
- self.request_status_failure_counter_limit: int = (
38
- settings.REQUEST_STATUS_FAILURE_COUNTER_LIMIT
39
- )
40
30
 
41
31
  self.logger = logging.getLogger("state_machine")
42
- self.task_status_thread: Optional[ThreadedRequest] = None
43
32
 
44
33
  def start(self) -> None:
45
34
  self.state_machine.update_state()
46
35
  self._run()
47
36
 
48
37
  def stop(self) -> None:
49
- if self.task_status_thread:
50
- self.task_status_thread.wait_for_thread()
51
- self.task_status_thread = None
38
+ self.state_machine.mission_ongoing = False
39
+ return
52
40
 
53
41
  def _run(self) -> None:
42
+ awaiting_task_status: bool = False
54
43
  transition: Callable
55
44
  while True:
56
45
  if self.state_machine.should_stop_mission():
@@ -61,50 +50,53 @@ class Monitor(State):
61
50
  transition = self.state_machine.pause # type: ignore
62
51
  break
63
52
 
64
- if not self.task_status_thread:
65
- self._run_get_status_thread(
66
- status_function=self.state_machine.robot.task_status,
67
- function_argument=self.state_machine.current_task.id,
68
- thread_name="State Machine Monitor Get Task Status",
69
- )
70
- try:
71
- status: TaskStatus = self.task_status_thread.get_output()
72
- self.request_status_failure_counter = 0
73
- except ThreadedRequestNotFinishedError:
74
- time.sleep(self.state_machine.sleep_time)
75
- continue
76
- except (
77
- RobotCommunicationTimeoutException,
78
- RobotCommunicationException,
79
- ) as e:
80
- retry_limit_exceeded: bool = self._check_if_exceeded_retry_limit(e)
81
- if retry_limit_exceeded:
82
- self.logger.error(
83
- f"Monitoring task {self.state_machine.current_task.id[:8]} failed "
84
- f"because: {e.error_description}"
85
- )
86
- status = TaskStatus.Failed
53
+ if not self.state_machine.mission_ongoing:
54
+ if self.state_machine.get_mission_started_event():
55
+ self.state_machine.mission_ongoing = True
87
56
  else:
88
- time.sleep(settings.REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY)
57
+ time.sleep(settings.FSM_SLEEP_TIME)
89
58
  continue
90
59
 
91
- except RobotTaskStatusException as e:
92
- self.state_machine.current_task.error_message = ErrorMessage(
93
- error_reason=e.error_reason, error_description=e.error_description
60
+ mission_failed = self.state_machine.get_mission_failed_event()
61
+ if mission_failed is not None:
62
+ self.state_machine.logger.warning(
63
+ f"Failed to initiate mission "
64
+ f"{str(self.state_machine.current_mission.id)[:8]} because: "
65
+ f"{mission_failed.error_description}"
94
66
  )
95
- self.logger.error(
96
- f"Monitoring task {self.state_machine.current_task.id[:8]} failed "
97
- f"because: {e.error_description}"
67
+ self.state_machine.current_mission.error_message = ErrorMessage(
68
+ error_reason=mission_failed.error_reason,
69
+ error_description=mission_failed.error_description,
98
70
  )
99
- status = TaskStatus.Failed
100
71
 
101
- except RobotException as e:
102
- self._set_error_message(e)
103
- status = TaskStatus.Failed
72
+ transition = self.state_machine.mission_failed_to_start # type: ignore
73
+ break
104
74
 
75
+ status: TaskStatus
76
+
77
+ task_failure: Optional[ErrorMessage] = (
78
+ self.state_machine.get_task_failure_event()
79
+ )
80
+ if task_failure is not None:
81
+ self.state_machine.current_task.error_message = task_failure
105
82
  self.logger.error(
106
- f"Retrieving the status failed because: {e.error_description}"
83
+ f"Monitoring task {self.state_machine.current_task.id[:8]} failed "
84
+ f"because: {task_failure.error_description}"
107
85
  )
86
+ status = TaskStatus.Failed
87
+ else:
88
+ status = self.state_machine.get_task_status_event()
89
+
90
+ if status is None:
91
+ if not awaiting_task_status:
92
+ self.state_machine.request_task_status(
93
+ self.state_machine.current_task
94
+ )
95
+ awaiting_task_status = True
96
+ time.sleep(settings.FSM_SLEEP_TIME)
97
+ continue
98
+ else:
99
+ awaiting_task_status = False
108
100
 
109
101
  if not isinstance(status, TaskStatus):
110
102
  self.logger.error(
@@ -148,17 +140,8 @@ class Monitor(State):
148
140
  task=self.state_machine.current_task
149
141
  )
150
142
 
151
- self.task_status_thread = None
152
- time.sleep(self.state_machine.sleep_time)
153
-
154
143
  transition()
155
144
 
156
- def _run_get_status_thread(
157
- self, status_function: Callable, function_argument: str, thread_name: str
158
- ) -> None:
159
- self.task_status_thread = ThreadedRequest(request_func=status_function)
160
- self.task_status_thread.start_thread(function_argument, name=thread_name)
161
-
162
145
  def _queue_inspections_for_upload(
163
146
  self, mission: Mission, current_task: InspectionTask
164
147
  ) -> None:
@@ -218,33 +201,3 @@ class Monitor(State):
218
201
  error_reason=e.error_reason, error_description=e.error_description
219
202
  )
220
203
  self.state_machine.current_task.error_message = error_message
221
-
222
- def _check_if_exceeded_retry_limit(
223
- self, e: Union[RobotCommunicationTimeoutException, RobotCommunicationException]
224
- ) -> bool:
225
- self.state_machine.current_mission.error_message = ErrorMessage(
226
- error_reason=e.error_reason, error_description=e.error_description
227
- )
228
- self.task_status_thread = None
229
- self.request_status_failure_counter += 1
230
- self.logger.warning(
231
- f"Monitoring task {self.state_machine.current_task.id} failed #: "
232
- f"{self.request_status_failure_counter} failed because: {e.error_description}"
233
- )
234
-
235
- if (
236
- self.request_status_failure_counter
237
- >= self.request_status_failure_counter_limit
238
- ):
239
- self.state_machine.current_task.error_message = ErrorMessage(
240
- error_reason=e.error_reason,
241
- error_description=e.error_description,
242
- )
243
- self.logger.error(
244
- f"Task will be cancelled after failing to get task status "
245
- f"{self.request_status_failure_counter} times because: "
246
- f"{e.error_description}"
247
- )
248
- return True
249
-
250
- return False
@@ -1,15 +1,9 @@
1
1
  import logging
2
2
  import time
3
- from typing import TYPE_CHECKING, Optional
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from transitions import State
6
6
 
7
- from isar.config.settings import settings
8
- from isar.services.utilities.threaded_request import (
9
- ThreadedRequest,
10
- ThreadedRequestNotFinishedError,
11
- )
12
- from robot_interface.models.exceptions.robot_exceptions import RobotException
13
7
  from robot_interface.models.mission.status import RobotStatus
14
8
 
15
9
  if TYPE_CHECKING:
@@ -21,43 +15,24 @@ class Offline(State):
21
15
  super().__init__(name="offline", on_enter=self.start, on_exit=self.stop)
22
16
  self.state_machine: "StateMachine" = state_machine
23
17
  self.logger = logging.getLogger("state_machine")
24
- self.robot_status_thread: Optional[ThreadedRequest] = None
25
18
 
26
19
  def start(self) -> None:
27
20
  self.state_machine.update_state()
28
21
  self._run()
29
22
 
30
23
  def stop(self) -> None:
31
- if self.robot_status_thread:
32
- self.robot_status_thread.wait_for_thread()
33
- self.robot_status_thread = None
24
+ return
34
25
 
35
26
  def _run(self) -> None:
36
27
  while True:
37
- if not self.robot_status_thread:
38
- self.robot_status_thread = ThreadedRequest(
39
- request_func=self.state_machine.robot.robot_status
40
- )
41
- self.robot_status_thread.start_thread(
42
- name="State Machine Offline Get Robot Status"
43
- )
44
-
45
- try:
46
- robot_status: RobotStatus = self.robot_status_thread.get_output()
47
- except ThreadedRequestNotFinishedError:
48
- time.sleep(self.state_machine.sleep_time)
49
- continue
50
-
51
- except RobotException as e:
52
- self.logger.error(
53
- f"Failed to get robot status because: {e.error_description}"
54
- )
55
-
56
- if robot_status != RobotStatus.Offline:
28
+ robot_status = self.state_machine.get_robot_status()
29
+ if robot_status == RobotStatus.BlockedProtectiveStop:
30
+ transition = self.state_machine.robot_protective_stop_engaged # type: ignore
31
+ break
32
+ elif robot_status != RobotStatus.Offline:
57
33
  transition = self.state_machine.robot_turned_online # type: ignore
58
34
  break
59
35
 
60
- self.robot_status_thread = None
61
- time.sleep(settings.ROBOT_API_STATUS_POLL_INTERVAL)
36
+ time.sleep(self.state_machine.sleep_time)
62
37
 
63
38
  transition()
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import time
3
- from typing import Callable, TYPE_CHECKING
3
+ from typing import TYPE_CHECKING, Callable
4
4
 
5
5
  from transitions import State
6
6
 
@@ -4,8 +4,6 @@ from enum import Enum
4
4
  class States(str, Enum):
5
5
  Off = "off"
6
6
  Idle = "idle"
7
- Initiate = "initiate"
8
- Initialize = "initialize"
9
7
  Monitor = "monitor"
10
8
  Paused = "paused"
11
9
  Stop = "stop"
@@ -0,0 +1,13 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from isar.state_machine.state_machine import StateMachine
5
+
6
+ from robot_interface.models.mission.status import MissionStatus, TaskStatus
7
+
8
+
9
+ def report_failed_mission_and_finalize(state_machine: "StateMachine") -> None:
10
+ state_machine.current_task.status = TaskStatus.Failed
11
+ state_machine.current_mission.status = MissionStatus.Failed
12
+ state_machine.publish_task_status(task=state_machine.current_task)
13
+ state_machine._finalize()
@@ -0,0 +1,39 @@
1
+ from typing import TYPE_CHECKING, List
2
+
3
+ if TYPE_CHECKING:
4
+ from isar.state_machine.state_machine import StateMachine
5
+
6
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
7
+ from robot_interface.models.mission.status import MissionStatus, TaskStatus
8
+
9
+
10
+ def finish_mission(state_machine: "StateMachine") -> bool:
11
+ fail_statuses: List[TaskStatus] = [
12
+ TaskStatus.Cancelled,
13
+ TaskStatus.Failed,
14
+ ]
15
+ partially_fail_statuses = fail_statuses + [TaskStatus.PartiallySuccessful]
16
+
17
+ if len(state_machine.current_mission.tasks) == 0:
18
+ state_machine.current_mission.status = MissionStatus.Successful
19
+ elif all(
20
+ task.status in fail_statuses for task in state_machine.current_mission.tasks
21
+ ):
22
+ state_machine.current_mission.error_message = ErrorMessage(
23
+ error_reason=None,
24
+ error_description="The mission failed because all tasks in the mission "
25
+ "failed",
26
+ )
27
+ state_machine.current_mission.status = MissionStatus.Failed
28
+ elif any(
29
+ task.status in partially_fail_statuses
30
+ for task in state_machine.current_mission.tasks
31
+ ):
32
+ state_machine.current_mission.status = MissionStatus.PartiallySuccessful
33
+ else:
34
+ state_machine.current_mission.status = MissionStatus.Successful
35
+ state_machine._finalize()
36
+
37
+ state_machine.current_task = None
38
+ state_machine.send_task_status()
39
+ return True
@@ -0,0 +1,24 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from isar.state_machine.state_machine import StateMachine
5
+
6
+ from isar.apis.models.models import ControlMissionResponse
7
+ from robot_interface.models.mission.status import MissionStatus, TaskStatus
8
+
9
+
10
+ def pause_mission(state_machine: "StateMachine") -> bool:
11
+ state_machine.logger.info(f"Pausing mission: {state_machine.current_mission.id}")
12
+ state_machine.current_mission.status = MissionStatus.Paused
13
+ state_machine.current_task.status = TaskStatus.Paused
14
+
15
+ paused_mission_response: ControlMissionResponse = (
16
+ state_machine._make_control_mission_response()
17
+ )
18
+ state_machine.queues.api_pause_mission.output.put(paused_mission_response)
19
+
20
+ state_machine.publish_mission_status()
21
+ state_machine.publish_task_status(task=state_machine.current_task)
22
+
23
+ state_machine.robot.pause()
24
+ return True
@@ -0,0 +1,27 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from isar.state_machine.state_machine import StateMachine
5
+
6
+ from isar.apis.models.models import ControlMissionResponse
7
+ from robot_interface.models.mission.status import MissionStatus, TaskStatus
8
+
9
+
10
+ def resume_mission(state_machine: "StateMachine") -> bool:
11
+ state_machine.logger.info(f"Resuming mission: {state_machine.current_mission.id}")
12
+ state_machine.current_mission.status = MissionStatus.InProgress
13
+ state_machine.current_mission.error_message = None
14
+ state_machine.current_task.status = TaskStatus.InProgress
15
+
16
+ state_machine.mission_ongoing = True
17
+
18
+ state_machine.publish_mission_status()
19
+ state_machine.publish_task_status(task=state_machine.current_task)
20
+
21
+ resume_mission_response: ControlMissionResponse = (
22
+ state_machine._make_control_mission_response()
23
+ )
24
+ state_machine.queues.api_resume_mission.output.put(resume_mission_response)
25
+
26
+ state_machine.robot.resume()
27
+ return True
@@ -0,0 +1,73 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from isar.state_machine.state_machine import StateMachine
5
+
6
+ from robot_interface.models.exceptions.robot_exceptions import (
7
+ ErrorMessage,
8
+ RobotException,
9
+ RobotInitializeException,
10
+ )
11
+ from robot_interface.models.mission.status import MissionStatus, TaskStatus
12
+
13
+
14
+ def put_start_mission_on_queue(state_machine: "StateMachine") -> bool:
15
+ state_machine.queues.api_start_mission.output.put(True)
16
+ return True
17
+
18
+
19
+ def initiate_mission(state_machine: "StateMachine") -> bool:
20
+ state_machine.logger.info(
21
+ f"Initialization successful. Starting new mission: "
22
+ f"{state_machine.current_mission.id}"
23
+ )
24
+ state_machine.log_mission_overview(mission=state_machine.current_mission)
25
+
26
+ state_machine.current_mission.status = MissionStatus.InProgress
27
+ state_machine.publish_mission_status()
28
+ state_machine.current_task = state_machine.task_selector.next_task()
29
+ state_machine.send_task_status()
30
+ if state_machine.current_task is None:
31
+ return False
32
+
33
+ state_machine.current_task.status = TaskStatus.InProgress
34
+ state_machine.publish_task_status(task=state_machine.current_task)
35
+ return True
36
+
37
+
38
+ def initialize_robot(state_machine: "StateMachine") -> bool:
39
+ try:
40
+ state_machine.robot.initialize()
41
+ except (RobotInitializeException, RobotException) as e:
42
+ state_machine.current_task.error_message = ErrorMessage(
43
+ error_reason=e.error_reason, error_description=e.error_description
44
+ )
45
+ state_machine.logger.error(
46
+ f"Failed to initialize robot because: {e.error_description}"
47
+ )
48
+ _initialization_failed(state_machine)
49
+ return False
50
+ return True
51
+
52
+
53
+ def set_mission_to_in_progress(state_machine: "StateMachine") -> bool:
54
+ state_machine.current_mission.status = MissionStatus.InProgress
55
+ state_machine.publish_task_status(task=state_machine.current_task)
56
+ state_machine.logger.info(
57
+ f"Successfully initiated "
58
+ f"{type(state_machine.current_task).__name__} "
59
+ f"task: {str(state_machine.current_task.id)[:8]}"
60
+ )
61
+ return True
62
+
63
+
64
+ def trigger_start_mission_or_task_event(state_machine: "StateMachine") -> bool:
65
+ state_machine.queues.state_machine_start_mission.input.put(
66
+ state_machine.current_mission
67
+ )
68
+ return True
69
+
70
+
71
+ def _initialization_failed(state_machine: "StateMachine") -> None:
72
+ state_machine.queues.api_start_mission.output.put(False)
73
+ state_machine._finalize()
@@ -0,0 +1,33 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from isar.state_machine.state_machine import StateMachine
5
+
6
+ from isar.apis.models.models import ControlMissionResponse
7
+ from robot_interface.models.mission.status import MissionStatus, TaskStatus
8
+
9
+
10
+ def stop_mission(state_machine: "StateMachine") -> bool:
11
+ if state_machine.current_mission is None:
12
+ state_machine._queue_empty_response()
13
+ state_machine.reset_state_machine()
14
+ return True
15
+
16
+ state_machine.current_mission.status = MissionStatus.Cancelled
17
+
18
+ for task in state_machine.current_mission.tasks:
19
+ if task.status in [
20
+ TaskStatus.NotStarted,
21
+ TaskStatus.InProgress,
22
+ TaskStatus.Paused,
23
+ ]:
24
+ task.status = TaskStatus.Cancelled
25
+
26
+ stopped_mission_response: ControlMissionResponse = (
27
+ state_machine._make_control_mission_response()
28
+ )
29
+ state_machine.queues.api_stop_mission.output.put(stopped_mission_response)
30
+
31
+ state_machine.publish_task_status(task=state_machine.current_task)
32
+ state_machine._finalize()
33
+ return True
@@ -0,0 +1,10 @@
1
+ from typing import TYPE_CHECKING, Callable
2
+
3
+ if TYPE_CHECKING:
4
+ from isar.state_machine.state_machine import StateMachine
5
+
6
+
7
+ def def_transition(
8
+ state_machine: "StateMachine", transition_function: Callable[["StateMachine"], bool]
9
+ ) -> Callable[[], bool]:
10
+ return lambda: transition_function(state_machine)
@@ -100,7 +100,7 @@ class SlimmStorage(StorageInterface):
100
100
  @staticmethod
101
101
  def _construct_multiform_request_image(
102
102
  filename: str, inspection: Inspection, mission: Mission
103
- ):
103
+ ) -> MultipartEncoder:
104
104
  array_of_orientation = (
105
105
  inspection.metadata.pose.orientation.to_quat_array().tolist()
106
106
  )
@@ -148,7 +148,7 @@ class SlimmStorage(StorageInterface):
148
148
  filename: str,
149
149
  inspection: Inspection,
150
150
  mission: Mission,
151
- ):
151
+ ) -> MultipartEncoder:
152
152
  array_of_orientation = (
153
153
  inspection.metadata.pose.orientation.to_quat_array().tolist()
154
154
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: isar
3
- Version: 1.25.8
3
+ Version: 1.26.0
4
4
  Summary: Integration and Supervisory control of Autonomous Robots
5
5
  Author-email: Equinor ASA <fg_robots_dev@equinor.com>
6
6
  License: Eclipse Public License version 2.0
@@ -127,6 +127,7 @@ Requires-Dist: transitions
127
127
  Requires-Dist: uvicorn
128
128
  Provides-Extra: dev
129
129
  Requires-Dist: black; extra == "dev"
130
+ Requires-Dist: isort; extra == "dev"
130
131
  Requires-Dist: mypy; extra == "dev"
131
132
  Requires-Dist: pip-tools; extra == "dev"
132
133
  Requires-Dist: pre-commit; extra == "dev"
@@ -350,8 +351,6 @@ In general the states
350
351
 
351
352
  ```
352
353
  States.Off,
353
- States.Initialize,
354
- States.Initiate,
355
354
  States.Stop,
356
355
  States.Monitor,
357
356
  States.Paused,