isar 1.31.0__py3-none-any.whl → 1.31.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 (46) hide show
  1. isar/config/open_telemetry.py +2 -8
  2. isar/eventhandlers/eventhandler.py +93 -0
  3. isar/models/events.py +118 -0
  4. isar/modules.py +1 -1
  5. isar/robot/robot.py +16 -18
  6. isar/robot/robot_start_mission.py +8 -14
  7. isar/robot/robot_status.py +2 -3
  8. isar/robot/robot_stop_mission.py +3 -9
  9. isar/robot/robot_task_status.py +3 -7
  10. isar/script.py +2 -1
  11. isar/services/utilities/scheduling_utilities.py +26 -24
  12. isar/state_machine/state_machine.py +79 -9
  13. isar/state_machine/states/await_next_mission.py +46 -11
  14. isar/state_machine/states/blocked_protective_stop.py +24 -15
  15. isar/state_machine/states/home.py +40 -9
  16. isar/state_machine/states/monitor.py +83 -12
  17. isar/state_machine/states/offline.py +25 -13
  18. isar/state_machine/states/paused.py +24 -38
  19. isar/state_machine/states/returning_home.py +75 -14
  20. isar/state_machine/states/robot_standing_still.py +41 -11
  21. isar/state_machine/states/stopping.py +52 -67
  22. isar/state_machine/states/unknown_status.py +37 -64
  23. isar/state_machine/transitions/functions/robot_status.py +4 -5
  24. isar/state_machine/transitions/functions/stop.py +3 -12
  25. isar/state_machine/utils/common_event_handlers.py +166 -0
  26. isar/storage/uploader.py +1 -1
  27. {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/METADATA +1 -1
  28. {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/RECORD +32 -43
  29. isar/models/communication/__init__.py +0 -0
  30. isar/models/communication/message.py +0 -8
  31. isar/models/communication/queues/__init__.py +0 -0
  32. isar/models/communication/queues/events.py +0 -58
  33. isar/models/communication/queues/queue_io.py +0 -12
  34. isar/models/communication/queues/queue_timeout_error.py +0 -2
  35. isar/models/communication/queues/queue_utils.py +0 -38
  36. isar/models/communication/queues/status_queue.py +0 -22
  37. isar/models/mission_metadata/__init__.py +0 -0
  38. isar/services/service_connections/stid/__init__.py +0 -0
  39. isar/services/utilities/queue_utilities.py +0 -39
  40. isar/state_machine/generic_states/idle.py +0 -133
  41. isar/state_machine/generic_states/ongoing_mission.py +0 -309
  42. isar/state_machine/generic_states/robot_unavailable.py +0 -61
  43. {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/WHEEL +0 -0
  44. {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/entry_points.txt +0 -0
  45. {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/licenses/LICENSE +0 -0
  46. {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,50 @@
1
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, List
2
2
 
3
- from transitions import State
3
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
4
+ from isar.state_machine.utils.common_event_handlers import (
5
+ return_home_event_handler,
6
+ robot_status_event_handler,
7
+ start_mission_event_handler,
8
+ stop_mission_event_handler,
9
+ )
10
+ from robot_interface.models.mission.status import RobotStatus
4
11
 
5
12
  if TYPE_CHECKING:
6
13
  from isar.state_machine.state_machine import StateMachine
7
14
 
8
- from isar.state_machine.generic_states.idle import Idle, IdleStates
9
15
 
16
+ class RobotStandingStill(EventHandlerBase):
10
17
 
11
- class RobotStandingStill(State, Idle):
12
- def __init__(self, state_machine: "StateMachine") -> None:
13
- State.__init__(
14
- self, name="robot_standing_still", on_enter=self.start, on_exit=self.stop
15
- )
16
- Idle.__init__(
17
- self,
18
+ def __init__(self, state_machine: "StateMachine"):
19
+ events = state_machine.events
20
+ shared_state = state_machine.shared_state
21
+
22
+ event_handlers: List[EventHandlerMapping] = [
23
+ EventHandlerMapping(
24
+ name="start_mission_event",
25
+ event=events.api_requests.start_mission.input,
26
+ handler=lambda event: start_mission_event_handler(state_machine, event),
27
+ ),
28
+ EventHandlerMapping(
29
+ name="return_home_event",
30
+ event=events.api_requests.return_home.input,
31
+ handler=lambda event: return_home_event_handler(state_machine, event),
32
+ ),
33
+ EventHandlerMapping(
34
+ name="stop_mission_event",
35
+ event=events.api_requests.return_home.input,
36
+ handler=lambda event: stop_mission_event_handler(state_machine, event),
37
+ ),
38
+ EventHandlerMapping(
39
+ name="robot_status_event",
40
+ event=shared_state.robot_status,
41
+ handler=lambda event: robot_status_event_handler(
42
+ state_machine, RobotStatus.Available, event
43
+ ),
44
+ ),
45
+ ]
46
+ super().__init__(
47
+ state_name="robot_standing_still",
18
48
  state_machine=state_machine,
19
- state=IdleStates.RobotStandingStill,
49
+ event_handler_mappings=event_handlers,
20
50
  )
@@ -1,75 +1,60 @@
1
1
  import logging
2
- import time
3
- from queue import Queue
4
- from typing import TYPE_CHECKING, Optional
2
+ from typing import TYPE_CHECKING, Callable, List, Optional
5
3
 
6
- from transitions import State
7
-
8
- from isar.models.communication.queues.queue_utils import check_for_event
4
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
5
+ from isar.models.events import Event
9
6
  from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
10
7
 
11
8
  if TYPE_CHECKING:
12
9
  from isar.state_machine.state_machine import StateMachine
13
10
 
14
11
 
15
- class Stopping(State):
16
- def __init__(self, state_machine: "StateMachine") -> None:
17
- super().__init__(name="stopping", on_enter=self.start, on_exit=self.stop)
18
- self.state_machine: "StateMachine" = state_machine
19
- self.logger = logging.getLogger("state_machine")
20
- self.events = self.state_machine.events
21
- self._count_number_retries: int = 0
22
- self.signal_state_machine_to_stop = state_machine.signal_state_machine_to_stop
23
- self.stopping_return_home_mission: bool = False
24
-
25
- def start(self) -> None:
26
- self.state_machine.update_state()
27
- if self.state_machine.current_mission is not None:
28
- self.stopping_return_home_mission = (
29
- self.state_machine.current_mission._is_return_to_home_mission()
30
- )
31
- self._run()
32
-
33
- def stop(self) -> None:
34
- self._count_number_retries = 0
35
- self.stopping_return_home_mission = False
36
-
37
- def _check_and_handle_failed_stop(self, event: Queue[ErrorMessage]) -> bool:
38
- error_message: Optional[ErrorMessage] = check_for_event(event)
39
- if error_message is not None:
40
- self.logger.warning(error_message.error_description)
41
- if self.stopping_return_home_mission:
42
- self.state_machine.return_home_mission_stopping_failed() # type: ignore
43
- else:
44
- self.state_machine.mission_stopping_failed() # type: ignore
45
- return True
46
- return False
47
-
48
- def _check_and_handle_successful_stop(self, event: Queue[bool]) -> bool:
49
- if check_for_event(event):
50
- if self.stopping_return_home_mission:
51
- self.state_machine.return_home_mission_stopped() # type: ignore
52
- else:
53
- self.state_machine.mission_stopped() # type: ignore
54
- return True
55
- return False
56
-
57
- def _run(self) -> None:
58
- while True:
59
- if self.signal_state_machine_to_stop.is_set():
60
- self.logger.info(
61
- "Stopping state machine from %s state", self.__class__.__name__
62
- )
63
- break
64
-
65
- if self._check_and_handle_failed_stop(
66
- self.events.robot_service_events.mission_failed_to_stop
67
- ):
68
- break
69
-
70
- if self._check_and_handle_successful_stop(
71
- self.events.robot_service_events.mission_successfully_stopped
72
- ):
73
- break
74
-
75
- time.sleep(self.state_machine.sleep_time)
12
+ class Stopping(EventHandlerBase):
13
+
14
+ def __init__(self, state_machine: "StateMachine"):
15
+ logger = logging.getLogger("state_machine")
16
+ events = state_machine.events
17
+
18
+ def _failed_stop_event_handler(
19
+ event: Event[ErrorMessage],
20
+ ) -> Optional[Callable]:
21
+ error_message: Optional[ErrorMessage] = event.consume_event()
22
+ if error_message is not None:
23
+ logger.warning(error_message.error_description)
24
+ if (
25
+ state_machine.current_mission is not None
26
+ and state_machine.current_mission._is_return_to_home_mission()
27
+ ):
28
+ return state_machine.return_home_mission_stopping_failed # type: ignore
29
+ else:
30
+ return state_machine.mission_stopping_failed # type: ignore
31
+ return None
32
+
33
+ def _successful_stop_event_handler(event: Event[bool]) -> Optional[Callable]:
34
+ if event.consume_event():
35
+ if (
36
+ state_machine.current_mission is not None
37
+ and state_machine.current_mission._is_return_to_home_mission()
38
+ ):
39
+ return state_machine.return_home_mission_stopped # type: ignore
40
+ else:
41
+ return state_machine.mission_stopped # type: ignore
42
+ return None
43
+
44
+ event_handlers: List[EventHandlerMapping] = [
45
+ EventHandlerMapping(
46
+ name="failed_stop_event",
47
+ event=events.robot_service_events.mission_failed_to_stop,
48
+ handler=_failed_stop_event_handler,
49
+ ),
50
+ EventHandlerMapping(
51
+ name="successful_stop_event",
52
+ event=events.robot_service_events.mission_successfully_stopped,
53
+ handler=_successful_stop_event_handler,
54
+ ),
55
+ ]
56
+ super().__init__(
57
+ state_name="stopping",
58
+ state_machine=state_machine,
59
+ event_handler_mappings=event_handlers,
60
+ )
@@ -1,74 +1,47 @@
1
- import logging
2
- import time
3
- from queue import Queue
4
- from typing import TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
5
2
 
6
- from transitions import State
7
-
8
- from isar.models.communication.queues.queue_utils import (
9
- check_for_event,
10
- check_shared_state,
11
- )
12
- from isar.models.communication.queues.status_queue import StatusQueue
3
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
4
+ from isar.models.events import Event
5
+ from isar.state_machine.utils.common_event_handlers import stop_mission_event_handler
13
6
  from robot_interface.models.mission.status import RobotStatus
14
7
 
15
8
  if TYPE_CHECKING:
16
9
  from isar.state_machine.state_machine import StateMachine
17
10
 
18
11
 
19
- class UnknownStatus(State):
20
- def __init__(self, state_machine: "StateMachine") -> None:
21
- super().__init__(name="unknown_status", on_enter=self.start, on_exit=self.stop)
22
- self.state_machine: "StateMachine" = state_machine
23
- self.logger = logging.getLogger("state_machine")
24
- self.events = self.state_machine.events
25
- self.shared_state = self.state_machine.shared_state
26
- self.signal_state_machine_to_stop = state_machine.signal_state_machine_to_stop
27
-
28
- def start(self) -> None:
29
- self.state_machine.update_state()
30
- self._run()
31
-
32
- def stop(self) -> None:
33
- return
34
-
35
- def _check_and_handle_stop_mission_event(self, event: Queue) -> bool:
36
- if check_for_event(event) is not None:
37
- self.state_machine.stop() # type: ignore
38
- return True
39
- return False
40
-
41
- def _check_and_handle_robot_status_event(
42
- self, event: StatusQueue[RobotStatus]
43
- ) -> bool:
44
- robot_status: RobotStatus = check_shared_state(event)
45
- if (
46
- robot_status == RobotStatus.Home
47
- or robot_status == RobotStatus.Offline
48
- or robot_status == RobotStatus.BlockedProtectiveStop
49
- or robot_status == RobotStatus.Available
50
- ):
51
- self.state_machine.robot_status_changed() # type: ignore
52
- return True
12
+ class UnknownStatus(EventHandlerBase):
53
13
 
54
- return False
14
+ def __init__(self, state_machine: "StateMachine"):
15
+ events = state_machine.events
16
+ shared_state = state_machine.shared_state
55
17
 
56
- def _run(self) -> None:
57
- while True:
58
- if self.signal_state_machine_to_stop.is_set():
59
- self.logger.info(
60
- "Stopping state machine from %s state", self.__class__.__name__
61
- )
62
- break
63
-
64
- if self._check_and_handle_stop_mission_event(
65
- self.events.api_requests.stop_mission.input
66
- ):
67
- break
68
-
69
- if self._check_and_handle_robot_status_event(
70
- self.shared_state.robot_status
18
+ def _robot_status_event_handler(
19
+ event: Event[RobotStatus],
20
+ ) -> Optional[Callable]:
21
+ robot_status: RobotStatus = event.check()
22
+ if (
23
+ robot_status == RobotStatus.Home
24
+ or robot_status == RobotStatus.Offline
25
+ or robot_status == RobotStatus.BlockedProtectiveStop
26
+ or robot_status == RobotStatus.Available
71
27
  ):
72
- break
73
-
74
- time.sleep(self.state_machine.sleep_time)
28
+ return state_machine.robot_status_changed # type: ignore
29
+ return None
30
+
31
+ event_handlers: List[EventHandlerMapping] = [
32
+ EventHandlerMapping(
33
+ name="stop_mission_event",
34
+ event=events.api_requests.stop_mission.input,
35
+ handler=lambda event: stop_mission_event_handler(state_machine, event),
36
+ ),
37
+ EventHandlerMapping(
38
+ name="robot_status_event",
39
+ event=shared_state.robot_status,
40
+ handler=_robot_status_event_handler,
41
+ ),
42
+ ]
43
+ super().__init__(
44
+ state_name="unknown_status",
45
+ state_machine=state_machine,
46
+ event_handler_mappings=event_handlers,
47
+ )
@@ -1,6 +1,5 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
- from isar.models.communication.queues.queue_utils import check_shared_state
4
3
  from robot_interface.models.mission.status import RobotStatus
5
4
 
6
5
  if TYPE_CHECKING:
@@ -8,20 +7,20 @@ if TYPE_CHECKING:
8
7
 
9
8
 
10
9
  def is_offline(state_machine: "StateMachine") -> bool:
11
- robot_status = check_shared_state(state_machine.shared_state.robot_status)
10
+ robot_status = state_machine.shared_state.robot_status.check()
12
11
  return robot_status == RobotStatus.Offline
13
12
 
14
13
 
15
14
  def is_available(state_machine: "StateMachine") -> bool:
16
- robot_status = check_shared_state(state_machine.shared_state.robot_status)
15
+ robot_status = state_machine.shared_state.robot_status.check()
17
16
  return robot_status == RobotStatus.Available
18
17
 
19
18
 
20
19
  def is_home(state_machine: "StateMachine") -> bool:
21
- robot_status = check_shared_state(state_machine.shared_state.robot_status)
20
+ robot_status = state_machine.shared_state.robot_status.check()
22
21
  return robot_status == RobotStatus.Home
23
22
 
24
23
 
25
24
  def is_blocked_protective_stop(state_machine: "StateMachine") -> bool:
26
- robot_status = check_shared_state(state_machine.shared_state.robot_status)
25
+ robot_status = state_machine.shared_state.robot_status.check()
27
26
  return robot_status == RobotStatus.BlockedProtectiveStop
@@ -1,10 +1,5 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
- from isar.models.communication.queues.queue_utils import (
4
- check_for_event_without_consumption,
5
- trigger_event_without_data,
6
- )
7
-
8
3
  if TYPE_CHECKING:
9
4
  from isar.state_machine.state_machine import StateMachine
10
5
 
@@ -13,7 +8,7 @@ from robot_interface.models.mission.status import MissionStatus, TaskStatus
13
8
 
14
9
 
15
10
  def trigger_stop_mission_event(state_machine: "StateMachine") -> bool:
16
- trigger_event_without_data(state_machine.events.state_machine_events.stop_mission)
11
+ state_machine.events.state_machine_events.stop_mission.trigger_event(True)
17
12
  return True
18
13
 
19
14
 
@@ -56,9 +51,7 @@ def stop_return_home_mission_cleanup(state_machine: "StateMachine") -> bool:
56
51
  state_machine.reset_state_machine()
57
52
  return True
58
53
 
59
- if not check_for_event_without_consumption(
60
- state_machine.events.api_requests.start_mission.input
61
- ):
54
+ if not state_machine.events.api_requests.start_mission.input.has_event():
62
55
  state_machine.current_mission.status = MissionStatus.Cancelled
63
56
 
64
57
  for task in state_machine.current_mission.tasks:
@@ -81,9 +74,7 @@ def stop_return_home_mission_cleanup(state_machine: "StateMachine") -> bool:
81
74
 
82
75
 
83
76
  def stop_return_home_mission_failed(state_machine: "StateMachine") -> bool:
84
- if check_for_event_without_consumption(
85
- state_machine.events.api_requests.start_mission.input
86
- ):
77
+ if state_machine.events.api_requests.start_mission.input.has_event():
87
78
  return True
88
79
  stopped_mission_response: ControlMissionResponse = (
89
80
  state_machine._make_control_mission_response()
@@ -0,0 +1,166 @@
1
+ from typing import TYPE_CHECKING, Callable, Optional
2
+
3
+ from isar.apis.models.models import ControlMissionResponse
4
+ from isar.models.events import Event
5
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
6
+ from robot_interface.models.mission.mission import Mission
7
+ from robot_interface.models.mission.status import RobotStatus, TaskStatus
8
+
9
+ if TYPE_CHECKING:
10
+ from isar.state_machine.state_machine import StateMachine
11
+
12
+
13
+ def start_mission_event_handler(
14
+ state_machine: "StateMachine", event: Event[Mission]
15
+ ) -> Optional[Callable]:
16
+ mission: Optional[Mission] = event.consume_event()
17
+ if mission:
18
+ state_machine.start_mission(mission=mission)
19
+ return state_machine.request_mission_start # type: ignore
20
+ return None
21
+
22
+
23
+ def return_home_event_handler(
24
+ state_machine: "StateMachine", event: Event[bool]
25
+ ) -> Optional[Callable]:
26
+ if event.consume_event():
27
+ state_machine.events.api_requests.return_home.output.put(True)
28
+ return state_machine.request_return_home # type: ignore
29
+ return None
30
+
31
+
32
+ def robot_status_event_handler(
33
+ state_machine: "StateMachine",
34
+ expected_status: RobotStatus,
35
+ event: Event[RobotStatus],
36
+ ) -> Optional[Callable]:
37
+ robot_status: RobotStatus = event.check()
38
+ if robot_status != expected_status:
39
+ return state_machine.robot_status_changed # type: ignore
40
+ return None
41
+
42
+
43
+ def stop_mission_event_handler(
44
+ state_machine: "StateMachine", event: Event[str]
45
+ ) -> Optional[Callable]:
46
+ mission_id: str = event.consume_event()
47
+ if mission_id is not None:
48
+ if state_machine.current_mission.id == mission_id or mission_id == "":
49
+ return state_machine.stop # type: ignore
50
+ else:
51
+ state_machine.events.api_requests.stop_mission.output.put(
52
+ ControlMissionResponse(
53
+ mission_id=mission_id,
54
+ mission_status=state_machine.current_mission.status,
55
+ mission_not_found=True,
56
+ task_id=state_machine.current_task.id,
57
+ task_status=state_machine.current_task.status,
58
+ )
59
+ )
60
+ return None
61
+
62
+
63
+ def mission_started_event_handler(
64
+ state_machine: "StateMachine",
65
+ event: Event[bool],
66
+ ) -> Optional[Callable]:
67
+ if event.consume_event():
68
+ state_machine.mission_ongoing = True
69
+ return None
70
+
71
+
72
+ def mission_failed_event_handler(
73
+ state_machine: "StateMachine",
74
+ event: Event[Optional[ErrorMessage]],
75
+ ) -> Optional[Callable]:
76
+ mission_failed: Optional[ErrorMessage] = event.consume_event()
77
+ if mission_failed is not None:
78
+ state_machine.logger.warning(
79
+ f"Failed to initiate mission "
80
+ f"{str(state_machine.current_mission.id)[:8]} because: "
81
+ f"{mission_failed.error_description}"
82
+ )
83
+ state_machine.current_mission.error_message = ErrorMessage(
84
+ error_reason=mission_failed.error_reason,
85
+ error_description=mission_failed.error_description,
86
+ )
87
+ return state_machine.mission_failed_to_start # type: ignore
88
+ return None
89
+
90
+
91
+ def task_status_failed_event_handler(
92
+ state_machine: "StateMachine",
93
+ handle_task_completed: Callable[[TaskStatus], Callable],
94
+ event: Event[Optional[ErrorMessage]],
95
+ ) -> Optional[Callable]:
96
+ if not state_machine.mission_ongoing:
97
+ return None
98
+
99
+ task_failure: Optional[ErrorMessage] = event.consume_event()
100
+ if task_failure is not None:
101
+ if state_machine.current_task is None:
102
+ state_machine.logger.warning(
103
+ "Received task status failed event when no task was running"
104
+ )
105
+ return None
106
+ state_machine.awaiting_task_status = False
107
+ state_machine.current_task.error_message = task_failure
108
+ state_machine.logger.error(
109
+ f"Monitoring task {state_machine.current_task.id[:8]} failed "
110
+ f"because: {task_failure.error_description}"
111
+ )
112
+ return _handle_new_task_status(
113
+ state_machine, handle_task_completed, TaskStatus.Failed
114
+ )
115
+
116
+ elif (
117
+ not state_machine.awaiting_task_status
118
+ and state_machine.current_task is not None
119
+ ):
120
+ state_machine.events.state_machine_events.task_status_request.trigger_event(
121
+ state_machine.current_task.id,
122
+ )
123
+ state_machine.awaiting_task_status = True
124
+ return None
125
+
126
+
127
+ def task_status_event_handler(
128
+ state_machine: "StateMachine",
129
+ handle_task_completed: Callable[[TaskStatus], Callable],
130
+ event: Event[Optional[TaskStatus]],
131
+ ) -> Optional[Callable]:
132
+ if not state_machine.mission_ongoing:
133
+ return None
134
+
135
+ status: Optional[TaskStatus] = event.consume_event()
136
+ if status is not None:
137
+ state_machine.awaiting_task_status = False
138
+ return _handle_new_task_status(state_machine, handle_task_completed, status)
139
+
140
+ elif (
141
+ not state_machine.awaiting_task_status
142
+ and state_machine.current_task is not None
143
+ ):
144
+ state_machine.events.state_machine_events.task_status_request.trigger_event(
145
+ state_machine.current_task.id,
146
+ )
147
+ state_machine.awaiting_task_status = True
148
+ return None
149
+
150
+
151
+ def _handle_new_task_status(
152
+ state_machine: "StateMachine",
153
+ handle_task_completed: Callable[[TaskStatus], Callable],
154
+ status: TaskStatus,
155
+ ) -> Optional[Callable]:
156
+ if state_machine.current_task is None:
157
+ state_machine.iterate_current_task()
158
+
159
+ state_machine.current_task.status = status
160
+
161
+ if state_machine.current_task.is_finished():
162
+ state_machine.report_task_status(state_machine.current_task)
163
+ state_machine.publish_task_status(task=state_machine.current_task)
164
+
165
+ return handle_task_completed(status)
166
+ return None
isar/storage/uploader.py CHANGED
@@ -7,7 +7,7 @@ from threading import Event
7
7
  from typing import List, Union
8
8
 
9
9
  from isar.config.settings import settings
10
- from isar.models.communication.queues.events import Events
10
+ from isar.models.events import Events
11
11
  from isar.storage.storage_interface import StorageException, StorageInterface
12
12
  from robot_interface.models.inspection.inspection import (
13
13
  Inspection,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isar
3
- Version: 1.31.0
3
+ Version: 1.31.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