manta-node 0.5b0__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.
Files changed (43) hide show
  1. manta_node/__init__.py +5 -0
  2. manta_node/__main__.py +57 -0
  3. manta_node/cli/__init__.py +6 -0
  4. manta_node/cli/commands/__init__.py +21 -0
  5. manta_node/cli/commands/cluster.py +419 -0
  6. manta_node/cli/commands/config.py +490 -0
  7. manta_node/cli/commands/logs.py +168 -0
  8. manta_node/cli/commands/start.py +459 -0
  9. manta_node/cli/commands/status.py +204 -0
  10. manta_node/cli/commands/stop.py +253 -0
  11. manta_node/cli/config_manager.py +139 -0
  12. manta_node/cli/main.py +133 -0
  13. manta_node/cli/version.py +106 -0
  14. manta_node/domain/__init__.py +8 -0
  15. manta_node/domain/task_lifecycle.py +90 -0
  16. manta_node/infrastructure/__init__.py +13 -0
  17. manta_node/infrastructure/config/__init__.py +31 -0
  18. manta_node/infrastructure/config/node_config_manager.py +918 -0
  19. manta_node/infrastructure/container/__init__.py +11 -0
  20. manta_node/infrastructure/container/docker_adapter.py +253 -0
  21. manta_node/infrastructure/container/image_executor.py +222 -0
  22. manta_node/infrastructure/container/manager.py +549 -0
  23. manta_node/infrastructure/filesystem/__init__.py +7 -0
  24. manta_node/infrastructure/filesystem/dataset_manager.py +469 -0
  25. manta_node/infrastructure/grpc/__init__.py +11 -0
  26. manta_node/infrastructure/grpc/client.py +373 -0
  27. manta_node/infrastructure/grpc/local_servicer.py +151 -0
  28. manta_node/infrastructure/grpc/world_servicer.py +284 -0
  29. manta_node/infrastructure/metrics/__init__.py +10 -0
  30. manta_node/infrastructure/metrics/collector.py +94 -0
  31. manta_node/infrastructure/metrics/metrics_collector.py +351 -0
  32. manta_node/infrastructure/mqtt/__init__.py +7 -0
  33. manta_node/infrastructure/mqtt/command_handler.py +450 -0
  34. manta_node/node_orchestrator.py +462 -0
  35. manta_node/task_manager.py +677 -0
  36. manta_node/tasks.py +273 -0
  37. manta_node/utils.py +52 -0
  38. manta_node-0.5b0.dist-info/METADATA +794 -0
  39. manta_node-0.5b0.dist-info/RECORD +43 -0
  40. manta_node-0.5b0.dist-info/WHEEL +5 -0
  41. manta_node-0.5b0.dist-info/entry_points.txt +2 -0
  42. manta_node-0.5b0.dist-info/licenses/LICENSE +683 -0
  43. manta_node-0.5b0.dist-info/top_level.txt +1 -0
manta_node/tasks.py ADDED
@@ -0,0 +1,273 @@
1
+ from datetime import datetime
2
+ from pathlib import Path
3
+ from typing import Callable, Iterable, Iterator, List, Tuple
4
+
5
+ from manta_common.build.common.tasks import MqttTask, TaskStatus, TaskUpdate
6
+ from manta_common.conversions import ID, TupleID
7
+ from .domain.task_lifecycle import TaskLifecycleService, TaskTransitionRule
8
+
9
+
10
+ class TaskProgression:
11
+ """
12
+ Task progression is a data structure which holds :
13
+
14
+ * a task update
15
+ * a module file
16
+ * a start time
17
+ """
18
+
19
+ __slots__ = ["task_update", "module_file", "start_time", "last_log_collected"]
20
+
21
+ def __init__(
22
+ self, task_update: TaskUpdate, module_file: Path, start_time: datetime
23
+ ):
24
+ self.task_update = task_update
25
+ self.module_file = module_file
26
+ self.start_time = start_time
27
+ self.last_log_collected = start_time
28
+
29
+ @property
30
+ def task_id(self) -> ID:
31
+ """
32
+ Get Task ID
33
+
34
+ Returns
35
+ -------
36
+ ID
37
+ Task ID
38
+ """
39
+ return ID(self.task_update.task_id)
40
+
41
+ @property
42
+ def swarm_id(self) -> ID:
43
+ """
44
+ Get Swarm ID
45
+
46
+ Returns
47
+ -------
48
+ ID
49
+ Swarm ID
50
+ """
51
+ return ID(self.task_update.swarm_id)
52
+
53
+ @property
54
+ def task_status(self) -> TaskStatus:
55
+ """
56
+ Get Task Status
57
+
58
+ Returns
59
+ -------
60
+ TaskStatus
61
+ Task Status
62
+ """
63
+ return self.task_update.task_status
64
+
65
+ @task_status.setter
66
+ def task_status(self, task_status: TaskStatus):
67
+ """
68
+ Set a new task status
69
+
70
+ Parameters
71
+ ----------
72
+ task_status : TaskStatus
73
+ Task Status to set
74
+ """
75
+ self.task_update.task_status = task_status
76
+
77
+ def unlink(self, missing_ok: bool = True):
78
+ """
79
+ Unlink module file
80
+
81
+ Parameters
82
+ ----------
83
+ missing_ok : bool
84
+ Extra parameter from :code:`Path.unlink`
85
+ """
86
+ self.module_file.unlink(missing_ok)
87
+
88
+ def is_active_task(self) -> bool:
89
+ """
90
+ Check if is an active task
91
+
92
+ Returns
93
+ -------
94
+ bool
95
+ Is active task
96
+ """
97
+ # Use domain service for business logic
98
+ return TaskLifecycleService.is_active(self.task_status)
99
+
100
+ def is_finished_task(self) -> bool:
101
+ """
102
+ Check if is a finished task
103
+
104
+ Returns
105
+ -------
106
+ bool
107
+ Is a finished task
108
+ """
109
+ # Use domain rule for terminal state check
110
+ return TaskTransitionRule.is_finished(self.task_status)
111
+
112
+ def compare_iteration(self, mqtt_task: MqttTask) -> bool:
113
+ """
114
+ Compare iteration between a task from MQTT and itself
115
+
116
+ Parameters
117
+ ----------
118
+ mqtt_task : MqttTask
119
+ Task from MQTT
120
+
121
+ Returns
122
+ -------
123
+ bool
124
+ Same iteration
125
+ """
126
+ return (
127
+ self.task_update.iteration == mqtt_task.iteration
128
+ and self.task_update.circular == mqtt_task.circular
129
+ )
130
+
131
+
132
+ class TaskProgressions:
133
+ """
134
+ List of Task Progression used in Task Manager and World Servicer
135
+ """
136
+
137
+ __slots__ = ["_tasks", "_env_ids"]
138
+
139
+ def __init__(self):
140
+ self._tasks: List[TaskProgression] = []
141
+ self._env_ids: List[Tuple[TupleID, TupleID]] = []
142
+
143
+ def __iter__(self) -> Iterator[TaskProgression]:
144
+ """
145
+ Iterate over tasks
146
+
147
+ Returns
148
+ -------
149
+ Iterator[TaskProgression]
150
+ Iterator of task progressions
151
+ """
152
+ return iter(self._tasks)
153
+
154
+ def __getitem__(self, env_id: Tuple[TupleID, TupleID]) -> TaskProgression:
155
+ """
156
+ Return the task progression given the task ID
157
+
158
+ Parameters
159
+ ----------
160
+ env_id : str
161
+ Task and Swarms IDs in a tuple
162
+
163
+ Returns
164
+ -------
165
+ TaskProgression
166
+ Task Progression
167
+ """
168
+ if env_id not in self._env_ids:
169
+ raise KeyError(
170
+ f"Cannot get task due to {env_id} not found in tasks {self._env_ids}"
171
+ )
172
+ return self._tasks[self._env_ids.index(env_id)]
173
+
174
+ def __contains__(self, env_id: Tuple[TupleID, TupleID]) -> bool:
175
+ """
176
+ Check if the task ID exists in itself
177
+
178
+ Parameters
179
+ ----------
180
+ env_id : Tuple[TupleID, TupleID]
181
+ Task and Swarms IDs in a tuple
182
+
183
+ Returns
184
+ -------
185
+ bool
186
+ It contains the task ID
187
+ """
188
+ return env_id in self._env_ids
189
+
190
+ def append(self, task_progression: TaskProgression):
191
+ """
192
+ Append a task progression
193
+
194
+ Parameters
195
+ ----------
196
+ task_progression : TaskProgression
197
+ Task Progression
198
+ """
199
+ self._tasks.append(task_progression)
200
+ self._env_ids.append(
201
+ (
202
+ ID(task_progression.task_update.swarm_id).tid,
203
+ task_progression.task_id.tid,
204
+ )
205
+ )
206
+
207
+ def filter(
208
+ self, condition: Callable[[TaskProgression], bool]
209
+ ) -> Iterable[TaskProgression]:
210
+ """
211
+ Filter keys given the condition function
212
+
213
+ Parameters
214
+ ----------
215
+ condition : Callable[[TaskProgression], bool]
216
+ Condition function
217
+
218
+ Returns
219
+ -------
220
+ Iterable[TaskProgression]
221
+ Filtered keys
222
+ """
223
+ return filter(condition, self._tasks)
224
+
225
+ def pop(self, env_id: Tuple[TupleID, TupleID]) -> TaskProgression:
226
+ """
227
+ Pop a task progression given the task ID
228
+
229
+ Parameters
230
+ ----------
231
+ task_id : Tuple[TupleID, TupleID]
232
+ Task and Swarms IDs in a tuple
233
+
234
+ Returns
235
+ -------
236
+ TaskProgression
237
+ Task progression popped
238
+ """
239
+ if env_id not in self._env_ids:
240
+ raise KeyError(f"Cannot pop task due to {env_id} not found in tasks")
241
+ index = self._env_ids.index(env_id)
242
+ self._env_ids.pop(index)
243
+ return self._tasks.pop(index)
244
+
245
+ def active_tasks(self) -> Iterable[TaskProgression]:
246
+ """
247
+ Return an iterable of active tasks
248
+
249
+ Returns
250
+ -------
251
+ Iterable[TaskProgression]
252
+ Active task progressions
253
+ """
254
+ return (
255
+ task_progression
256
+ for task_progression in self._tasks
257
+ if task_progression.is_active_task()
258
+ )
259
+
260
+ def finished_tasks(self) -> Iterable[TaskProgression]:
261
+ """
262
+ Return an iterable of finished tasks
263
+
264
+ Returns
265
+ -------
266
+ Iterable[TaskProgression]
267
+ Finished task progressions
268
+ """
269
+ return (
270
+ task_progression
271
+ for task_progression in self._tasks
272
+ if task_progression.is_finished_task()
273
+ )
manta_node/utils.py ADDED
@@ -0,0 +1,52 @@
1
+ from pathlib import Path
2
+ from typing import List
3
+
4
+ from manta_common.build.common.informations import Overview
5
+
6
+ __all__ = ["collect_dataset_overviews"]
7
+
8
+ DTYPES = {
9
+ ".txt": "text",
10
+ ".csv": "csv",
11
+ ".npx": "numpy",
12
+ ".npy": "numpy",
13
+ ".npz": "numpy",
14
+ ".np": "numpy",
15
+ }
16
+
17
+
18
+ def collect_dataset_overviews(data_folder: Path) -> List[Overview]:
19
+ """
20
+ Collect dataset overviews including :
21
+
22
+ - name of a dataset
23
+ - its description
24
+ - its dtype (numpy, pytorch ...)
25
+
26
+ Parameters
27
+ ----------
28
+ data_folder: Path
29
+ Data folder
30
+
31
+ Returns
32
+ -------
33
+ List[Overview]
34
+ List of dataset overviews
35
+ """
36
+ overviews = []
37
+ # Check if the file exists in the data_folder
38
+ if not data_folder.exists():
39
+ # Create the data folder
40
+ data_folder.mkdir(exist_ok=True)
41
+ return overviews
42
+
43
+ # Get the list of files in the data_folder
44
+ overviews = [
45
+ Overview(
46
+ name=file.name,
47
+ description="No description available",
48
+ dtype=DTYPES.get(file.suffix, "binary") if file.is_file() else "folder",
49
+ )
50
+ for file in data_folder.iterdir()
51
+ ]
52
+ return overviews