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.
- manta_node/__init__.py +5 -0
- manta_node/__main__.py +57 -0
- manta_node/cli/__init__.py +6 -0
- manta_node/cli/commands/__init__.py +21 -0
- manta_node/cli/commands/cluster.py +419 -0
- manta_node/cli/commands/config.py +490 -0
- manta_node/cli/commands/logs.py +168 -0
- manta_node/cli/commands/start.py +459 -0
- manta_node/cli/commands/status.py +204 -0
- manta_node/cli/commands/stop.py +253 -0
- manta_node/cli/config_manager.py +139 -0
- manta_node/cli/main.py +133 -0
- manta_node/cli/version.py +106 -0
- manta_node/domain/__init__.py +8 -0
- manta_node/domain/task_lifecycle.py +90 -0
- manta_node/infrastructure/__init__.py +13 -0
- manta_node/infrastructure/config/__init__.py +31 -0
- manta_node/infrastructure/config/node_config_manager.py +918 -0
- manta_node/infrastructure/container/__init__.py +11 -0
- manta_node/infrastructure/container/docker_adapter.py +253 -0
- manta_node/infrastructure/container/image_executor.py +222 -0
- manta_node/infrastructure/container/manager.py +549 -0
- manta_node/infrastructure/filesystem/__init__.py +7 -0
- manta_node/infrastructure/filesystem/dataset_manager.py +469 -0
- manta_node/infrastructure/grpc/__init__.py +11 -0
- manta_node/infrastructure/grpc/client.py +373 -0
- manta_node/infrastructure/grpc/local_servicer.py +151 -0
- manta_node/infrastructure/grpc/world_servicer.py +284 -0
- manta_node/infrastructure/metrics/__init__.py +10 -0
- manta_node/infrastructure/metrics/collector.py +94 -0
- manta_node/infrastructure/metrics/metrics_collector.py +351 -0
- manta_node/infrastructure/mqtt/__init__.py +7 -0
- manta_node/infrastructure/mqtt/command_handler.py +450 -0
- manta_node/node_orchestrator.py +462 -0
- manta_node/task_manager.py +677 -0
- manta_node/tasks.py +273 -0
- manta_node/utils.py +52 -0
- manta_node-0.5b0.dist-info/METADATA +794 -0
- manta_node-0.5b0.dist-info/RECORD +43 -0
- manta_node-0.5b0.dist-info/WHEEL +5 -0
- manta_node-0.5b0.dist-info/entry_points.txt +2 -0
- manta_node-0.5b0.dist-info/licenses/LICENSE +683 -0
- manta_node-0.5b0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import (
|
|
6
|
+
AsyncIterable,
|
|
7
|
+
AsyncIterator,
|
|
8
|
+
Iterable,
|
|
9
|
+
Optional,
|
|
10
|
+
Type,
|
|
11
|
+
TypeVar,
|
|
12
|
+
Union,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from manta_common.base_client import GrpcClientBase, MetadataDict
|
|
16
|
+
from manta_common.build.common.informations import (
|
|
17
|
+
DatasetOverviews,
|
|
18
|
+
MetricsSnapshot,
|
|
19
|
+
NodeOverview,
|
|
20
|
+
NodeStatus,
|
|
21
|
+
Registration,
|
|
22
|
+
)
|
|
23
|
+
from manta_common.build.common.results import (
|
|
24
|
+
ChunkResultValues,
|
|
25
|
+
GlobalTag,
|
|
26
|
+
GlobalUpdate,
|
|
27
|
+
GlobalValue,
|
|
28
|
+
Result,
|
|
29
|
+
ResultQuery,
|
|
30
|
+
)
|
|
31
|
+
from manta_common.build.common.system import Empty, Logs, Ok
|
|
32
|
+
from manta_common.build.common.tasks import TaskScheduling
|
|
33
|
+
from manta_common.build.node.node_service import NodeServiceStub, StopSwarmProcess
|
|
34
|
+
from manta_common.errors import MantaError
|
|
35
|
+
from manta_common.retry import RetryPolicy, StreamingRetryPolicy
|
|
36
|
+
from manta_common.traces import Tracer
|
|
37
|
+
|
|
38
|
+
__all__ = ["NodeClient"]
|
|
39
|
+
|
|
40
|
+
T = TypeVar("T")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class NodeClient(GrpcClientBase):
|
|
44
|
+
"""
|
|
45
|
+
Node client facilitates management of requests to Manager with retry
|
|
46
|
+
and connection management capabilities.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
#: Default retry policy for regular methods
|
|
50
|
+
DEFAULT_RETRY_POLICY = RetryPolicy(
|
|
51
|
+
max_retries=3,
|
|
52
|
+
initial_delay=0.2,
|
|
53
|
+
max_delay=10.0,
|
|
54
|
+
backoff_factor=2.0,
|
|
55
|
+
jitter_factor=0.2,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
#: Default retry policy for streaming methods
|
|
59
|
+
DEFAULT_STREAMING_RETRY_POLICY = StreamingRetryPolicy(
|
|
60
|
+
max_retries=3,
|
|
61
|
+
initial_delay=0.2,
|
|
62
|
+
max_delay=10.0,
|
|
63
|
+
backoff_factor=2.0,
|
|
64
|
+
jitter_factor=0.2,
|
|
65
|
+
retry_if_no_items_processed=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def _get_stub_class(self) -> Type[NodeServiceStub]:
|
|
69
|
+
"""
|
|
70
|
+
Get the stub class for this client.
|
|
71
|
+
"""
|
|
72
|
+
return NodeServiceStub
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def metadata(self) -> MetadataDict:
|
|
76
|
+
"""
|
|
77
|
+
Get metadata for gRPC requests.
|
|
78
|
+
|
|
79
|
+
Subclasses can override this property to provide custom metadata.
|
|
80
|
+
Similar to ssl_context property pattern.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
MetadataDict
|
|
85
|
+
Metadata dictionary for gRPC requests
|
|
86
|
+
"""
|
|
87
|
+
return {"authorization": self.secured_token}
|
|
88
|
+
|
|
89
|
+
def __init__(
|
|
90
|
+
self,
|
|
91
|
+
manager_host: str,
|
|
92
|
+
manager_port: int,
|
|
93
|
+
secured_token: str,
|
|
94
|
+
ssl_cert_folder: Optional[Path] = None,
|
|
95
|
+
retry_policy: Optional[RetryPolicy] = None,
|
|
96
|
+
streaming_retry_policy: Optional[StreamingRetryPolicy] = None,
|
|
97
|
+
) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Initialize Node client
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
|
|
104
|
+
Node identifier
|
|
105
|
+
manager_host : str
|
|
106
|
+
Manager hostname
|
|
107
|
+
manager_port : int
|
|
108
|
+
Manager port
|
|
109
|
+
secured_token : str
|
|
110
|
+
Secured token for the Manager first connection
|
|
111
|
+
ssl_cert_folder : Optional[Path]
|
|
112
|
+
SSL certificate folder
|
|
113
|
+
retry_policy : Optional[RetryPolicy]
|
|
114
|
+
Custom retry policy for operations
|
|
115
|
+
streaming_retry_policy : Optional[StreamingRetryPolicy]
|
|
116
|
+
Custom retry policy for streaming operations
|
|
117
|
+
"""
|
|
118
|
+
self.ssl_cert_folder = ssl_cert_folder
|
|
119
|
+
self.secured_token = secured_token
|
|
120
|
+
self.tracer = Tracer(getLogger(__name__))
|
|
121
|
+
|
|
122
|
+
# Log connection configuration for troubleshooting
|
|
123
|
+
security_mode = (
|
|
124
|
+
"TLS"
|
|
125
|
+
if (ssl_cert_folder is not None or manager_port == 443)
|
|
126
|
+
else "insecure"
|
|
127
|
+
)
|
|
128
|
+
self.tracer.info(
|
|
129
|
+
f"Initializing NodeClient for manager at {security_mode}://{manager_host}:{manager_port}"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Log JWT token status without exposing the actual token
|
|
133
|
+
if secured_token:
|
|
134
|
+
token_length = len(secured_token)
|
|
135
|
+
# Basic JWT format validation (should have 3 parts separated by .)
|
|
136
|
+
token_parts = secured_token.count(".") + 1
|
|
137
|
+
if token_parts == 3:
|
|
138
|
+
self.tracer.debug(
|
|
139
|
+
f"JWT token present: {token_length} chars, format appears valid (3 parts)"
|
|
140
|
+
)
|
|
141
|
+
else:
|
|
142
|
+
self.tracer.warning(
|
|
143
|
+
f"JWT token present: {token_length} chars, but format may be invalid "
|
|
144
|
+
f"(expected 3 parts, got {token_parts})"
|
|
145
|
+
)
|
|
146
|
+
else:
|
|
147
|
+
self.tracer.error("JWT token is empty or None - authentication will fail")
|
|
148
|
+
|
|
149
|
+
self.tracer.info(str(self.metadata))
|
|
150
|
+
|
|
151
|
+
super().__init__(
|
|
152
|
+
host=manager_host,
|
|
153
|
+
port=manager_port,
|
|
154
|
+
secure=ssl_cert_folder is not None or manager_port == 443,
|
|
155
|
+
tracer=self.tracer,
|
|
156
|
+
retry_policy=retry_policy,
|
|
157
|
+
streaming_retry_policy=streaming_retry_policy,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
async def is_available(self, request: Empty) -> Ok:
|
|
161
|
+
"""
|
|
162
|
+
Check if the Manager is available
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
request : Empty
|
|
167
|
+
Empty request
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
Ok
|
|
172
|
+
Response
|
|
173
|
+
"""
|
|
174
|
+
return await self.call_service_method("is_available", request)
|
|
175
|
+
|
|
176
|
+
async def register_node(self, request: NodeOverview) -> Registration:
|
|
177
|
+
"""
|
|
178
|
+
Register the node with the Manager via gRPC
|
|
179
|
+
and get back MQTT information
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
request : NodeOverview
|
|
184
|
+
Node ID and its data names
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
-------
|
|
188
|
+
Registration
|
|
189
|
+
Node ID and MQTT information
|
|
190
|
+
"""
|
|
191
|
+
return await self.call_service_method("register_node", request)
|
|
192
|
+
|
|
193
|
+
async def get_task_result(
|
|
194
|
+
self, request: ResultQuery
|
|
195
|
+
) -> AsyncIterator[ChunkResultValues]:
|
|
196
|
+
"""
|
|
197
|
+
Get the swarm results
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
request : ResultQuery
|
|
202
|
+
Result query
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
AsyncIterator[ChunkResultValues]
|
|
207
|
+
Result values
|
|
208
|
+
"""
|
|
209
|
+
async for chunk in self.stream_service_method("get_task_result", request):
|
|
210
|
+
yield chunk
|
|
211
|
+
|
|
212
|
+
async def add_task_result(self, request: AsyncIterable[Result]) -> Ok:
|
|
213
|
+
"""
|
|
214
|
+
Set a swarm result
|
|
215
|
+
|
|
216
|
+
Parameters
|
|
217
|
+
----------
|
|
218
|
+
request : AsyncIterable[Result]
|
|
219
|
+
Task ID, global tag and value
|
|
220
|
+
|
|
221
|
+
Returns
|
|
222
|
+
-------
|
|
223
|
+
Ok
|
|
224
|
+
Response
|
|
225
|
+
"""
|
|
226
|
+
return await self.call_service_method("add_task_result", request)
|
|
227
|
+
|
|
228
|
+
async def get_global(self, request: GlobalTag) -> AsyncIterator[GlobalValue]:
|
|
229
|
+
"""
|
|
230
|
+
Get global values
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
request : GlobalTag
|
|
235
|
+
Swarm ID and global tag
|
|
236
|
+
|
|
237
|
+
Returns
|
|
238
|
+
-------
|
|
239
|
+
AsyncIterator[GlobalValue]
|
|
240
|
+
Global values
|
|
241
|
+
"""
|
|
242
|
+
async for value in self.stream_service_method("get_global", request):
|
|
243
|
+
yield value
|
|
244
|
+
|
|
245
|
+
async def set_global(
|
|
246
|
+
self,
|
|
247
|
+
request: Union[AsyncIterable[GlobalUpdate], Iterable[GlobalUpdate]],
|
|
248
|
+
) -> Ok:
|
|
249
|
+
"""
|
|
250
|
+
Set global values
|
|
251
|
+
|
|
252
|
+
Parameters
|
|
253
|
+
----------
|
|
254
|
+
request : Union[AsyncIterable[GlobalUpdate], Iterable[GlobalUpdate]]
|
|
255
|
+
Task ID, global tag and value
|
|
256
|
+
|
|
257
|
+
Returns
|
|
258
|
+
-------
|
|
259
|
+
Ok
|
|
260
|
+
Response
|
|
261
|
+
"""
|
|
262
|
+
return await self.call_service_method("set_global", request)
|
|
263
|
+
|
|
264
|
+
async def set_node_status(self, request: NodeStatus) -> Ok:
|
|
265
|
+
"""
|
|
266
|
+
Set node status
|
|
267
|
+
|
|
268
|
+
Parameters
|
|
269
|
+
----------
|
|
270
|
+
request : NodeStatus
|
|
271
|
+
Node ID, its status
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
Ok
|
|
276
|
+
Response
|
|
277
|
+
"""
|
|
278
|
+
return await self.call_service_method("set_node_status", request)
|
|
279
|
+
|
|
280
|
+
async def set_system_summary(self, request: MetricsSnapshot) -> Ok:
|
|
281
|
+
"""
|
|
282
|
+
Set system summary
|
|
283
|
+
|
|
284
|
+
Parameters
|
|
285
|
+
----------
|
|
286
|
+
request : MetricsSnapshot
|
|
287
|
+
Node ID and its system information
|
|
288
|
+
|
|
289
|
+
Returns
|
|
290
|
+
-------
|
|
291
|
+
Ok
|
|
292
|
+
Response
|
|
293
|
+
"""
|
|
294
|
+
return await self.call_service_method("set_system_summary", request)
|
|
295
|
+
|
|
296
|
+
async def set_overviews(self, request: DatasetOverviews) -> Ok:
|
|
297
|
+
"""
|
|
298
|
+
Set dataset overviews
|
|
299
|
+
|
|
300
|
+
Parameters
|
|
301
|
+
----------
|
|
302
|
+
request : DatasetOverviews
|
|
303
|
+
Node ID and its dataset overviews
|
|
304
|
+
|
|
305
|
+
Returns
|
|
306
|
+
-------
|
|
307
|
+
Ok
|
|
308
|
+
Response
|
|
309
|
+
"""
|
|
310
|
+
return await self.call_service_method("set_overviews", request)
|
|
311
|
+
|
|
312
|
+
async def stop_swarm(self, request: StopSwarmProcess) -> Ok:
|
|
313
|
+
"""
|
|
314
|
+
Stop the swarm
|
|
315
|
+
|
|
316
|
+
Parameters
|
|
317
|
+
----------
|
|
318
|
+
request : StopSwarmProcess
|
|
319
|
+
Swarm ID
|
|
320
|
+
|
|
321
|
+
Returns
|
|
322
|
+
-------
|
|
323
|
+
Ok
|
|
324
|
+
Response
|
|
325
|
+
"""
|
|
326
|
+
return await self.call_service_method("stop_swarm", request)
|
|
327
|
+
|
|
328
|
+
async def add_task_logs(self, request: AsyncIterable[Logs]) -> Ok:
|
|
329
|
+
"""
|
|
330
|
+
Add task logs to the database
|
|
331
|
+
|
|
332
|
+
Parameters
|
|
333
|
+
----------
|
|
334
|
+
request : AsyncIterable[Logs]
|
|
335
|
+
Task logs
|
|
336
|
+
|
|
337
|
+
Returns
|
|
338
|
+
-------
|
|
339
|
+
Ok
|
|
340
|
+
Response
|
|
341
|
+
"""
|
|
342
|
+
return await self.call_service_method("add_task_logs", request)
|
|
343
|
+
|
|
344
|
+
async def schedule_task(self, request: TaskScheduling) -> Ok:
|
|
345
|
+
"""
|
|
346
|
+
Schedule next task
|
|
347
|
+
|
|
348
|
+
Parameters
|
|
349
|
+
----------
|
|
350
|
+
request : TaskScheduling
|
|
351
|
+
Task scheduling containing node IDs
|
|
352
|
+
|
|
353
|
+
Returns
|
|
354
|
+
-------
|
|
355
|
+
Ok
|
|
356
|
+
Response
|
|
357
|
+
"""
|
|
358
|
+
return await self.call_service_method("schedule_task", request)
|
|
359
|
+
|
|
360
|
+
async def send_error(self, manta_error: MantaError):
|
|
361
|
+
"""
|
|
362
|
+
Send the error to the Manager
|
|
363
|
+
|
|
364
|
+
Parameters
|
|
365
|
+
----------
|
|
366
|
+
error : MantaError
|
|
367
|
+
Error object
|
|
368
|
+
"""
|
|
369
|
+
try:
|
|
370
|
+
self.tracer.debug("Sending MantaError to the Manager")
|
|
371
|
+
await self.call_service_method("send_error", manta_error.to_err())
|
|
372
|
+
except Exception as exc:
|
|
373
|
+
self.tracer.exception(f"Cannot send error to the Manager: {repr(exc)}")
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
from logging import getLogger
|
|
2
|
+
from typing import AsyncIterator
|
|
3
|
+
|
|
4
|
+
from manta_common.build.common.system import Binary
|
|
5
|
+
from manta_common.build.node.light_service import (
|
|
6
|
+
DataRequest,
|
|
7
|
+
DirRequest,
|
|
8
|
+
ExistsResponse,
|
|
9
|
+
ListDirResponse,
|
|
10
|
+
LocalBase,
|
|
11
|
+
ProtoPath,
|
|
12
|
+
ReadText,
|
|
13
|
+
)
|
|
14
|
+
from manta_common.conversions import ID
|
|
15
|
+
from manta_common.decorators import catch_batch_errors, catch_streaming_errors
|
|
16
|
+
from manta_common.traces import Tracer
|
|
17
|
+
from ..filesystem.dataset_manager import DatasetManager
|
|
18
|
+
from ..grpc.client import NodeClient
|
|
19
|
+
|
|
20
|
+
__all__ = ["LocalServicer"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LocalServicer(LocalBase):
|
|
24
|
+
"""
|
|
25
|
+
Local Servicer that provides access to the local data
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
|
|
30
|
+
Node ID
|
|
31
|
+
node_client : NodeClient
|
|
32
|
+
Node client instance
|
|
33
|
+
dataset_manager : DatasetManager
|
|
34
|
+
Dataset manager for handling data operations
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
DTYPES = {
|
|
38
|
+
".txt": "text",
|
|
39
|
+
".csv": "csv",
|
|
40
|
+
".npx": "numpy",
|
|
41
|
+
".npy": "numpy",
|
|
42
|
+
".npz": "numpy",
|
|
43
|
+
".np": "numpy",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
node_client: NodeClient,
|
|
49
|
+
dataset_manager: DatasetManager,
|
|
50
|
+
):
|
|
51
|
+
self.tracer = Tracer(getLogger(__name__))
|
|
52
|
+
self.node_client = node_client
|
|
53
|
+
self.dataset_manager = dataset_manager
|
|
54
|
+
super().__init__()
|
|
55
|
+
|
|
56
|
+
def _set_task_and_swarm_ids(self, data_request: DataRequest):
|
|
57
|
+
self.tracer.set_metadata(
|
|
58
|
+
task_id=ID(data_request.task_id),
|
|
59
|
+
swarm_id=ID(data_request.swarm_id),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@catch_streaming_errors
|
|
63
|
+
async def get_binary_data(self, data_request: DataRequest) -> AsyncIterator[Binary]:
|
|
64
|
+
"""
|
|
65
|
+
Get the binary data
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
data_request : DataRequest
|
|
70
|
+
Data Request containing the name of the file
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
AsyncIterator[Binary]
|
|
75
|
+
Binary data
|
|
76
|
+
|
|
77
|
+
Raises
|
|
78
|
+
------
|
|
79
|
+
MantaLocalError
|
|
80
|
+
If the file is not found
|
|
81
|
+
"""
|
|
82
|
+
self._set_task_and_swarm_ids(data_request)
|
|
83
|
+
for chunk in self.dataset_manager.get_dataset_as_bytes(data_request.name):
|
|
84
|
+
yield Binary(content=chunk)
|
|
85
|
+
|
|
86
|
+
@catch_batch_errors
|
|
87
|
+
async def list_dir(self, request: DirRequest):
|
|
88
|
+
"""
|
|
89
|
+
List the directories in the data folder
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
request : DirRequest
|
|
94
|
+
Data Request
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
ListString
|
|
99
|
+
List of directories
|
|
100
|
+
"""
|
|
101
|
+
self._set_task_and_swarm_ids(request.data_request)
|
|
102
|
+
files = self.dataset_manager.list_files(request.data_request.name, request.path)
|
|
103
|
+
paths = [ProtoPath(value=str(f["name"]), is_file=f["is_file"]) for f in files]
|
|
104
|
+
self.tracer.info(f"Found {len(paths)} entries in directory")
|
|
105
|
+
return ListDirResponse(paths=paths)
|
|
106
|
+
|
|
107
|
+
@catch_streaming_errors
|
|
108
|
+
async def read_file_lines(self, request: ReadText) -> AsyncIterator[Binary]:
|
|
109
|
+
"""
|
|
110
|
+
Read the lines of a file
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
request : ReadText
|
|
115
|
+
Data Request containing the name of the file
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
ListString
|
|
120
|
+
List of lines
|
|
121
|
+
"""
|
|
122
|
+
self._set_task_and_swarm_ids(request.data_request)
|
|
123
|
+
for line in self.dataset_manager.read_file_lines(
|
|
124
|
+
request.data_request.name,
|
|
125
|
+
request.path.value,
|
|
126
|
+
encoding=request.encoding,
|
|
127
|
+
errors=request.errors,
|
|
128
|
+
newline=request.newline,
|
|
129
|
+
):
|
|
130
|
+
yield Binary(content=line)
|
|
131
|
+
|
|
132
|
+
@catch_batch_errors
|
|
133
|
+
async def exists(self, request: DirRequest) -> ExistsResponse:
|
|
134
|
+
"""
|
|
135
|
+
Check if a file exists
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
request : DirRequest
|
|
140
|
+
Data Request with path
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
ExistsResponse
|
|
145
|
+
Response with boolean indicating if the file exists
|
|
146
|
+
"""
|
|
147
|
+
self._set_task_and_swarm_ids(request.data_request)
|
|
148
|
+
exists = self.dataset_manager.check_exists(
|
|
149
|
+
request.data_request.name, request.path
|
|
150
|
+
)
|
|
151
|
+
return ExistsResponse(value=exists)
|