isar 1.24.6__py3-none-any.whl → 1.25.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.
- isar/apis/models/models.py +1 -0
- isar/apis/models/start_mission_definition.py +137 -133
- isar/apis/schedule/scheduling_controller.py +27 -9
- isar/config/predefined_missions/default.json +12 -11
- isar/config/predefined_missions/default_turtlebot.json +17 -16
- isar/mission_planner/local_planner.py +6 -20
- isar/mission_planner/mission_planner_interface.py +1 -1
- isar/script.py +1 -1
- isar/state_machine/state_machine.py +2 -2
- isar/state_machine/states/monitor.py +11 -3
- isar/storage/slimm_storage.py +4 -1
- isar/storage/utilities.py +3 -4
- {isar-1.24.6.dist-info → isar-1.25.1.dist-info}/METADATA +1 -1
- {isar-1.24.6.dist-info → isar-1.25.1.dist-info}/RECORD +22 -24
- robot_interface/models/inspection/inspection.py +4 -11
- robot_interface/models/mission/mission.py +9 -17
- robot_interface/models/mission/task.py +28 -40
- robot_interface/robot_interface.py +7 -5
- isar/services/readers/__init__.py +0 -0
- isar/services/readers/base_reader.py +0 -37
- {isar-1.24.6.dist-info → isar-1.25.1.dist-info}/LICENSE +0 -0
- {isar-1.24.6.dist-info → isar-1.25.1.dist-info}/WHEEL +0 -0
- {isar-1.24.6.dist-info → isar-1.25.1.dist-info}/entry_points.txt +0 -0
- {isar-1.24.6.dist-info → isar-1.25.1.dist-info}/top_level.txt +0 -0
isar/apis/models/models.py
CHANGED
|
@@ -2,7 +2,6 @@ import time
|
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from typing import List, Optional
|
|
4
4
|
|
|
5
|
-
from alitra import Frame, Orientation, Pose, Position
|
|
6
5
|
from pydantic import BaseModel, Field
|
|
7
6
|
|
|
8
7
|
from isar.apis.models.models import InputPose, InputPosition
|
|
@@ -44,188 +43,193 @@ class StartMissionInspectionDefinition(BaseModel):
|
|
|
44
43
|
analysis_type: Optional[str] = None
|
|
45
44
|
duration: Optional[float] = None
|
|
46
45
|
metadata: Optional[dict] = None
|
|
47
|
-
id: Optional[str] = None
|
|
48
46
|
|
|
49
47
|
|
|
50
48
|
class StartMissionTaskDefinition(BaseModel):
|
|
49
|
+
id: Optional[str] = None
|
|
51
50
|
type: TaskType = Field(default=TaskType.Inspection)
|
|
52
51
|
pose: InputPose
|
|
53
52
|
inspection: Optional[StartMissionInspectionDefinition] = None
|
|
54
53
|
tag: Optional[str] = None
|
|
55
|
-
id: Optional[str] = None
|
|
56
54
|
zoom: Optional[ZoomDescription] = None
|
|
57
55
|
|
|
58
56
|
|
|
59
57
|
class StartMissionDefinition(BaseModel):
|
|
60
58
|
tasks: List[StartMissionTaskDefinition]
|
|
61
|
-
id: Optional[str] = None
|
|
62
59
|
name: Optional[str] = None
|
|
63
60
|
start_pose: Optional[InputPose] = None
|
|
64
|
-
dock: Optional[bool] =
|
|
65
|
-
undock: Optional[bool] =
|
|
61
|
+
dock: Optional[bool] = Field(default=False)
|
|
62
|
+
undock: Optional[bool] = Field(default=False)
|
|
66
63
|
|
|
67
64
|
|
|
68
|
-
def to_isar_mission(
|
|
65
|
+
def to_isar_mission(
|
|
66
|
+
start_mission_definition: StartMissionDefinition,
|
|
67
|
+
return_pose: Optional[InputPose] = None,
|
|
68
|
+
) -> Mission:
|
|
69
69
|
isar_tasks: List[TASKS] = []
|
|
70
70
|
|
|
71
|
-
for
|
|
72
|
-
task: TASKS =
|
|
73
|
-
if start_mission_task_definition.id:
|
|
74
|
-
task.id = start_mission_task_definition.id
|
|
71
|
+
for task_definition in start_mission_definition.tasks:
|
|
72
|
+
task: TASKS = to_isar_task(task_definition)
|
|
75
73
|
isar_tasks.append(task)
|
|
76
74
|
|
|
75
|
+
if return_pose:
|
|
76
|
+
isar_tasks.append(ReturnToHome(pose=return_pose.to_alitra_pose()))
|
|
77
|
+
|
|
77
78
|
if not isar_tasks:
|
|
78
79
|
raise MissionPlannerError("Mission does not contain any valid tasks")
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
isar_mission: Mission = Mission(tasks=isar_tasks)
|
|
83
|
-
|
|
84
|
-
isar_mission.dock = start_mission_definition.dock
|
|
85
|
-
isar_mission.undock = start_mission_definition.undock
|
|
86
|
-
|
|
81
|
+
isar_mission_name: str
|
|
87
82
|
if start_mission_definition.name:
|
|
88
|
-
|
|
83
|
+
isar_mission_name = start_mission_definition.name
|
|
89
84
|
else:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if start_mission_definition.id:
|
|
93
|
-
isar_mission.id = start_mission_definition.id
|
|
85
|
+
isar_mission_name = _build_mission_name()
|
|
94
86
|
|
|
87
|
+
start_pose = None
|
|
95
88
|
if start_mission_definition.start_pose:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
input_pose.orientation.x,
|
|
106
|
-
input_pose.orientation.y,
|
|
107
|
-
input_pose.orientation.z,
|
|
108
|
-
input_pose.orientation.w,
|
|
109
|
-
input_frame,
|
|
110
|
-
)
|
|
111
|
-
isar_mission.start_pose = Pose(
|
|
112
|
-
position=input_position, orientation=input_orientation, frame=input_frame
|
|
113
|
-
)
|
|
114
|
-
|
|
115
|
-
return isar_mission
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def check_for_duplicate_ids(items: List[TASKS]):
|
|
119
|
-
duplicate_ids = get_duplicate_ids(items=items)
|
|
120
|
-
if len(duplicate_ids) > 0:
|
|
121
|
-
raise MissionPlannerError(
|
|
122
|
-
f"Failed to create as there were duplicate IDs which is not allowed "
|
|
123
|
-
f"({duplicate_ids})"
|
|
124
|
-
)
|
|
125
|
-
|
|
89
|
+
start_pose = start_mission_definition.start_pose.to_alitra_pose()
|
|
90
|
+
|
|
91
|
+
return Mission(
|
|
92
|
+
tasks=isar_tasks,
|
|
93
|
+
name=isar_mission_name,
|
|
94
|
+
start_pose=start_pose,
|
|
95
|
+
dock=start_mission_definition.dock,
|
|
96
|
+
undock=start_mission_definition.undock,
|
|
97
|
+
)
|
|
126
98
|
|
|
127
|
-
def create_isar_task(start_mission_task_definition) -> TASKS:
|
|
128
99
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
100
|
+
def to_isar_task(task_definition: StartMissionTaskDefinition) -> TASKS:
|
|
101
|
+
if task_definition.type == TaskType.Inspection:
|
|
102
|
+
return to_inspection_task(task_definition)
|
|
103
|
+
elif task_definition.type == TaskType.Localization:
|
|
104
|
+
return to_localization_task(task_definition)
|
|
105
|
+
elif task_definition.type == TaskType.ReturnToHome:
|
|
106
|
+
return create_return_to_home_task(task_definition)
|
|
107
|
+
elif task_definition.type == TaskType.Dock:
|
|
136
108
|
return create_dock_task()
|
|
137
109
|
else:
|
|
138
110
|
raise MissionPlannerError(
|
|
139
|
-
f"Failed to create task: '{
|
|
111
|
+
f"Failed to create task: '{task_definition.type}' is not a valid"
|
|
140
112
|
)
|
|
141
113
|
|
|
142
114
|
|
|
143
|
-
def
|
|
144
|
-
|
|
145
|
-
) -> TASKS:
|
|
115
|
+
def to_inspection_task(task_definition: StartMissionTaskDefinition) -> TASKS:
|
|
116
|
+
inspection_definition = task_definition.inspection
|
|
146
117
|
|
|
147
|
-
if
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
elif
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
118
|
+
if inspection_definition.type == InspectionTypes.image:
|
|
119
|
+
if task_definition.id:
|
|
120
|
+
return TakeImage(
|
|
121
|
+
id=task_definition.id,
|
|
122
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
123
|
+
tag_id=task_definition.tag,
|
|
124
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
125
|
+
metadata=task_definition.inspection.metadata,
|
|
126
|
+
zoom=task_definition.zoom,
|
|
127
|
+
)
|
|
128
|
+
else:
|
|
129
|
+
return TakeImage(
|
|
130
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
131
|
+
tag_id=task_definition.tag,
|
|
132
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
133
|
+
metadata=task_definition.inspection.metadata,
|
|
134
|
+
zoom=task_definition.zoom,
|
|
135
|
+
)
|
|
136
|
+
elif inspection_definition.type == InspectionTypes.video:
|
|
137
|
+
if task_definition.id:
|
|
138
|
+
return TakeVideo(
|
|
139
|
+
id=task_definition.id,
|
|
140
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
141
|
+
tag_id=task_definition.tag,
|
|
142
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
143
|
+
duration=inspection_definition.duration,
|
|
144
|
+
metadata=task_definition.inspection.metadata,
|
|
145
|
+
zoom=task_definition.zoom,
|
|
146
|
+
)
|
|
147
|
+
else:
|
|
148
|
+
return TakeVideo(
|
|
149
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
150
|
+
tag_id=task_definition.tag,
|
|
151
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
152
|
+
duration=inspection_definition.duration,
|
|
153
|
+
metadata=task_definition.inspection.metadata,
|
|
154
|
+
zoom=task_definition.zoom,
|
|
155
|
+
)
|
|
156
|
+
elif inspection_definition.type == InspectionTypes.thermal_image:
|
|
157
|
+
if task_definition.id:
|
|
158
|
+
return TakeThermalImage(
|
|
159
|
+
id=task_definition.id,
|
|
160
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
161
|
+
tag_id=task_definition.tag,
|
|
162
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
163
|
+
metadata=task_definition.inspection.metadata,
|
|
164
|
+
zoom=task_definition.zoom,
|
|
165
|
+
)
|
|
166
|
+
else:
|
|
167
|
+
return TakeThermalImage(
|
|
168
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
169
|
+
tag_id=task_definition.tag,
|
|
170
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
171
|
+
metadata=task_definition.inspection.metadata,
|
|
172
|
+
zoom=task_definition.zoom,
|
|
173
|
+
)
|
|
174
|
+
elif inspection_definition.type == InspectionTypes.thermal_video:
|
|
175
|
+
if task_definition.id:
|
|
176
|
+
return TakeThermalVideo(
|
|
177
|
+
id=task_definition.id,
|
|
178
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
179
|
+
tag_id=task_definition.tag,
|
|
180
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
181
|
+
duration=inspection_definition.duration,
|
|
182
|
+
metadata=task_definition.inspection.metadata,
|
|
183
|
+
zoom=task_definition.zoom,
|
|
184
|
+
)
|
|
185
|
+
else:
|
|
186
|
+
return TakeThermalVideo(
|
|
187
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
188
|
+
tag_id=task_definition.tag,
|
|
189
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
190
|
+
duration=inspection_definition.duration,
|
|
191
|
+
metadata=task_definition.inspection.metadata,
|
|
192
|
+
zoom=task_definition.zoom,
|
|
193
|
+
)
|
|
194
|
+
elif inspection_definition.type == InspectionTypes.audio:
|
|
195
|
+
if task_definition.id:
|
|
196
|
+
return RecordAudio(
|
|
197
|
+
id=task_definition.id,
|
|
198
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
199
|
+
tag_id=task_definition.tag,
|
|
200
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
201
|
+
duration=inspection_definition.duration,
|
|
202
|
+
metadata=task_definition.inspection.metadata,
|
|
203
|
+
zoom=task_definition.zoom,
|
|
204
|
+
)
|
|
205
|
+
else:
|
|
206
|
+
return RecordAudio(
|
|
207
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
208
|
+
tag_id=task_definition.tag,
|
|
209
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
210
|
+
duration=inspection_definition.duration,
|
|
211
|
+
metadata=task_definition.inspection.metadata,
|
|
212
|
+
zoom=task_definition.zoom,
|
|
213
|
+
)
|
|
193
214
|
else:
|
|
194
215
|
raise ValueError(
|
|
195
|
-
f"Inspection type '{
|
|
216
|
+
f"Inspection type '{inspection_definition.type}' not supported"
|
|
196
217
|
)
|
|
197
218
|
|
|
198
219
|
|
|
199
|
-
def
|
|
200
|
-
|
|
201
|
-
) -> Localize:
|
|
202
|
-
return Localize(
|
|
203
|
-
localization_pose=start_mission_task_definition.pose.to_alitra_pose()
|
|
204
|
-
)
|
|
220
|
+
def to_localization_task(task_definition: StartMissionTaskDefinition) -> Localize:
|
|
221
|
+
return Localize(localization_pose=task_definition.pose.to_alitra_pose())
|
|
205
222
|
|
|
206
223
|
|
|
207
224
|
def create_return_to_home_task(
|
|
208
|
-
|
|
225
|
+
task_definition: StartMissionTaskDefinition,
|
|
209
226
|
) -> ReturnToHome:
|
|
210
|
-
return ReturnToHome(pose=
|
|
227
|
+
return ReturnToHome(pose=task_definition.pose.to_alitra_pose())
|
|
211
228
|
|
|
212
229
|
|
|
213
230
|
def create_dock_task() -> DockingProcedure:
|
|
214
231
|
return DockingProcedure(behavior="dock")
|
|
215
232
|
|
|
216
233
|
|
|
217
|
-
def get_duplicate_ids(items: List[TASKS]) -> List[str]:
|
|
218
|
-
unique_ids: List[str] = []
|
|
219
|
-
duplicate_ids: List[str] = []
|
|
220
|
-
for item in items:
|
|
221
|
-
id: str = item.id
|
|
222
|
-
if id not in unique_ids:
|
|
223
|
-
unique_ids.append(id)
|
|
224
|
-
else:
|
|
225
|
-
duplicate_ids.append(id)
|
|
226
|
-
|
|
227
|
-
return duplicate_ids
|
|
228
|
-
|
|
229
|
-
|
|
230
234
|
def _build_mission_name() -> str:
|
|
231
235
|
return f"{settings.PLANT_SHORT_NAME}{settings.ROBOT_NAME}{int(time.time())}"
|
|
@@ -21,7 +21,13 @@ from isar.mission_planner.mission_planner_interface import MissionPlannerError
|
|
|
21
21
|
from isar.services.utilities.scheduling_utilities import SchedulingUtilities
|
|
22
22
|
from isar.state_machine.states_enum import States
|
|
23
23
|
from robot_interface.models.mission.mission import Mission
|
|
24
|
-
from robot_interface.models.mission.task import
|
|
24
|
+
from robot_interface.models.mission.task import (
|
|
25
|
+
TASKS,
|
|
26
|
+
InspectionTask,
|
|
27
|
+
Localize,
|
|
28
|
+
MoveArm,
|
|
29
|
+
ReturnToHome,
|
|
30
|
+
)
|
|
25
31
|
|
|
26
32
|
|
|
27
33
|
class SchedulingController:
|
|
@@ -115,7 +121,9 @@ class SchedulingController:
|
|
|
115
121
|
self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
|
|
116
122
|
|
|
117
123
|
try:
|
|
118
|
-
mission: Mission = to_isar_mission(
|
|
124
|
+
mission: Mission = to_isar_mission(
|
|
125
|
+
start_mission_definition=mission_definition, return_pose=return_pose
|
|
126
|
+
)
|
|
119
127
|
except MissionPlannerError as e:
|
|
120
128
|
error_message = f"Bad Request - Cannot create ISAR mission: {e}"
|
|
121
129
|
self.logger.warning(error_message)
|
|
@@ -127,9 +135,6 @@ class SchedulingController:
|
|
|
127
135
|
self.scheduling_utilities.verify_robot_capable_of_mission(
|
|
128
136
|
mission=mission, robot_capabilities=robot_settings.CAPABILITIES
|
|
129
137
|
)
|
|
130
|
-
if return_pose:
|
|
131
|
-
pose: Pose = return_pose.to_alitra_pose()
|
|
132
|
-
mission.tasks.append(ReturnToHome(pose=pose))
|
|
133
138
|
|
|
134
139
|
initial_pose_alitra: Optional[Pose] = (
|
|
135
140
|
initial_pose.to_alitra_pose() if initial_pose else None
|
|
@@ -213,7 +218,9 @@ class SchedulingController:
|
|
|
213
218
|
self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
|
|
214
219
|
|
|
215
220
|
pose: Pose = target_pose.to_alitra_pose()
|
|
216
|
-
mission: Mission = Mission(
|
|
221
|
+
mission: Mission = Mission(
|
|
222
|
+
name="Drive to pose", tasks=[ReturnToHome(pose=pose)]
|
|
223
|
+
)
|
|
217
224
|
|
|
218
225
|
self.logger.info(
|
|
219
226
|
f"Starting drive to mission with ISAR Mission ID: '{mission.id}'"
|
|
@@ -237,7 +244,9 @@ class SchedulingController:
|
|
|
237
244
|
self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
|
|
238
245
|
|
|
239
246
|
pose: Pose = localization_pose.to_alitra_pose()
|
|
240
|
-
mission: Mission = Mission(
|
|
247
|
+
mission: Mission = Mission(
|
|
248
|
+
name="Localization mission", tasks=[Localize(localization_pose=pose)]
|
|
249
|
+
)
|
|
241
250
|
|
|
242
251
|
self.logger.info(
|
|
243
252
|
f"Starting localization mission with ISAR Mission ID: '{mission.id}'"
|
|
@@ -284,7 +293,9 @@ class SchedulingController:
|
|
|
284
293
|
|
|
285
294
|
self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
|
|
286
295
|
|
|
287
|
-
mission: Mission = Mission(
|
|
296
|
+
mission: Mission = Mission(
|
|
297
|
+
name="Move arm mission", tasks=[MoveArm(arm_pose=arm_pose_literal)]
|
|
298
|
+
)
|
|
288
299
|
|
|
289
300
|
self.logger.info(
|
|
290
301
|
f"Starting move arm mission with ISAR Mission ID: '{mission.id}'"
|
|
@@ -302,4 +313,11 @@ class SchedulingController:
|
|
|
302
313
|
)
|
|
303
314
|
|
|
304
315
|
def _task_api_response(self, task: TASKS) -> TaskResponse:
|
|
305
|
-
|
|
316
|
+
if isinstance(task, InspectionTask):
|
|
317
|
+
inspection_id = task.inspection_id
|
|
318
|
+
else:
|
|
319
|
+
inspection_id = None
|
|
320
|
+
|
|
321
|
+
return TaskResponse(
|
|
322
|
+
id=task.id, tag_id=task.tag_id, inspection_id=inspection_id, type=task.type
|
|
323
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "1",
|
|
3
|
+
"name": "Default mission",
|
|
3
4
|
"tasks": [
|
|
4
5
|
{
|
|
5
6
|
"type": "take_image",
|
|
@@ -8,22 +9,22 @@
|
|
|
8
9
|
"x": -2,
|
|
9
10
|
"y": -2,
|
|
10
11
|
"z": 0,
|
|
11
|
-
"frame": "asset"
|
|
12
|
+
"frame": {"name": "asset"}
|
|
12
13
|
},
|
|
13
14
|
"orientation": {
|
|
14
15
|
"x": 0,
|
|
15
16
|
"y": 0,
|
|
16
17
|
"z": 0.4794255,
|
|
17
18
|
"w": 0.8775826,
|
|
18
|
-
"frame": "asset"
|
|
19
|
+
"frame": {"name": "asset"}
|
|
19
20
|
},
|
|
20
|
-
"frame": "asset"
|
|
21
|
+
"frame": {"name": "asset"}
|
|
21
22
|
},
|
|
22
23
|
"target": {
|
|
23
24
|
"x": 2,
|
|
24
25
|
"y": 2,
|
|
25
26
|
"z": 0,
|
|
26
|
-
"frame": "
|
|
27
|
+
"frame": {"name": "asset"}
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
{
|
|
@@ -33,22 +34,22 @@
|
|
|
33
34
|
"x": -2,
|
|
34
35
|
"y": 2,
|
|
35
36
|
"z": 0,
|
|
36
|
-
"frame": "asset"
|
|
37
|
+
"frame": {"name": "asset"}
|
|
37
38
|
},
|
|
38
39
|
"orientation": {
|
|
39
40
|
"x": 0,
|
|
40
41
|
"y": 0,
|
|
41
42
|
"z": 0.4794255,
|
|
42
43
|
"w": 0.8775826,
|
|
43
|
-
"frame": "asset"
|
|
44
|
+
"frame": {"name": "asset"}
|
|
44
45
|
},
|
|
45
|
-
"frame": "asset"
|
|
46
|
+
"frame": {"name": "asset"}
|
|
46
47
|
},
|
|
47
48
|
"target": {
|
|
48
49
|
"x": 2,
|
|
49
50
|
"y": 2,
|
|
50
51
|
"z": 0,
|
|
51
|
-
"frame": "
|
|
52
|
+
"frame": {"name": "asset"}
|
|
52
53
|
}
|
|
53
54
|
},
|
|
54
55
|
{
|
|
@@ -58,16 +59,16 @@
|
|
|
58
59
|
"x": 2,
|
|
59
60
|
"y": 2,
|
|
60
61
|
"z": 0,
|
|
61
|
-
"frame": "asset"
|
|
62
|
+
"frame": {"name": "asset"}
|
|
62
63
|
},
|
|
63
64
|
"orientation": {
|
|
64
65
|
"x": 0,
|
|
65
66
|
"y": 0,
|
|
66
67
|
"z": 0.4794255,
|
|
67
68
|
"w": 0.8775826,
|
|
68
|
-
"frame": "asset"
|
|
69
|
+
"frame": {"name": "asset"}
|
|
69
70
|
},
|
|
70
|
-
"frame": "asset"
|
|
71
|
+
"frame": {"name": "asset"}
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "2",
|
|
3
|
+
"name": "Default mission Turtlebot",
|
|
3
4
|
"tasks": [
|
|
4
5
|
{
|
|
5
6
|
"type": "take_image",
|
|
@@ -8,22 +9,22 @@
|
|
|
8
9
|
"x": -3.6,
|
|
9
10
|
"y": 4,
|
|
10
11
|
"z": 0,
|
|
11
|
-
"frame": "asset"
|
|
12
|
+
"frame": {"name": "asset"}
|
|
12
13
|
},
|
|
13
14
|
"orientation": {
|
|
14
15
|
"x": 0,
|
|
15
16
|
"y": 0,
|
|
16
17
|
"z": -0.7286672256879113,
|
|
17
18
|
"w": -0.6848660759820616,
|
|
18
|
-
"frame": "asset"
|
|
19
|
+
"frame": {"name": "asset"}
|
|
19
20
|
},
|
|
20
|
-
"frame": "asset"
|
|
21
|
+
"frame": {"name": "asset"}
|
|
21
22
|
},
|
|
22
23
|
"target": {
|
|
23
24
|
"x": -4.7,
|
|
24
25
|
"y": 4.9,
|
|
25
26
|
"z": 0,
|
|
26
|
-
"frame": "
|
|
27
|
+
"frame": {"name": "asset"}
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
|
|
@@ -34,22 +35,22 @@
|
|
|
34
35
|
"x": 4.7,
|
|
35
36
|
"y": 3,
|
|
36
37
|
"z": 0,
|
|
37
|
-
"frame": "asset"
|
|
38
|
+
"frame": {"name": "asset"}
|
|
38
39
|
},
|
|
39
40
|
"orientation": {
|
|
40
41
|
"x": 0,
|
|
41
42
|
"y": 0,
|
|
42
43
|
"z": 0.5769585,
|
|
43
44
|
"w": 0.8167734,
|
|
44
|
-
"frame": "asset"
|
|
45
|
+
"frame": {"name": "asset"}
|
|
45
46
|
},
|
|
46
|
-
"frame": "asset"
|
|
47
|
+
"frame": {"name": "asset"}
|
|
47
48
|
},
|
|
48
49
|
"target": {
|
|
49
50
|
"x": 5.6,
|
|
50
51
|
"y": 5.2,
|
|
51
52
|
"z": 0,
|
|
52
|
-
"frame": "
|
|
53
|
+
"frame": {"name": "asset"}
|
|
53
54
|
}
|
|
54
55
|
},
|
|
55
56
|
{
|
|
@@ -59,22 +60,22 @@
|
|
|
59
60
|
"x": 4.7,
|
|
60
61
|
"y": 3,
|
|
61
62
|
"z": 0,
|
|
62
|
-
"frame": "asset"
|
|
63
|
+
"frame": {"name": "asset"}
|
|
63
64
|
},
|
|
64
65
|
"orientation": {
|
|
65
66
|
"x": 0,
|
|
66
67
|
"y": 0,
|
|
67
68
|
"z": 0.5769585,
|
|
68
69
|
"w": 0.8167734,
|
|
69
|
-
"frame": "asset"
|
|
70
|
+
"frame": {"name": "asset"}
|
|
70
71
|
},
|
|
71
|
-
"frame": "asset"
|
|
72
|
+
"frame": {"name": "asset"}
|
|
72
73
|
},
|
|
73
74
|
"target": {
|
|
74
75
|
"x": 3.1,
|
|
75
76
|
"y": 5.2,
|
|
76
77
|
"z": 0,
|
|
77
|
-
"frame": "
|
|
78
|
+
"frame": {"name": "asset"}
|
|
78
79
|
}
|
|
79
80
|
},
|
|
80
81
|
{
|
|
@@ -84,22 +85,22 @@
|
|
|
84
85
|
"x": 0.95,
|
|
85
86
|
"y": 2.6,
|
|
86
87
|
"z": 0,
|
|
87
|
-
"frame": "asset"
|
|
88
|
+
"frame": {"name": "asset"}
|
|
88
89
|
},
|
|
89
90
|
"orientation": {
|
|
90
91
|
"x": 0,
|
|
91
92
|
"y": 0,
|
|
92
93
|
"z": -0.6992469,
|
|
93
94
|
"w": 0.7148802,
|
|
94
|
-
"frame": "asset"
|
|
95
|
+
"frame": {"name": "asset"}
|
|
95
96
|
},
|
|
96
|
-
"frame": "asset"
|
|
97
|
+
"frame": {"name": "asset"}
|
|
97
98
|
},
|
|
98
99
|
"target": {
|
|
99
100
|
"x": 1.9,
|
|
100
101
|
"y": 1.9,
|
|
101
102
|
"z": 0,
|
|
102
|
-
"frame": "
|
|
103
|
+
"frame": {"name": "asset"}
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
]
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
3
|
from pathlib import Path
|
|
3
|
-
from typing import List, Optional
|
|
4
4
|
|
|
5
|
-
from alitra import Frame
|
|
6
5
|
from injector import inject
|
|
7
6
|
|
|
8
7
|
from isar.config.settings import settings
|
|
@@ -11,10 +10,8 @@ from isar.mission_planner.mission_planner_interface import (
|
|
|
11
10
|
MissionPlannerError,
|
|
12
11
|
MissionPlannerInterface,
|
|
13
12
|
)
|
|
14
|
-
from isar.services.readers.base_reader import BaseReader, BaseReaderError
|
|
15
13
|
from robot_interface.models.mission.mission import Mission
|
|
16
14
|
|
|
17
|
-
|
|
18
15
|
logger = logging.getLogger("api")
|
|
19
16
|
|
|
20
17
|
|
|
@@ -39,16 +36,10 @@ class LocalPlanner(MissionPlannerInterface):
|
|
|
39
36
|
|
|
40
37
|
@staticmethod
|
|
41
38
|
def read_mission_from_file(mission_path: Path) -> Mission:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
mission: Mission = BaseReader.dict_to_dataclass(
|
|
45
|
-
dataclass_dict=mission_dict,
|
|
46
|
-
target_dataclass=Mission,
|
|
47
|
-
cast_config=[Frame],
|
|
48
|
-
strict_config=True,
|
|
49
|
-
)
|
|
39
|
+
with open(mission_path) as json_file:
|
|
40
|
+
mission_dict = json.load(json_file)
|
|
50
41
|
|
|
51
|
-
return
|
|
42
|
+
return Mission(**mission_dict)
|
|
52
43
|
|
|
53
44
|
def get_predefined_missions(self) -> dict:
|
|
54
45
|
missions: dict = {}
|
|
@@ -57,13 +48,8 @@ class LocalPlanner(MissionPlannerInterface):
|
|
|
57
48
|
for file in json_files:
|
|
58
49
|
mission_name = file.stem
|
|
59
50
|
path_to_file = self.predefined_mission_folder.joinpath(file.name)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
except BaseReaderError as e:
|
|
63
|
-
logger.warning(
|
|
64
|
-
f"Failed to read predefined mission {path_to_file} \n {e}"
|
|
65
|
-
)
|
|
66
|
-
continue
|
|
51
|
+
|
|
52
|
+
mission: Mission = self.read_mission_from_file(path_to_file)
|
|
67
53
|
if mission.id in invalid_mission_ids:
|
|
68
54
|
logger.warning(
|
|
69
55
|
f"Duplicate mission id {mission.id} : {path_to_file.as_posix()}"
|
isar/script.py
CHANGED
|
@@ -412,7 +412,7 @@ class StateMachine(object):
|
|
|
412
412
|
Transitions into idle state.
|
|
413
413
|
|
|
414
414
|
"""
|
|
415
|
-
self.to_idle()
|
|
415
|
+
self.to_idle() # type: ignore
|
|
416
416
|
|
|
417
417
|
def iterate_current_task(self):
|
|
418
418
|
if self.current_task.is_finished():
|
|
@@ -426,7 +426,7 @@ class StateMachine(object):
|
|
|
426
426
|
|
|
427
427
|
def update_state(self):
|
|
428
428
|
"""Updates the current state of the state machine."""
|
|
429
|
-
self.current_state = States(self.state)
|
|
429
|
+
self.current_state = States(self.state) # type: ignore
|
|
430
430
|
self.send_state_status()
|
|
431
431
|
self._log_state_transition(self.current_state)
|
|
432
432
|
self.logger.info(f"State: {self.current_state}")
|
|
@@ -13,11 +13,11 @@ from isar.services.utilities.threaded_request import (
|
|
|
13
13
|
)
|
|
14
14
|
from robot_interface.models.exceptions.robot_exceptions import (
|
|
15
15
|
ErrorMessage,
|
|
16
|
+
RobotCommunicationException,
|
|
16
17
|
RobotCommunicationTimeoutException,
|
|
17
18
|
RobotException,
|
|
18
19
|
RobotRetrieveInspectionException,
|
|
19
20
|
RobotTaskStatusException,
|
|
20
|
-
RobotCommunicationException,
|
|
21
21
|
)
|
|
22
22
|
from robot_interface.models.inspection.inspection import Inspection
|
|
23
23
|
from robot_interface.models.mission.mission import Mission
|
|
@@ -173,6 +173,12 @@ class Monitor(State):
|
|
|
173
173
|
inspection: Inspection = self.state_machine.robot.get_inspection(
|
|
174
174
|
task=current_task
|
|
175
175
|
)
|
|
176
|
+
if current_task.inspection_id == inspection.id:
|
|
177
|
+
self.logger.warning(
|
|
178
|
+
f"The inspection_id of task ({current_task.inspection_id}) "
|
|
179
|
+
f"and result ({inspection.id}) is not matching. "
|
|
180
|
+
f"This may lead to confusions when accessing the inspection later"
|
|
181
|
+
)
|
|
176
182
|
|
|
177
183
|
except (RobotRetrieveInspectionException, RobotException) as e:
|
|
178
184
|
self._set_error_message(e)
|
|
@@ -183,7 +189,7 @@ class Monitor(State):
|
|
|
183
189
|
|
|
184
190
|
if not inspection:
|
|
185
191
|
self.logger.warning(
|
|
186
|
-
f"No inspection data retrieved for task {str(current_task.id)[:8]}"
|
|
192
|
+
f"No inspection result data retrieved for task {str(current_task.id)[:8]}"
|
|
187
193
|
)
|
|
188
194
|
|
|
189
195
|
inspection.metadata.tag_id = current_task.tag_id
|
|
@@ -193,7 +199,9 @@ class Monitor(State):
|
|
|
193
199
|
mission,
|
|
194
200
|
)
|
|
195
201
|
self.state_machine.queues.upload_queue.put(message)
|
|
196
|
-
self.logger.info(
|
|
202
|
+
self.logger.info(
|
|
203
|
+
f"Inspection result: {str(inspection.id)[:8]} queued for upload"
|
|
204
|
+
)
|
|
197
205
|
|
|
198
206
|
def _report_task_status(self, task: Task) -> None:
|
|
199
207
|
self.request_status_failure_counter = 0
|
isar/storage/slimm_storage.py
CHANGED
|
@@ -71,7 +71,10 @@ class SlimmStorage(StorageInterface):
|
|
|
71
71
|
return inspection_path
|
|
72
72
|
|
|
73
73
|
def _ingest(
|
|
74
|
-
self,
|
|
74
|
+
self,
|
|
75
|
+
inspection: Inspection,
|
|
76
|
+
multiform_body: MultipartEncoder,
|
|
77
|
+
request_url: str,
|
|
75
78
|
) -> str:
|
|
76
79
|
token: str = self.credentials.get_token(self.request_scope).token
|
|
77
80
|
try:
|
isar/storage/utilities.py
CHANGED
|
@@ -34,10 +34,11 @@ def construct_metadata_file(
|
|
|
34
34
|
"plant_code": settings.PLANT_CODE,
|
|
35
35
|
"media_orientation_reference_system": settings.MEDIA_ORIENTATION_REFERENCE_SYSTEM, # noqa: E501
|
|
36
36
|
"additional_meta": {
|
|
37
|
+
"inspection_id": inspection.id,
|
|
37
38
|
"mission_id": mission.id,
|
|
38
39
|
"mission_name": mission.name,
|
|
39
|
-
"plant_name": settings.PLANT_NAME,
|
|
40
40
|
"mission_date": datetime.now(timezone.utc).date(),
|
|
41
|
+
"plant_name": settings.PLANT_NAME,
|
|
41
42
|
"isar_id": settings.ISAR_ID,
|
|
42
43
|
"robot_name": settings.ROBOT_NAME,
|
|
43
44
|
"analysis_type": (
|
|
@@ -69,9 +70,7 @@ def construct_metadata_file(
|
|
|
69
70
|
return json.dumps(data, cls=EnhancedJSONEncoder, indent=4).encode()
|
|
70
71
|
|
|
71
72
|
|
|
72
|
-
def get_filename(
|
|
73
|
-
inspection: Inspection,
|
|
74
|
-
) -> str:
|
|
73
|
+
def get_filename(inspection: Inspection) -> str:
|
|
75
74
|
inspection_type: str = type(inspection).__name__
|
|
76
75
|
tag: str = inspection.metadata.tag_id if inspection.metadata.tag_id else "no-tag"
|
|
77
76
|
epoch_time: int = int(time.time())
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
isar/__init__.py,sha256=cH8p8bVveu3FUL6kBhldcSlLaoHgD82Kd0-SwSNfGXw,87
|
|
2
2
|
isar/modules.py,sha256=da1oE79leMID2cQKrVgahFyo-NAqNa_UA0PNHCA3Zt8,7361
|
|
3
|
-
isar/script.py,sha256=
|
|
3
|
+
isar/script.py,sha256=MRC_w1kzWuutE9C7QNVtPhKbsld-uWKiMrcUWufiNzQ,5988
|
|
4
4
|
isar/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
isar/apis/api.py,sha256=vUy7QbHrKcTHjh2rkU7lqQPkCasI6umha8r6H88JiXE,13942
|
|
6
6
|
isar/apis/models/__init__.py,sha256=NI1BYyN__Ogr00Qqe0XJ-9gEVPva2brXo2RJsbrS4tM,52
|
|
7
|
-
isar/apis/models/models.py,sha256=
|
|
8
|
-
isar/apis/models/start_mission_definition.py,sha256=
|
|
7
|
+
isar/apis/models/models.py,sha256=HzLaWhjAv0uJRBWipIgYg_F75eaQ5jl9Pi4UnYbDJ-M,1749
|
|
8
|
+
isar/apis/models/start_mission_definition.py,sha256=yaWICdWJrCYFIm5Aq1K3BVxD9oyVuXYaaY9hJG2aoVY,8820
|
|
9
9
|
isar/apis/robot_control/robot_controller.py,sha256=en6j-dHIxUXraREz7JETqtxgHl79ks7TBgBwPKc6VQE,1019
|
|
10
10
|
isar/apis/schedule/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
isar/apis/schedule/scheduling_controller.py,sha256=
|
|
11
|
+
isar/apis/schedule/scheduling_controller.py,sha256=JvuioSWmJohiCqfGSCDvOq-CK2Y7ACHfXLfH-UhVQJ8,11371
|
|
12
12
|
isar/apis/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
isar/apis/security/authentication.py,sha256=TI8U9Y_L6ihHLMeM50ZONd5EPfuHdw_XMU_Q987W4AY,1975
|
|
14
14
|
isar/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -33,11 +33,11 @@ isar/config/predefined_mission_definition/default_exr.json,sha256=L3-kqjfgXoULDU
|
|
|
33
33
|
isar/config/predefined_mission_definition/default_mission.json,sha256=nEk1ql17RAs2I5Ws2wA-0GJ6oqJco-Q0Q0vhf4k6ajc,2926
|
|
34
34
|
isar/config/predefined_mission_definition/default_turtlebot.json,sha256=Ka379MLu8qiGIa6Fu-8p8A4OgHVccLkKYSX0RthUOeI,4060
|
|
35
35
|
isar/config/predefined_missions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
-
isar/config/predefined_missions/default.json,sha256=
|
|
37
|
-
isar/config/predefined_missions/default_turtlebot.json,sha256=
|
|
36
|
+
isar/config/predefined_missions/default.json,sha256=EDMfPQi2D_517jlfeU2BBFySkbvhYG7uEK6cbiK7DRM,1464
|
|
37
|
+
isar/config/predefined_missions/default_turtlebot.json,sha256=8Vk1_0P0BBsG0vwh4vwIYINiiWioErHZ0Ppjq3ctaPM,2143
|
|
38
38
|
isar/mission_planner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
-
isar/mission_planner/local_planner.py,sha256=
|
|
40
|
-
isar/mission_planner/mission_planner_interface.py,sha256=
|
|
39
|
+
isar/mission_planner/local_planner.py,sha256=45zVP3hzUHdZ5Ty4KWRL85_AUWiTmBhTtlsAruUDMD4,2561
|
|
40
|
+
isar/mission_planner/mission_planner_interface.py,sha256=UgpPIM4FbrWOD7fGY3Ul64k3uYb8wo0FwSWGewYoVbc,485
|
|
41
41
|
isar/mission_planner/sequential_task_selector.py,sha256=lzBPV97wGBfqwpEh4l_7qhijx56yQtOmIM9DhIMOGFY,649
|
|
42
42
|
isar/mission_planner/task_selector_interface.py,sha256=mzZEQfvU9BLCo_pu3fXXuYIjwjdjcr0vJ2pUCtFsr68,713
|
|
43
43
|
isar/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -52,8 +52,6 @@ isar/models/mission_metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
52
52
|
isar/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
53
|
isar/services/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
isar/services/auth/azure_credentials.py,sha256=9PlwGe5FrPRbW2dp0go7LMp8_l_FRvL8xOXotXwzRDo,364
|
|
55
|
-
isar/services/readers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
|
-
isar/services/readers/base_reader.py,sha256=_fNd5fb5dFeMtOvfWzIAGO-KIgl3zT19iEuzSjeZNPc,987
|
|
57
55
|
isar/services/service_connections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
58
56
|
isar/services/service_connections/request_handler.py,sha256=0LxC0lu_HXeEf_xmJWjfEsh14oAUI97cpG1IWtBlcs4,4278
|
|
59
57
|
isar/services/service_connections/mqtt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -67,13 +65,13 @@ isar/services/utilities/robot_utilities.py,sha256=4-ob4kcIiRN_GXFDBMwBadfbwpYqKE
|
|
|
67
65
|
isar/services/utilities/scheduling_utilities.py,sha256=UUMxhudY2mQRG6Edjq6BG7oxwlqmcu5h6fMyw4Vhl_o,8376
|
|
68
66
|
isar/services/utilities/threaded_request.py,sha256=py4G-_RjnIdHljmKFAcQ6ddqMmp-ZYV39Ece-dqRqjs,1874
|
|
69
67
|
isar/state_machine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
-
isar/state_machine/state_machine.py,sha256=
|
|
68
|
+
isar/state_machine/state_machine.py,sha256=9QO1g-uAI6jYuKq9e7a9CoDRAQHNJ-crZ9NuTnaS_wU,21788
|
|
71
69
|
isar/state_machine/states_enum.py,sha256=BlrUcBWkM5K6D_UZXRwTaUgGpAagWmVZH6HhDBGzVU4,278
|
|
72
70
|
isar/state_machine/states/__init__.py,sha256=kErbKPDTwNfCLijvdyN6_AuOqDwR23nu9F0Qovsnir4,218
|
|
73
71
|
isar/state_machine/states/idle.py,sha256=YKTOPVJUTGp-XR3N8FSm1s5ol3zoTmGs0THUMiO5h6A,3298
|
|
74
72
|
isar/state_machine/states/initialize.py,sha256=TVXV5Ps3N4_flM88j9pQiX88kZgLzLwzlJy_6hPbgcA,2359
|
|
75
73
|
isar/state_machine/states/initiate.py,sha256=j1wvSC3zVODgRkKOVsQROiuWkjihSBtwCs5GsoivLvc,5655
|
|
76
|
-
isar/state_machine/states/monitor.py,sha256=
|
|
74
|
+
isar/state_machine/states/monitor.py,sha256=pN52wtrrcrXxz913ZcFEELwaStL-eTZ6IIDiYw6oqe0,10253
|
|
77
75
|
isar/state_machine/states/off.py,sha256=jjqN_oJMpBtWuY7hP-c9f0w3p2CYCfe-NpmYHHPnmyI,544
|
|
78
76
|
isar/state_machine/states/offline.py,sha256=IfEZ6-kl6OfJSRT1eKHOey7AU23tKiSHqpwGqclmH_c,2166
|
|
79
77
|
isar/state_machine/states/paused.py,sha256=TIg1iJvAxGUIfzE_qWp0wrq4Ka0a3zEf3GNwIWLIK0M,1177
|
|
@@ -81,12 +79,12 @@ isar/state_machine/states/stop.py,sha256=WVyjhndHcccy7_P9bU7SXyZB3qphsGahdSymagh
|
|
|
81
79
|
isar/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
82
80
|
isar/storage/blob_storage.py,sha256=8sfG1I23nPyVy6uZOq0O0FycZBjsSDIuAWdCVdVMEeM,3217
|
|
83
81
|
isar/storage/local_storage.py,sha256=Bnmoi5gyN8r-oRh0aHrOdGqaH3JqRScFKMRXYojW5kY,1855
|
|
84
|
-
isar/storage/slimm_storage.py,sha256=
|
|
82
|
+
isar/storage/slimm_storage.py,sha256=iVtc7w_VPFoe0fWyPpI9kjau3C1rn7w2n5EJaqloFIU,8991
|
|
85
83
|
isar/storage/storage_interface.py,sha256=DYDry4I7aZpDHJhsBF6s8zrgokFAc7fdKJKfA8AvL7o,828
|
|
86
84
|
isar/storage/uploader.py,sha256=JBlgaHYdFFUPlkx0eI0HBhP93fr9PIPTaYp6HG0iMeU,6509
|
|
87
|
-
isar/storage/utilities.py,sha256=
|
|
85
|
+
isar/storage/utilities.py,sha256=fitsdQ1ox5gr9fk9VuSk_iTBiEAIS8NZAnHabUZORh0,3173
|
|
88
86
|
robot_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
|
-
robot_interface/robot_interface.py,sha256=
|
|
87
|
+
robot_interface/robot_interface.py,sha256=KtvWp1MDYgepG3uR9i8pt66zifhaXFl0nInClzL1FG0,9679
|
|
90
88
|
robot_interface/test_robot_interface.py,sha256=FV1urn7SbsMyWBIcTKjsBwAG4IsXeZ6pLHE0mA9EGGs,692
|
|
91
89
|
robot_interface/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
92
90
|
robot_interface/models/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -94,11 +92,11 @@ robot_interface/models/exceptions/robot_exceptions.py,sha256=7s9X7GaQVhQiTnXLi-a
|
|
|
94
92
|
robot_interface/models/initialize/__init__.py,sha256=rz5neEDr59GDbzzI_FF0DId-C-I-50l113P-h-C_QBY,48
|
|
95
93
|
robot_interface/models/initialize/initialize_params.py,sha256=2eG5Aq5bDKU6tVkaUMAoc46GERBgyaKkqv6yLupdRLc,164
|
|
96
94
|
robot_interface/models/inspection/__init__.py,sha256=14wfuj4XZazrigKD7fL98khFKz-eckIpEgPcYRj40Kg,227
|
|
97
|
-
robot_interface/models/inspection/inspection.py,sha256=
|
|
95
|
+
robot_interface/models/inspection/inspection.py,sha256=nSoKTDPRWnpaJuoKnaE_2EEJ6oH4dQkqEuECcQTvVhI,2059
|
|
98
96
|
robot_interface/models/mission/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
99
|
-
robot_interface/models/mission/mission.py,sha256=
|
|
97
|
+
robot_interface/models/mission/mission.py,sha256=QZBDQiOmpb4C7nNCf1PaCWwpvAc8jrhwHSznOe2YhX8,842
|
|
100
98
|
robot_interface/models/mission/status.py,sha256=C_viZWNTYOncWCdurx7Pko_D9d595QmHuJZBT8YMHUg,724
|
|
101
|
-
robot_interface/models/mission/task.py,sha256=
|
|
99
|
+
robot_interface/models/mission/task.py,sha256=boRigdjY9dvJzHYxAweqydRGt7CUyXFcCjMVw-lrwJM,4969
|
|
102
100
|
robot_interface/models/robots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
103
101
|
robot_interface/models/robots/media.py,sha256=Bo6XisTND9MOsxvJe6mWtKumFCpX6pbEBzEnAKpoIpU,232
|
|
104
102
|
robot_interface/models/robots/robot_model.py,sha256=pZQsqhn9hh6XE3EjMZhWMzYqg5oJ4CJ4CXeOASKvEf8,452
|
|
@@ -108,9 +106,9 @@ robot_interface/telemetry/payloads.py,sha256=JM5E_IHkZpim_zdwc-w52D7dYFBeP4iO1-x
|
|
|
108
106
|
robot_interface/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
109
107
|
robot_interface/utilities/json_service.py,sha256=nU2Q_3P9Fq9hs6F_wtUjWtHfl_g1Siy-yDhXXSKwHwg,1018
|
|
110
108
|
robot_interface/utilities/uuid_string_factory.py,sha256=_NQIbBQ56w0qqO0MUDP6aPpHbxW7ATRhK8HnQiBSLkc,76
|
|
111
|
-
isar-1.
|
|
112
|
-
isar-1.
|
|
113
|
-
isar-1.
|
|
114
|
-
isar-1.
|
|
115
|
-
isar-1.
|
|
116
|
-
isar-1.
|
|
109
|
+
isar-1.25.1.dist-info/LICENSE,sha256=3fc2-ebLwHWwzfQbulGNRdcNob3SBQeCfEVUDYxsuqw,14058
|
|
110
|
+
isar-1.25.1.dist-info/METADATA,sha256=QvUtSw8nmGfn1MgIgqxHa9mzQNpH1hudpRrNwmodfwA,30661
|
|
111
|
+
isar-1.25.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
112
|
+
isar-1.25.1.dist-info/entry_points.txt,sha256=TFam7uNNw7J0iiDYzsH2gfG0u1eV1wh3JTw_HkhgKLk,49
|
|
113
|
+
isar-1.25.1.dist-info/top_level.txt,sha256=UwIML2RtuQKCyJJkatcSnyp6-ldDjboB9k9JgKipO-U,21
|
|
114
|
+
isar-1.25.1.dist-info/RECORD,,
|
|
@@ -4,8 +4,7 @@ from datetime import datetime
|
|
|
4
4
|
from typing import Optional, Type
|
|
5
5
|
|
|
6
6
|
from alitra import Pose
|
|
7
|
-
|
|
8
|
-
from robot_interface.utilities.uuid_string_factory import uuid4_string
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
@dataclass
|
|
@@ -43,18 +42,16 @@ class AudioMetadata(InspectionMetadata):
|
|
|
43
42
|
duration: Optional[float] = field(default=None)
|
|
44
43
|
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
class Inspection:
|
|
45
|
+
class Inspection(BaseModel):
|
|
48
46
|
metadata: InspectionMetadata
|
|
49
|
-
id: str =
|
|
50
|
-
data: Optional[bytes] =
|
|
47
|
+
id: str = Field(frozen=True)
|
|
48
|
+
data: Optional[bytes] = Field(default=None, frozen=True)
|
|
51
49
|
|
|
52
50
|
@staticmethod
|
|
53
51
|
def get_metadata_type() -> Type[InspectionMetadata]:
|
|
54
52
|
return InspectionMetadata
|
|
55
53
|
|
|
56
54
|
|
|
57
|
-
@dataclass
|
|
58
55
|
class Image(Inspection):
|
|
59
56
|
metadata: ImageMetadata
|
|
60
57
|
|
|
@@ -63,7 +60,6 @@ class Image(Inspection):
|
|
|
63
60
|
return ImageMetadata
|
|
64
61
|
|
|
65
62
|
|
|
66
|
-
@dataclass
|
|
67
63
|
class ThermalImage(Inspection):
|
|
68
64
|
metadata: ThermalImageMetadata
|
|
69
65
|
|
|
@@ -72,7 +68,6 @@ class ThermalImage(Inspection):
|
|
|
72
68
|
return ThermalImageMetadata
|
|
73
69
|
|
|
74
70
|
|
|
75
|
-
@dataclass
|
|
76
71
|
class Video(Inspection):
|
|
77
72
|
metadata: VideoMetadata
|
|
78
73
|
|
|
@@ -81,7 +76,6 @@ class Video(Inspection):
|
|
|
81
76
|
return VideoMetadata
|
|
82
77
|
|
|
83
78
|
|
|
84
|
-
@dataclass
|
|
85
79
|
class ThermalVideo(Inspection):
|
|
86
80
|
metadata: ThermalVideoMetadata
|
|
87
81
|
|
|
@@ -90,7 +84,6 @@ class ThermalVideo(Inspection):
|
|
|
90
84
|
return ThermalVideoMetadata
|
|
91
85
|
|
|
92
86
|
|
|
93
|
-
@dataclass
|
|
94
87
|
class Audio(Inspection):
|
|
95
88
|
metadata: AudioMetadata
|
|
96
89
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from dataclasses import dataclass, field
|
|
2
1
|
from typing import List, Optional
|
|
3
2
|
|
|
4
3
|
from alitra import Pose
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
5
|
|
|
6
6
|
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
|
|
7
7
|
from robot_interface.models.mission.status import MissionStatus
|
|
@@ -9,20 +9,12 @@ from robot_interface.models.mission.task import TASKS
|
|
|
9
9
|
from robot_interface.utilities.uuid_string_factory import uuid4_string
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
tasks: List[TASKS]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
undock: Optional[bool] = None
|
|
12
|
+
class Mission(BaseModel):
|
|
13
|
+
id: str = Field(default_factory=uuid4_string, frozen=True)
|
|
14
|
+
tasks: List[TASKS] = Field(default_factory=list, frozen=True)
|
|
15
|
+
name: str = Field(frozen=True)
|
|
16
|
+
start_pose: Optional[Pose] = Field(default=None, frozen=True)
|
|
17
|
+
dock: bool = Field(default=False, frozen=True)
|
|
18
|
+
undock: bool = Field(default=False, frozen=True)
|
|
20
19
|
status: MissionStatus = MissionStatus.NotStarted
|
|
21
|
-
error_message: Optional[ErrorMessage] =
|
|
22
|
-
|
|
23
|
-
def _set_unique_id(self) -> None:
|
|
24
|
-
self.id: str = uuid4_string()
|
|
25
|
-
|
|
26
|
-
def __post_init__(self) -> None:
|
|
27
|
-
if self.id is None:
|
|
28
|
-
self._set_unique_id()
|
|
20
|
+
error_message: Optional[ErrorMessage] = Field(default=None)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from dataclasses import dataclass, field
|
|
2
1
|
from enum import Enum
|
|
3
|
-
from typing import
|
|
2
|
+
from typing import Literal, Optional, Type, Union
|
|
4
3
|
|
|
5
4
|
from alitra import Pose, Position
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
7
|
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
|
|
8
8
|
from robot_interface.models.inspection import (
|
|
@@ -29,18 +29,16 @@ class TaskTypes(str, Enum):
|
|
|
29
29
|
DockingProcedure = "docking_procedure"
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
class ZoomDescription:
|
|
32
|
+
class ZoomDescription(BaseModel):
|
|
34
33
|
objectWidth: float
|
|
35
34
|
objectHeight: float
|
|
36
35
|
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
id: str = field(default_factory=uuid4_string, init=True)
|
|
37
|
+
class Task(BaseModel):
|
|
38
|
+
status: TaskStatus = Field(default=TaskStatus.NotStarted)
|
|
39
|
+
error_message: Optional[ErrorMessage] = Field(default=None)
|
|
40
|
+
tag_id: Optional[str] = Field(default=None)
|
|
41
|
+
id: str = Field(default_factory=uuid4_string, frozen=True)
|
|
44
42
|
|
|
45
43
|
def is_finished(self) -> bool:
|
|
46
44
|
if (
|
|
@@ -56,69 +54,63 @@ class Task:
|
|
|
56
54
|
return self.status
|
|
57
55
|
|
|
58
56
|
|
|
59
|
-
@dataclass
|
|
60
57
|
class InspectionTask(Task):
|
|
61
58
|
"""
|
|
62
59
|
Base class for all inspection tasks which produce results to be uploaded.
|
|
63
60
|
"""
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
robot_pose: Pose =
|
|
67
|
-
metadata: Optional[dict] =
|
|
68
|
-
zoom: Optional[ZoomDescription] =
|
|
62
|
+
inspection_id: str = Field(default_factory=uuid4_string, frozen=True)
|
|
63
|
+
robot_pose: Pose = Field(default=None, init=True)
|
|
64
|
+
metadata: Optional[dict] = Field(default_factory=dict)
|
|
65
|
+
zoom: Optional[ZoomDescription] = Field(default=None)
|
|
69
66
|
|
|
70
67
|
@staticmethod
|
|
71
68
|
def get_inspection_type() -> Type[Inspection]:
|
|
72
69
|
return Inspection
|
|
73
70
|
|
|
74
71
|
|
|
75
|
-
@dataclass
|
|
76
72
|
class DockingProcedure(Task):
|
|
77
73
|
"""
|
|
78
74
|
Task which causes the robot to dock or undock
|
|
79
75
|
"""
|
|
80
76
|
|
|
81
|
-
behavior: Literal["dock", "undock"] =
|
|
77
|
+
behavior: Literal["dock", "undock"] = Field(default=None)
|
|
82
78
|
type: Literal[TaskTypes.DockingProcedure] = TaskTypes.DockingProcedure
|
|
83
79
|
|
|
84
80
|
|
|
85
|
-
@dataclass
|
|
86
81
|
class ReturnToHome(Task):
|
|
87
82
|
"""
|
|
88
83
|
Task which cases the robot to return home
|
|
89
84
|
"""
|
|
90
85
|
|
|
91
|
-
pose: Pose =
|
|
86
|
+
pose: Pose = Field(default=None)
|
|
92
87
|
type: Literal[TaskTypes.ReturnToHome] = TaskTypes.ReturnToHome
|
|
93
88
|
|
|
94
89
|
|
|
95
|
-
@dataclass
|
|
96
90
|
class Localize(Task):
|
|
97
91
|
"""
|
|
98
92
|
Task which causes the robot to localize
|
|
99
93
|
"""
|
|
100
94
|
|
|
101
|
-
localization_pose: Pose =
|
|
95
|
+
localization_pose: Pose = Field(default=None)
|
|
102
96
|
type: Literal[TaskTypes.Localize] = TaskTypes.Localize
|
|
103
97
|
|
|
104
98
|
|
|
105
|
-
@dataclass
|
|
106
99
|
class MoveArm(Task):
|
|
107
100
|
"""
|
|
108
101
|
Task which causes the robot to move its arm
|
|
109
102
|
"""
|
|
110
103
|
|
|
111
|
-
arm_pose: str =
|
|
104
|
+
arm_pose: str = Field(default=None)
|
|
112
105
|
type: Literal[TaskTypes.MoveArm] = TaskTypes.MoveArm
|
|
113
106
|
|
|
114
107
|
|
|
115
|
-
@dataclass
|
|
116
108
|
class TakeImage(InspectionTask):
|
|
117
109
|
"""
|
|
118
|
-
Task which causes the robot to take an image towards the given
|
|
110
|
+
Task which causes the robot to take an image towards the given target.
|
|
119
111
|
"""
|
|
120
112
|
|
|
121
|
-
target: Position =
|
|
113
|
+
target: Position = Field(default=None)
|
|
122
114
|
type: Literal[TaskTypes.TakeImage] = TaskTypes.TakeImage
|
|
123
115
|
|
|
124
116
|
@staticmethod
|
|
@@ -126,13 +118,12 @@ class TakeImage(InspectionTask):
|
|
|
126
118
|
return Image
|
|
127
119
|
|
|
128
120
|
|
|
129
|
-
@dataclass
|
|
130
121
|
class TakeThermalImage(InspectionTask):
|
|
131
122
|
"""
|
|
132
|
-
Task which causes the robot to take a thermal image towards the given
|
|
123
|
+
Task which causes the robot to take a thermal image towards the given target.
|
|
133
124
|
"""
|
|
134
125
|
|
|
135
|
-
target: Position =
|
|
126
|
+
target: Position = Field(default=None)
|
|
136
127
|
type: Literal[TaskTypes.TakeThermalImage] = TaskTypes.TakeThermalImage
|
|
137
128
|
|
|
138
129
|
@staticmethod
|
|
@@ -140,16 +131,15 @@ class TakeThermalImage(InspectionTask):
|
|
|
140
131
|
return ThermalImage
|
|
141
132
|
|
|
142
133
|
|
|
143
|
-
@dataclass
|
|
144
134
|
class TakeVideo(InspectionTask):
|
|
145
135
|
"""
|
|
146
|
-
Task which causes the robot to take a video towards the given
|
|
136
|
+
Task which causes the robot to take a video towards the given target.
|
|
147
137
|
|
|
148
138
|
Duration of video is given in seconds.
|
|
149
139
|
"""
|
|
150
140
|
|
|
151
|
-
target: Position =
|
|
152
|
-
duration: float =
|
|
141
|
+
target: Position = Field(default=None)
|
|
142
|
+
duration: float = Field(default=None)
|
|
153
143
|
type: Literal[TaskTypes.TakeVideo] = TaskTypes.TakeVideo
|
|
154
144
|
|
|
155
145
|
@staticmethod
|
|
@@ -157,16 +147,15 @@ class TakeVideo(InspectionTask):
|
|
|
157
147
|
return Video
|
|
158
148
|
|
|
159
149
|
|
|
160
|
-
@dataclass
|
|
161
150
|
class TakeThermalVideo(InspectionTask):
|
|
162
151
|
"""
|
|
163
|
-
Task which causes the robot to record thermal video towards the given
|
|
152
|
+
Task which causes the robot to record thermal video towards the given target
|
|
164
153
|
|
|
165
154
|
Duration of video is given in seconds.
|
|
166
155
|
"""
|
|
167
156
|
|
|
168
|
-
target: Position =
|
|
169
|
-
duration: float =
|
|
157
|
+
target: Position = Field(default=None)
|
|
158
|
+
duration: float = Field(default=None)
|
|
170
159
|
type: Literal[TaskTypes.TakeThermalVideo] = TaskTypes.TakeThermalVideo
|
|
171
160
|
|
|
172
161
|
@staticmethod
|
|
@@ -174,7 +163,6 @@ class TakeThermalVideo(InspectionTask):
|
|
|
174
163
|
return ThermalVideo
|
|
175
164
|
|
|
176
165
|
|
|
177
|
-
@dataclass
|
|
178
166
|
class RecordAudio(InspectionTask):
|
|
179
167
|
"""
|
|
180
168
|
Task which causes the robot to record a video at its position, facing the target.
|
|
@@ -182,8 +170,8 @@ class RecordAudio(InspectionTask):
|
|
|
182
170
|
Duration of audio is given in seconds.
|
|
183
171
|
"""
|
|
184
172
|
|
|
185
|
-
target: Position =
|
|
186
|
-
duration: float =
|
|
173
|
+
target: Position = Field(default=None)
|
|
174
|
+
duration: float = Field(default=None)
|
|
187
175
|
type: Literal[TaskTypes.RecordAudio] = TaskTypes.RecordAudio
|
|
188
176
|
|
|
189
177
|
@staticmethod
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from abc import ABCMeta, abstractmethod
|
|
2
2
|
from queue import Queue
|
|
3
3
|
from threading import Thread
|
|
4
|
-
from typing import Callable, List
|
|
4
|
+
from typing import Callable, List, Optional
|
|
5
5
|
|
|
6
|
-
from robot_interface.models.robots.media import MediaConfig
|
|
7
6
|
from robot_interface.models.initialize import InitializeParams
|
|
8
7
|
from robot_interface.models.inspection.inspection import Inspection
|
|
9
8
|
from robot_interface.models.mission.mission import Mission
|
|
10
9
|
from robot_interface.models.mission.status import RobotStatus, TaskStatus
|
|
11
10
|
from robot_interface.models.mission.task import InspectionTask, Task
|
|
11
|
+
from robot_interface.models.robots.media import MediaConfig
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class RobotInterface(metaclass=ABCMeta):
|
|
@@ -166,8 +166,10 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
166
166
|
|
|
167
167
|
Returns
|
|
168
168
|
-------
|
|
169
|
-
Sequence[
|
|
170
|
-
List containing all the inspection
|
|
169
|
+
Sequence[Inspection]
|
|
170
|
+
List containing all the inspection connected to the given task.
|
|
171
|
+
get_inspection has responsibility to assign the inspection_id of the task
|
|
172
|
+
to the inspection that it returns.
|
|
171
173
|
|
|
172
174
|
Raises
|
|
173
175
|
------
|
|
@@ -226,7 +228,7 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
226
228
|
raise NotImplementedError
|
|
227
229
|
|
|
228
230
|
@abstractmethod
|
|
229
|
-
def generate_media_config(self) -> MediaConfig:
|
|
231
|
+
def generate_media_config(self) -> Optional[MediaConfig]:
|
|
230
232
|
"""
|
|
231
233
|
Generate a JSON containing the url and token needed to establish a media stream
|
|
232
234
|
connection to a robot.
|
|
File without changes
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import logging
|
|
3
|
-
from dataclasses import is_dataclass
|
|
4
|
-
from logging import Logger
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Any, Optional
|
|
7
|
-
|
|
8
|
-
from dacite import Config, from_dict
|
|
9
|
-
|
|
10
|
-
logger: Logger = logging.getLogger("api")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class BaseReader:
|
|
14
|
-
@staticmethod
|
|
15
|
-
def read_json(location: Path) -> dict:
|
|
16
|
-
with open(location) as json_file:
|
|
17
|
-
return json.load(json_file)
|
|
18
|
-
|
|
19
|
-
@staticmethod
|
|
20
|
-
def dict_to_dataclass(
|
|
21
|
-
dataclass_dict: dict,
|
|
22
|
-
target_dataclass: Any,
|
|
23
|
-
cast_config: list = [],
|
|
24
|
-
strict_config: bool = False,
|
|
25
|
-
) -> Optional[Any]:
|
|
26
|
-
if not is_dataclass(target_dataclass):
|
|
27
|
-
raise BaseReaderError("{target_dataclass} is not a dataclass")
|
|
28
|
-
generated_dataclass = from_dict(
|
|
29
|
-
data_class=target_dataclass,
|
|
30
|
-
data=dataclass_dict,
|
|
31
|
-
config=Config(cast=cast_config, strict=strict_config),
|
|
32
|
-
)
|
|
33
|
-
return generated_dataclass
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class BaseReaderError(Exception):
|
|
37
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|