isar 1.26.0__py3-none-any.whl → 1.26.1__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 (33) hide show
  1. isar/apis/models/start_mission_definition.py +0 -4
  2. isar/apis/schedule/scheduling_controller.py +2 -25
  3. isar/config/settings.py +1 -1
  4. isar/models/communication/queues/events.py +57 -0
  5. isar/models/communication/queues/queue_utils.py +18 -13
  6. isar/models/communication/queues/status_queue.py +7 -5
  7. isar/modules.py +26 -13
  8. isar/robot/robot.py +46 -13
  9. isar/robot/robot_start_mission.py +10 -10
  10. isar/robot/robot_status.py +7 -4
  11. isar/robot/robot_stop_mission.py +72 -0
  12. isar/robot/robot_task_status.py +6 -6
  13. isar/script.py +7 -7
  14. isar/services/utilities/scheduling_utilities.py +10 -8
  15. isar/state_machine/state_machine.py +19 -72
  16. isar/state_machine/states/blocked_protective_stop.py +4 -12
  17. isar/state_machine/states/idle.py +45 -25
  18. isar/state_machine/states/monitor.py +127 -90
  19. isar/state_machine/states/offline.py +5 -1
  20. isar/state_machine/states/paused.py +5 -2
  21. isar/state_machine/states/stop.py +29 -58
  22. isar/state_machine/transitions/pause.py +1 -1
  23. isar/state_machine/transitions/resume.py +1 -1
  24. isar/state_machine/transitions/start_mission.py +3 -3
  25. isar/state_machine/transitions/stop.py +9 -2
  26. isar/storage/uploader.py +5 -5
  27. {isar-1.26.0.dist-info → isar-1.26.1.dist-info}/METADATA +4 -17
  28. {isar-1.26.0.dist-info → isar-1.26.1.dist-info}/RECORD +32 -31
  29. {isar-1.26.0.dist-info → isar-1.26.1.dist-info}/WHEEL +1 -1
  30. isar/models/communication/queues/queues.py +0 -37
  31. {isar-1.26.0.dist-info → isar-1.26.1.dist-info}/entry_points.txt +0 -0
  32. {isar-1.26.0.dist-info → isar-1.26.1.dist-info/licenses}/LICENSE +0 -0
  33. {isar-1.26.0.dist-info → isar-1.26.1.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,14 @@
1
1
  import logging
2
2
  import time
3
3
  from copy import deepcopy
4
- from typing import TYPE_CHECKING, Callable, Optional, Tuple
4
+ from queue import Queue
5
+ from typing import TYPE_CHECKING, Optional, Tuple
5
6
 
6
7
  from injector import inject
7
8
  from transitions import State
8
9
 
9
10
  from isar.config.settings import settings
11
+ from isar.models.communication.queues.queue_utils import check_for_event, trigger_event
10
12
  from isar.services.utilities.threaded_request import ThreadedRequest
11
13
  from robot_interface.models.exceptions.robot_exceptions import (
12
14
  ErrorMessage,
@@ -29,6 +31,9 @@ class Monitor(State):
29
31
  self.state_machine: "StateMachine" = state_machine
30
32
 
31
33
  self.logger = logging.getLogger("state_machine")
34
+ self.events = self.state_machine.events
35
+
36
+ self.awaiting_task_status: bool = False
32
37
 
33
38
  def start(self) -> None:
34
39
  self.state_machine.update_state()
@@ -38,109 +43,132 @@ class Monitor(State):
38
43
  self.state_machine.mission_ongoing = False
39
44
  return
40
45
 
41
- def _run(self) -> None:
42
- awaiting_task_status: bool = False
43
- transition: Callable
44
- while True:
45
- if self.state_machine.should_stop_mission():
46
- transition = self.state_machine.stop # type: ignore
47
- break
46
+ def _check_and_handle_stop_mission_event(self, event: Queue) -> bool:
47
+ if check_for_event(event):
48
+ self.state_machine.stop() # type: ignore
49
+ return True
50
+ return False
51
+
52
+ def _check_and_handle_pause_mission_event(self, event: Queue) -> bool:
53
+ if check_for_event(event):
54
+ self.state_machine.pause() # type: ignore
55
+ return True
56
+ return False
57
+
58
+ def _check_and_handle_mission_started_event(self, event: Queue) -> None:
59
+ if not self.state_machine.mission_ongoing:
60
+ if check_for_event(event):
61
+ self.state_machine.mission_ongoing = True
62
+
63
+ def _check_and_handle_mission_failed_event(self, event: Queue) -> bool:
64
+ mission_failed: Optional[ErrorMessage] = check_for_event(event)
65
+ if mission_failed is not None:
66
+ self.state_machine.logger.warning(
67
+ f"Failed to initiate mission "
68
+ f"{str(self.state_machine.current_mission.id)[:8]} because: "
69
+ f"{mission_failed.error_description}"
70
+ )
71
+ self.state_machine.current_mission.error_message = ErrorMessage(
72
+ error_reason=mission_failed.error_reason,
73
+ error_description=mission_failed.error_description,
74
+ )
48
75
 
49
- if self.state_machine.should_pause_mission():
50
- transition = self.state_machine.pause # type: ignore
51
- break
76
+ self.state_machine.mission_failed_to_start() # type: ignore
77
+ return True
78
+ return False
52
79
 
53
- if not self.state_machine.mission_ongoing:
54
- if self.state_machine.get_mission_started_event():
55
- self.state_machine.mission_ongoing = True
56
- else:
57
- time.sleep(settings.FSM_SLEEP_TIME)
58
- continue
59
-
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}"
66
- )
67
- self.state_machine.current_mission.error_message = ErrorMessage(
68
- error_reason=mission_failed.error_reason,
69
- error_description=mission_failed.error_description,
70
- )
80
+ def _check_and_handle_task_status_failed_event(self, event: Queue) -> bool:
81
+ task_failure: Optional[ErrorMessage] = check_for_event(event)
82
+ if task_failure is not None:
83
+ self.awaiting_task_status = False
84
+ self.state_machine.current_task.error_message = task_failure
85
+ self.logger.error(
86
+ f"Monitoring task {self.state_machine.current_task.id[:8]} failed "
87
+ f"because: {task_failure.error_description}"
88
+ )
89
+ return self._handle_new_task_status(TaskStatus.Failed)
90
+ elif not self.awaiting_task_status:
91
+ trigger_event(
92
+ self.events.state_machine_events.task_status_request,
93
+ self.state_machine.current_task.id,
94
+ )
95
+ self.awaiting_task_status = True
96
+ return False
97
+
98
+ def _check_and_handle_task_status_event(self, event: Queue) -> bool:
99
+ status: Optional[TaskStatus] = check_for_event(event)
100
+ if status is not None:
101
+ self.awaiting_task_status = False
102
+ return self._handle_new_task_status(status)
103
+ elif not self.awaiting_task_status:
104
+ trigger_event(
105
+ self.events.state_machine_events.task_status_request,
106
+ self.state_machine.current_task.id,
107
+ )
108
+ self.awaiting_task_status = True
109
+ return False
71
110
 
72
- transition = self.state_machine.mission_failed_to_start # type: ignore
73
- break
111
+ def _handle_new_task_status(self, status: TaskStatus) -> bool:
112
+ if self.state_machine.current_task is None:
113
+ self.state_machine.iterate_current_task()
74
114
 
75
- status: TaskStatus
115
+ self.state_machine.current_task.status = status
76
116
 
77
- task_failure: Optional[ErrorMessage] = (
78
- self.state_machine.get_task_failure_event()
117
+ if self._should_upload_inspections():
118
+ get_inspection_thread = ThreadedRequest(self._queue_inspections_for_upload)
119
+ get_inspection_thread.start_thread(
120
+ deepcopy(self.state_machine.current_mission),
121
+ deepcopy(self.state_machine.current_task),
122
+ name="State Machine Get Inspections",
79
123
  )
80
- if task_failure is not None:
81
- self.state_machine.current_task.error_message = task_failure
82
- self.logger.error(
83
- f"Monitoring task {self.state_machine.current_task.id[:8]} failed "
84
- f"because: {task_failure.error_description}"
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
100
-
101
- if not isinstance(status, TaskStatus):
102
- self.logger.error(
103
- f"Received an invalid status update {status} when monitoring mission. "
104
- "Only TaskStatus is expected."
105
- )
106
- break
107
124
 
125
+ if self.state_machine.current_task.is_finished():
126
+ self._report_task_status(self.state_machine.current_task)
127
+ self.state_machine.publish_task_status(task=self.state_machine.current_task)
128
+
129
+ self.state_machine.iterate_current_task()
108
130
  if self.state_machine.current_task is None:
109
- self.state_machine.iterate_current_task()
131
+ self.state_machine.mission_finished() # type: ignore
132
+ return True
110
133
 
111
- self.state_machine.current_task.status = status
134
+ # Report and update next task
135
+ self.state_machine.current_task.update_task_status()
136
+ self.state_machine.publish_task_status(task=self.state_machine.current_task)
137
+ return False
112
138
 
113
- if (
114
- not settings.UPLOAD_INSPECTIONS_ASYNC
115
- and self._should_upload_inspections()
139
+ def _run(self) -> None:
140
+ self.awaiting_task_status = False
141
+ while True:
142
+ if self._check_and_handle_stop_mission_event(
143
+ self.events.api_requests.stop_mission.input
116
144
  ):
117
- get_inspection_thread = ThreadedRequest(
118
- self._queue_inspections_for_upload
119
- )
120
- get_inspection_thread.start_thread(
121
- deepcopy(self.state_machine.current_mission),
122
- deepcopy(self.state_machine.current_task),
123
- name="State Machine Get Inspections",
124
- )
145
+ break
125
146
 
126
- if self.state_machine.current_task.is_finished():
127
- self._report_task_status(self.state_machine.current_task)
128
- self.state_machine.publish_task_status(
129
- task=self.state_machine.current_task
130
- )
147
+ if self._check_and_handle_pause_mission_event(
148
+ self.events.api_requests.pause_mission.input
149
+ ):
150
+ break
131
151
 
132
- self.state_machine.iterate_current_task()
133
- if self.state_machine.current_task is None:
134
- transition = self.state_machine.mission_finished # type: ignore
135
- break
152
+ self._check_and_handle_mission_started_event(
153
+ self.events.robot_service_events.mission_started
154
+ )
136
155
 
137
- # Report and update next task
138
- self.state_machine.current_task.update_task_status()
139
- self.state_machine.publish_task_status(
140
- task=self.state_machine.current_task
141
- )
156
+ if self._check_and_handle_mission_failed_event(
157
+ self.events.robot_service_events.mission_failed
158
+ ):
159
+ break
160
+
161
+ if self._check_and_handle_task_status_failed_event(
162
+ self.events.robot_service_events.task_status_failed
163
+ ):
164
+ break
165
+
166
+ if self._check_and_handle_task_status_event(
167
+ self.events.robot_service_events.task_status_updated
168
+ ):
169
+ break
142
170
 
143
- transition()
171
+ time.sleep(settings.FSM_SLEEP_TIME)
144
172
 
145
173
  def _queue_inspections_for_upload(
146
174
  self, mission: Mission, current_task: InspectionTask
@@ -163,6 +191,12 @@ class Monitor(State):
163
191
  )
164
192
  return
165
193
 
194
+ except Exception as e:
195
+ self.logger.error(
196
+ f"Failed to retrieve inspections because of unexpected error: {e}"
197
+ )
198
+ return
199
+
166
200
  if not inspection:
167
201
  self.logger.warning(
168
202
  f"No inspection result data retrieved for task {str(current_task.id)[:8]}"
@@ -174,7 +208,7 @@ class Monitor(State):
174
208
  inspection,
175
209
  mission,
176
210
  )
177
- self.state_machine.queues.upload_queue.put(message)
211
+ self.state_machine.events.upload_queue.put(message)
178
212
  self.logger.info(
179
213
  f"Inspection result: {str(inspection.id)[:8]} queued for upload"
180
214
  )
@@ -190,6 +224,9 @@ class Monitor(State):
190
224
  )
191
225
 
192
226
  def _should_upload_inspections(self) -> bool:
227
+ if settings.UPLOAD_INSPECTIONS_ASYNC:
228
+ return False
229
+
193
230
  return (
194
231
  self.state_machine.current_task.is_finished()
195
232
  and self.state_machine.current_task.status == TaskStatus.Successful
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING
4
4
 
5
5
  from transitions import State
6
6
 
7
+ from isar.models.communication.queues.queue_utils import check_shared_state
7
8
  from robot_interface.models.mission.status import RobotStatus
8
9
 
9
10
  if TYPE_CHECKING:
@@ -15,6 +16,7 @@ class Offline(State):
15
16
  super().__init__(name="offline", on_enter=self.start, on_exit=self.stop)
16
17
  self.state_machine: "StateMachine" = state_machine
17
18
  self.logger = logging.getLogger("state_machine")
19
+ self.shared_state = self.state_machine.shared_state
18
20
 
19
21
  def start(self) -> None:
20
22
  self.state_machine.update_state()
@@ -25,7 +27,9 @@ class Offline(State):
25
27
 
26
28
  def _run(self) -> None:
27
29
  while True:
28
- robot_status = self.state_machine.get_robot_status()
30
+ robot_status: RobotStatus = check_shared_state(
31
+ self.shared_state.robot_status
32
+ )
29
33
  if robot_status == RobotStatus.BlockedProtectiveStop:
30
34
  transition = self.state_machine.robot_protective_stop_engaged # type: ignore
31
35
  break
@@ -4,6 +4,8 @@ from typing import TYPE_CHECKING, Callable
4
4
 
5
5
  from transitions import State
6
6
 
7
+ from isar.models.communication.queues.queue_utils import check_for_event
8
+
7
9
  if TYPE_CHECKING:
8
10
  from isar.state_machine.state_machine import StateMachine
9
11
 
@@ -13,6 +15,7 @@ class Paused(State):
13
15
  super().__init__(name="paused", on_enter=self.start)
14
16
  self.state_machine: "StateMachine" = state_machine
15
17
  self.logger = logging.getLogger("state_machine")
18
+ self.events = self.state_machine.events
16
19
 
17
20
  def start(self) -> None:
18
21
  self.state_machine.update_state()
@@ -21,11 +24,11 @@ class Paused(State):
21
24
  def _run(self) -> None:
22
25
  transition: Callable
23
26
  while True:
24
- if self.state_machine.should_stop_mission():
27
+ if check_for_event(self.events.api_requests.pause_mission.input):
25
28
  transition = self.state_machine.stop # type: ignore
26
29
  break
27
30
 
28
- if self.state_machine.should_resume_mission():
31
+ if check_for_event(self.events.api_requests.resume_mission.input):
29
32
  transition = self.state_machine.resume # type: ignore
30
33
  break
31
34
 
@@ -1,18 +1,13 @@
1
1
  import logging
2
2
  import time
3
- from typing import TYPE_CHECKING, Callable, Optional
3
+ from queue import Queue
4
+ from typing import TYPE_CHECKING, Optional
4
5
 
5
6
  from transitions import State
6
7
 
7
- from isar.services.utilities.threaded_request import (
8
- ThreadedRequest,
9
- ThreadedRequestNotFinishedError,
10
- )
11
- from robot_interface.models.exceptions.robot_exceptions import (
12
- ErrorMessage,
13
- RobotActionException,
14
- RobotException,
15
- )
8
+ from isar.models.communication.queues.queue_utils import check_for_event
9
+ from isar.services.utilities.threaded_request import ThreadedRequest
10
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
16
11
 
17
12
  if TYPE_CHECKING:
18
13
  from isar.state_machine.state_machine import StateMachine
@@ -23,6 +18,7 @@ class Stop(State):
23
18
  super().__init__(name="stop", on_enter=self.start, on_exit=self.stop)
24
19
  self.state_machine: "StateMachine" = state_machine
25
20
  self.logger = logging.getLogger("state_machine")
21
+ self.events = self.state_machine.events
26
22
  self.stop_thread: Optional[ThreadedRequest] = None
27
23
  self._count_number_retries: int = 0
28
24
 
@@ -36,56 +32,31 @@ class Stop(State):
36
32
  self.stop_thread = None
37
33
  self._count_number_retries = 0
38
34
 
39
- def _run(self) -> None:
40
- transition: Callable
41
- while True:
42
- if not self.stop_thread:
43
- self.stop_thread = ThreadedRequest(self.state_machine.robot.stop)
44
- self.stop_thread.start_thread(name="State Machine Stop Robot")
45
-
46
- try:
47
- self.stop_thread.get_output()
48
- except ThreadedRequestNotFinishedError:
49
- time.sleep(self.state_machine.sleep_time)
50
- continue
51
-
52
- except (RobotActionException, RobotException) as e:
53
- if self.handle_stop_fail(
54
- retry_limit=self.state_machine.stop_robot_attempts_limit,
55
- error_message=ErrorMessage(
56
- error_reason=e.error_reason,
57
- error_description=e.error_description,
58
- ),
59
- ):
60
- transition = self.state_machine.mission_stopped # type: ignore
61
- break
62
-
63
- self.logger.warning(
64
- f"\nFailed to stop robot because: {e.error_description}"
65
- f"\nAttempting to stop the robot again"
66
- )
67
-
68
- self.stop_thread = None
69
- continue
70
-
71
- transition = self.state_machine.mission_stopped # type: ignore
35
+ def _check_and_handle_failed_stop(self, event: Queue[ErrorMessage]) -> bool:
36
+ error_message: Optional[ErrorMessage] = check_for_event(event)
37
+ if error_message is not None:
38
+ self.logger.warning(error_message.error_description)
39
+ self.state_machine.mission_stopped() # type: ignore
40
+ return True
41
+ return False
72
42
 
73
- break
43
+ def _check_and_handle_successful_stop(self, event: Queue[bool]) -> bool:
44
+ if check_for_event(event):
45
+ self.state_machine.mission_stopped() # type: ignore
46
+ return True
47
+ return False
74
48
 
75
- transition()
49
+ def _run(self) -> None:
50
+ while True:
76
51
 
77
- def handle_stop_fail(self, retry_limit: int, error_message: ErrorMessage) -> bool:
78
- self._count_number_retries += 1
79
- if self._count_number_retries > retry_limit:
80
- self.state_machine.current_task.error_message = error_message
52
+ if self._check_and_handle_failed_stop(
53
+ self.events.robot_service_events.mission_failed_to_stop
54
+ ):
55
+ break
81
56
 
82
- self.logger.error(
83
- f"\nFailed to stop the robot after {retry_limit} attempts because: "
84
- f"{error_message.error_description}"
85
- f"\nBe aware that the robot may still be moving even though a stop has "
86
- "been attempted"
87
- )
57
+ if self._check_and_handle_successful_stop(
58
+ self.events.robot_service_events.mission_successfully_stopped
59
+ ):
60
+ break
88
61
 
89
- return True
90
- time.sleep(self.state_machine.sleep_time)
91
- return False
62
+ time.sleep(self.state_machine.sleep_time)
@@ -15,7 +15,7 @@ def pause_mission(state_machine: "StateMachine") -> bool:
15
15
  paused_mission_response: ControlMissionResponse = (
16
16
  state_machine._make_control_mission_response()
17
17
  )
18
- state_machine.queues.api_pause_mission.output.put(paused_mission_response)
18
+ state_machine.events.api_requests.pause_mission.output.put(paused_mission_response)
19
19
 
20
20
  state_machine.publish_mission_status()
21
21
  state_machine.publish_task_status(task=state_machine.current_task)
@@ -21,7 +21,7 @@ def resume_mission(state_machine: "StateMachine") -> bool:
21
21
  resume_mission_response: ControlMissionResponse = (
22
22
  state_machine._make_control_mission_response()
23
23
  )
24
- state_machine.queues.api_resume_mission.output.put(resume_mission_response)
24
+ state_machine.events.api_requests.resume_mission.output.put(resume_mission_response)
25
25
 
26
26
  state_machine.robot.resume()
27
27
  return True
@@ -12,7 +12,7 @@ from robot_interface.models.mission.status import MissionStatus, TaskStatus
12
12
 
13
13
 
14
14
  def put_start_mission_on_queue(state_machine: "StateMachine") -> bool:
15
- state_machine.queues.api_start_mission.output.put(True)
15
+ state_machine.events.api_requests.start_mission.output.put(True)
16
16
  return True
17
17
 
18
18
 
@@ -62,12 +62,12 @@ def set_mission_to_in_progress(state_machine: "StateMachine") -> bool:
62
62
 
63
63
 
64
64
  def trigger_start_mission_or_task_event(state_machine: "StateMachine") -> bool:
65
- state_machine.queues.state_machine_start_mission.input.put(
65
+ state_machine.events.state_machine_events.start_mission.put(
66
66
  state_machine.current_mission
67
67
  )
68
68
  return True
69
69
 
70
70
 
71
71
  def _initialization_failed(state_machine: "StateMachine") -> None:
72
- state_machine.queues.api_start_mission.output.put(False)
72
+ state_machine.events.api_requests.start_mission.output.put(False)
73
73
  state_machine._finalize()
@@ -1,5 +1,7 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
+ from isar.models.communication.queues.queue_utils import trigger_event_without_data
4
+
3
5
  if TYPE_CHECKING:
4
6
  from isar.state_machine.state_machine import StateMachine
5
7
 
@@ -7,7 +9,12 @@ from isar.apis.models.models import ControlMissionResponse
7
9
  from robot_interface.models.mission.status import MissionStatus, TaskStatus
8
10
 
9
11
 
10
- def stop_mission(state_machine: "StateMachine") -> bool:
12
+ def trigger_stop_mission_event(state_machine: "StateMachine") -> bool:
13
+ trigger_event_without_data(state_machine.events.state_machine_events.stop_mission)
14
+ return True
15
+
16
+
17
+ def stop_mission_cleanup(state_machine: "StateMachine") -> bool:
11
18
  if state_machine.current_mission is None:
12
19
  state_machine._queue_empty_response()
13
20
  state_machine.reset_state_machine()
@@ -26,7 +33,7 @@ def stop_mission(state_machine: "StateMachine") -> bool:
26
33
  stopped_mission_response: ControlMissionResponse = (
27
34
  state_machine._make_control_mission_response()
28
35
  )
29
- state_machine.queues.api_stop_mission.output.put(stopped_mission_response)
36
+ state_machine.events.api_requests.stop_mission.output.put(stopped_mission_response)
30
37
 
31
38
  state_machine.publish_task_status(task=state_machine.current_task)
32
39
  state_machine._finalize()
isar/storage/uploader.py CHANGED
@@ -8,7 +8,7 @@ from typing import List, Union
8
8
  from injector import inject
9
9
 
10
10
  from isar.config.settings import settings
11
- from isar.models.communication.queues.queues import Queues
11
+ from isar.models.communication.queues.events import Events
12
12
  from isar.storage.storage_interface import StorageException, StorageInterface
13
13
  from robot_interface.models.inspection.inspection import Inspection
14
14
  from robot_interface.models.mission.mission import Mission
@@ -48,7 +48,7 @@ class Uploader:
48
48
  @inject
49
49
  def __init__(
50
50
  self,
51
- queues: Queues,
51
+ events: Events,
52
52
  storage_handlers: List[StorageInterface],
53
53
  mqtt_publisher: MqttClientInterface,
54
54
  max_wait_time: int = settings.UPLOAD_FAILURE_MAX_WAIT,
@@ -58,8 +58,8 @@ class Uploader:
58
58
 
59
59
  Parameters
60
60
  ----------
61
- queues : Queues
62
- Queues used for cross-thread communication.
61
+ events : Events
62
+ Events used for cross-thread communication.
63
63
  storage_handlers : List[StorageInterface]
64
64
  List of handlers for different upload options
65
65
  max_wait_time : float
@@ -67,7 +67,7 @@ class Uploader:
67
67
  max_retry_attempts : int
68
68
  Maximum attempts to retry an upload when it fails
69
69
  """
70
- self.upload_queue: Queue = queues.upload_queue
70
+ self.upload_queue: Queue = events.upload_queue
71
71
  self.storage_handlers: List[StorageInterface] = storage_handlers
72
72
  self.mqtt_publisher = mqtt_publisher
73
73
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: isar
3
- Version: 1.26.0
3
+ Version: 1.26.1
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
@@ -95,6 +95,7 @@ Classifier: Programming Language :: Python :: 3.9
95
95
  Classifier: Programming Language :: Python :: 3.10
96
96
  Classifier: Programming Language :: Python :: 3.11
97
97
  Classifier: Programming Language :: Python :: 3.12
98
+ Classifier: Programming Language :: Python :: 3.13
98
99
  Classifier: Topic :: Scientific/Engineering
99
100
  Classifier: Topic :: Scientific/Engineering :: Physics
100
101
  Classifier: Topic :: Software Development :: Libraries
@@ -137,6 +138,7 @@ Requires-Dist: pytest-xdist; extra == "dev"
137
138
  Requires-Dist: pytest; extra == "dev"
138
139
  Requires-Dist: requests-mock; extra == "dev"
139
140
  Requires-Dist: ruff; extra == "dev"
141
+ Dynamic: license-file
140
142
 
141
143
  # ISAR
142
144
 
@@ -254,21 +256,6 @@ In [this](./src/isar/config/predefined_missions) folder there are predefined def
254
256
  corresponding to `mission_id=1`. A new mission may be added by adding a new json-file with a mission description. Note,
255
257
  the mission IDs must be unique.
256
258
 
257
- ### Running with docker-compose
258
-
259
- ISAR may be started with an instance of the [isar-robot](https://github.com/equinor/isar-robot) package by
260
-
261
- ```shell
262
- docker-compose up --build
263
- ```
264
-
265
- Provided that the simulator from [isar-turtlebot](https://github.com/equinor/isar-turtlebot) is running ISAR may be
266
- started with the turtlebot by
267
-
268
- ```shell
269
- docker-compose -f docker-compose-turtlebot.yml up --build
270
- ```
271
-
272
259
  ### Configuration
273
260
 
274
261
  The system consists of many configuration variables which may alter the functionality. As an example, it is possible to