proximl 0.5.16__py3-none-any.whl → 1.0.0__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.
- examples/local_storage.py +0 -2
- proximl/__init__.py +1 -1
- proximl/checkpoints.py +56 -57
- proximl/cli/__init__.py +6 -3
- proximl/cli/checkpoint.py +18 -57
- proximl/cli/dataset.py +17 -57
- proximl/cli/job/__init__.py +11 -53
- proximl/cli/job/create.py +51 -24
- proximl/cli/model.py +14 -56
- proximl/cli/volume.py +18 -57
- proximl/datasets.py +50 -55
- proximl/jobs.py +239 -68
- proximl/models.py +51 -55
- proximl/projects/projects.py +2 -2
- proximl/proximl.py +50 -16
- proximl/utils/__init__.py +1 -0
- proximl/{auth.py → utils/auth.py} +4 -3
- proximl/utils/transfer.py +587 -0
- proximl/volumes.py +48 -53
- {proximl-0.5.16.dist-info → proximl-1.0.0.dist-info}/METADATA +3 -3
- {proximl-0.5.16.dist-info → proximl-1.0.0.dist-info}/RECORD +53 -51
- tests/integration/test_checkpoints_integration.py +4 -3
- tests/integration/test_datasets_integration.py +5 -3
- tests/integration/test_jobs_integration.py +33 -27
- tests/integration/test_models_integration.py +7 -3
- tests/integration/test_volumes_integration.py +2 -2
- tests/unit/cli/test_cli_checkpoint_unit.py +312 -1
- tests/unit/cloudbender/test_nodes_unit.py +112 -0
- tests/unit/cloudbender/test_providers_unit.py +96 -0
- tests/unit/cloudbender/test_regions_unit.py +106 -0
- tests/unit/cloudbender/test_services_unit.py +141 -0
- tests/unit/conftest.py +23 -10
- tests/unit/projects/test_project_data_connectors_unit.py +39 -0
- tests/unit/projects/test_project_datastores_unit.py +37 -0
- tests/unit/projects/test_project_members_unit.py +46 -0
- tests/unit/projects/test_project_services_unit.py +65 -0
- tests/unit/projects/test_projects_unit.py +17 -1
- tests/unit/test_auth_unit.py +17 -2
- tests/unit/test_checkpoints_unit.py +256 -71
- tests/unit/test_datasets_unit.py +218 -68
- tests/unit/test_exceptions.py +133 -0
- tests/unit/test_gpu_types_unit.py +11 -1
- tests/unit/test_jobs_unit.py +1014 -95
- tests/unit/test_main_unit.py +20 -0
- tests/unit/test_models_unit.py +218 -70
- tests/unit/test_proximl_unit.py +627 -3
- tests/unit/test_volumes_unit.py +211 -70
- tests/unit/utils/__init__.py +1 -0
- tests/unit/utils/test_transfer_unit.py +4260 -0
- proximl/cli/connection.py +0 -61
- proximl/connections.py +0 -621
- tests/unit/test_connections_unit.py +0 -182
- {proximl-0.5.16.dist-info → proximl-1.0.0.dist-info}/LICENSE +0 -0
- {proximl-0.5.16.dist-info → proximl-1.0.0.dist-info}/WHEEL +0 -0
- {proximl-0.5.16.dist-info → proximl-1.0.0.dist-info}/entry_points.txt +0 -0
- {proximl-0.5.16.dist-info → proximl-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -44,7 +44,9 @@ class CheckpointsTests:
|
|
|
44
44
|
api_response = dict()
|
|
45
45
|
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
46
46
|
await checkpoints.get("1234")
|
|
47
|
-
mock_proximl._query.assert_called_once_with(
|
|
47
|
+
mock_proximl._query.assert_called_once_with(
|
|
48
|
+
"/checkpoint/1234", "GET", dict()
|
|
49
|
+
)
|
|
48
50
|
|
|
49
51
|
@mark.asyncio
|
|
50
52
|
async def test_list_checkpoints(
|
|
@@ -55,7 +57,30 @@ class CheckpointsTests:
|
|
|
55
57
|
api_response = dict()
|
|
56
58
|
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
57
59
|
await checkpoints.list()
|
|
58
|
-
mock_proximl._query.assert_called_once_with(
|
|
60
|
+
mock_proximl._query.assert_called_once_with(
|
|
61
|
+
"/checkpoint", "GET", dict()
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@mark.asyncio
|
|
65
|
+
async def test_list_public_checkpoints(
|
|
66
|
+
self,
|
|
67
|
+
checkpoints,
|
|
68
|
+
mock_proximl,
|
|
69
|
+
):
|
|
70
|
+
api_response = [
|
|
71
|
+
dict(
|
|
72
|
+
checkpoint_uuid="1",
|
|
73
|
+
name="public checkpoint",
|
|
74
|
+
status="ready",
|
|
75
|
+
)
|
|
76
|
+
]
|
|
77
|
+
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
78
|
+
result = await checkpoints.list_public()
|
|
79
|
+
mock_proximl._query.assert_called_once_with(
|
|
80
|
+
"/checkpoint/public", "GET", dict()
|
|
81
|
+
)
|
|
82
|
+
assert len(result) == 1
|
|
83
|
+
assert isinstance(result[0], specimen.Checkpoint)
|
|
59
84
|
|
|
60
85
|
@mark.asyncio
|
|
61
86
|
async def test_remove_checkpoint(
|
|
@@ -133,9 +158,7 @@ class CheckpointTests:
|
|
|
133
158
|
|
|
134
159
|
@mark.asyncio
|
|
135
160
|
async def test_checkpoint_get_log_url(self, checkpoint, mock_proximl):
|
|
136
|
-
api_response =
|
|
137
|
-
"https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/logs/first_one.zip"
|
|
138
|
-
)
|
|
161
|
+
api_response = "https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/logs/first_one.zip"
|
|
139
162
|
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
140
163
|
response = await checkpoint.get_log_url()
|
|
141
164
|
mock_proximl._query.assert_called_once_with(
|
|
@@ -160,81 +183,155 @@ class CheckpointTests:
|
|
|
160
183
|
assert response == api_response
|
|
161
184
|
|
|
162
185
|
@mark.asyncio
|
|
163
|
-
async def
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"
|
|
186
|
+
async def test_checkpoint_connect_downloading_status(self, mock_proximl):
|
|
187
|
+
checkpoint = specimen.Checkpoint(
|
|
188
|
+
mock_proximl,
|
|
189
|
+
checkpoint_uuid="1",
|
|
190
|
+
project_uuid="proj-id-1",
|
|
191
|
+
name="test checkpoint",
|
|
192
|
+
status="downloading",
|
|
193
|
+
auth_token="test-token",
|
|
194
|
+
hostname="example.com",
|
|
195
|
+
source_uri="/path/to/source",
|
|
168
196
|
)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
197
|
+
|
|
198
|
+
with patch(
|
|
199
|
+
"proximl.checkpoints.Checkpoint.refresh", new_callable=AsyncMock
|
|
200
|
+
) as mock_refresh:
|
|
201
|
+
with patch(
|
|
202
|
+
"proximl.checkpoints.upload", new_callable=AsyncMock
|
|
203
|
+
) as mock_upload:
|
|
204
|
+
await checkpoint.connect()
|
|
205
|
+
mock_refresh.assert_called_once()
|
|
206
|
+
mock_upload.assert_called_once_with(
|
|
207
|
+
"example.com", "test-token", "/path/to/source"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
@mark.asyncio
|
|
211
|
+
async def test_checkpoint_connect_exporting_status(
|
|
212
|
+
self, mock_proximl, tmp_path
|
|
213
|
+
):
|
|
214
|
+
output_dir = str(tmp_path / "output")
|
|
215
|
+
checkpoint = specimen.Checkpoint(
|
|
216
|
+
mock_proximl,
|
|
217
|
+
checkpoint_uuid="1",
|
|
218
|
+
project_uuid="proj-id-1",
|
|
219
|
+
name="test checkpoint",
|
|
220
|
+
status="exporting",
|
|
221
|
+
auth_token="test-token",
|
|
222
|
+
hostname="example.com",
|
|
223
|
+
output_uri=output_dir,
|
|
173
224
|
)
|
|
174
|
-
assert response == api_response
|
|
175
225
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
226
|
+
with patch(
|
|
227
|
+
"proximl.checkpoints.Checkpoint.refresh", new_callable=AsyncMock
|
|
228
|
+
) as mock_refresh:
|
|
229
|
+
with patch(
|
|
230
|
+
"proximl.checkpoints.download", new_callable=AsyncMock
|
|
231
|
+
) as mock_download:
|
|
232
|
+
await checkpoint.connect()
|
|
233
|
+
mock_refresh.assert_called_once()
|
|
234
|
+
mock_download.assert_called_once_with(
|
|
235
|
+
"example.com", "test-token", output_dir
|
|
236
|
+
)
|
|
180
237
|
|
|
181
|
-
|
|
238
|
+
@mark.asyncio
|
|
239
|
+
async def test_checkpoint_connect_new_status_waits_for_downloading(
|
|
240
|
+
self, mock_proximl
|
|
241
|
+
):
|
|
182
242
|
checkpoint = specimen.Checkpoint(
|
|
183
243
|
mock_proximl,
|
|
184
244
|
checkpoint_uuid="1",
|
|
185
|
-
project_uuid="
|
|
186
|
-
name="
|
|
245
|
+
project_uuid="proj-id-1",
|
|
246
|
+
name="test checkpoint",
|
|
187
247
|
status="new",
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
"
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
"
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
with patch(
|
|
251
|
+
"proximl.checkpoints.Checkpoint.wait_for", new_callable=AsyncMock
|
|
252
|
+
) as mock_wait:
|
|
253
|
+
with patch(
|
|
254
|
+
"proximl.checkpoints.Checkpoint.refresh",
|
|
255
|
+
new_callable=AsyncMock,
|
|
256
|
+
) as mock_refresh:
|
|
257
|
+
# After refresh, status becomes downloading
|
|
258
|
+
def update_status():
|
|
259
|
+
checkpoint._status = "downloading"
|
|
260
|
+
checkpoint._checkpoint.update(
|
|
261
|
+
{
|
|
262
|
+
"auth_token": "test-token",
|
|
263
|
+
"hostname": "example.com",
|
|
264
|
+
"source_uri": "/path/to/source",
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
mock_refresh.side_effect = update_status
|
|
269
|
+
|
|
270
|
+
with patch(
|
|
271
|
+
"proximl.checkpoints.upload", new_callable=AsyncMock
|
|
272
|
+
) as mock_upload:
|
|
273
|
+
await checkpoint.connect()
|
|
274
|
+
mock_wait.assert_called_once_with("downloading")
|
|
275
|
+
mock_refresh.assert_called_once()
|
|
276
|
+
mock_upload.assert_called_once()
|
|
214
277
|
|
|
215
278
|
@mark.asyncio
|
|
216
|
-
async def
|
|
279
|
+
async def test_checkpoint_connect_invalid_status(self, mock_proximl):
|
|
280
|
+
checkpoint = specimen.Checkpoint(
|
|
281
|
+
mock_proximl,
|
|
282
|
+
checkpoint_uuid="1",
|
|
283
|
+
project_uuid="proj-id-1",
|
|
284
|
+
name="test checkpoint",
|
|
285
|
+
status="ready",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
with raises(
|
|
289
|
+
SpecificationError,
|
|
290
|
+
match="You can only connect to downloading or exporting checkpoints",
|
|
291
|
+
):
|
|
292
|
+
await checkpoint.connect()
|
|
293
|
+
|
|
294
|
+
@mark.asyncio
|
|
295
|
+
async def test_checkpoint_connect_missing_properties_downloading(
|
|
296
|
+
self, mock_proximl
|
|
297
|
+
):
|
|
298
|
+
checkpoint = specimen.Checkpoint(
|
|
299
|
+
mock_proximl,
|
|
300
|
+
checkpoint_uuid="1",
|
|
301
|
+
project_uuid="proj-id-1",
|
|
302
|
+
name="test checkpoint",
|
|
303
|
+
status="downloading",
|
|
304
|
+
)
|
|
305
|
+
|
|
217
306
|
with patch(
|
|
218
|
-
"proximl.checkpoints.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
assert resp == "connected"
|
|
307
|
+
"proximl.checkpoints.Checkpoint.refresh", new_callable=AsyncMock
|
|
308
|
+
):
|
|
309
|
+
with raises(
|
|
310
|
+
SpecificationError,
|
|
311
|
+
match="missing required connection properties",
|
|
312
|
+
):
|
|
313
|
+
await checkpoint.connect()
|
|
226
314
|
|
|
227
315
|
@mark.asyncio
|
|
228
|
-
async def
|
|
316
|
+
async def test_checkpoint_connect_missing_properties_exporting(
|
|
317
|
+
self, mock_proximl
|
|
318
|
+
):
|
|
319
|
+
checkpoint = specimen.Checkpoint(
|
|
320
|
+
mock_proximl,
|
|
321
|
+
checkpoint_uuid="1",
|
|
322
|
+
project_uuid="proj-id-1",
|
|
323
|
+
name="test checkpoint",
|
|
324
|
+
status="exporting",
|
|
325
|
+
)
|
|
326
|
+
|
|
229
327
|
with patch(
|
|
230
|
-
"proximl.checkpoints.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
assert resp == "removed"
|
|
328
|
+
"proximl.checkpoints.Checkpoint.refresh", new_callable=AsyncMock
|
|
329
|
+
):
|
|
330
|
+
with raises(
|
|
331
|
+
SpecificationError,
|
|
332
|
+
match="missing required connection properties",
|
|
333
|
+
):
|
|
334
|
+
await checkpoint.connect()
|
|
238
335
|
|
|
239
336
|
@mark.asyncio
|
|
240
337
|
async def test_checkpoint_remove(self, checkpoint, mock_proximl):
|
|
@@ -340,7 +437,9 @@ class CheckpointTests:
|
|
|
340
437
|
assert response.id == "data-id-1"
|
|
341
438
|
|
|
342
439
|
@mark.asyncio
|
|
343
|
-
async def test_checkpoint_wait_for_successful(
|
|
440
|
+
async def test_checkpoint_wait_for_successful(
|
|
441
|
+
self, checkpoint, mock_proximl
|
|
442
|
+
):
|
|
344
443
|
api_response = {
|
|
345
444
|
"customer_uuid": "cus-id-1",
|
|
346
445
|
"checkpoint_uuid": "data-id-1",
|
|
@@ -373,7 +472,9 @@ class CheckpointTests:
|
|
|
373
472
|
mock_proximl._query.assert_not_called()
|
|
374
473
|
|
|
375
474
|
@mark.asyncio
|
|
376
|
-
async def test_checkpoint_wait_for_incorrect_status(
|
|
475
|
+
async def test_checkpoint_wait_for_incorrect_status(
|
|
476
|
+
self, checkpoint, mock_proximl
|
|
477
|
+
):
|
|
377
478
|
api_response = None
|
|
378
479
|
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
379
480
|
with raises(SpecificationError):
|
|
@@ -381,7 +482,9 @@ class CheckpointTests:
|
|
|
381
482
|
mock_proximl._query.assert_not_called()
|
|
382
483
|
|
|
383
484
|
@mark.asyncio
|
|
384
|
-
async def test_checkpoint_wait_for_with_delay(
|
|
485
|
+
async def test_checkpoint_wait_for_with_delay(
|
|
486
|
+
self, checkpoint, mock_proximl
|
|
487
|
+
):
|
|
385
488
|
api_response_initial = dict(
|
|
386
489
|
checkpoint_uuid="1",
|
|
387
490
|
name="first one",
|
|
@@ -437,7 +540,9 @@ class CheckpointTests:
|
|
|
437
540
|
self, checkpoint, mock_proximl
|
|
438
541
|
):
|
|
439
542
|
mock_proximl._query = AsyncMock(
|
|
440
|
-
side_effect=ApiError(
|
|
543
|
+
side_effect=ApiError(
|
|
544
|
+
404, dict(errorMessage="Checkpoint Not Found")
|
|
545
|
+
)
|
|
441
546
|
)
|
|
442
547
|
await checkpoint.wait_for("archived")
|
|
443
548
|
mock_proximl._query.assert_called()
|
|
@@ -447,8 +552,88 @@ class CheckpointTests:
|
|
|
447
552
|
self, checkpoint, mock_proximl
|
|
448
553
|
):
|
|
449
554
|
mock_proximl._query = AsyncMock(
|
|
450
|
-
side_effect=ApiError(
|
|
555
|
+
side_effect=ApiError(
|
|
556
|
+
404, dict(errorMessage="Checkpoint Not Found")
|
|
557
|
+
)
|
|
451
558
|
)
|
|
452
559
|
with raises(ApiError):
|
|
453
560
|
await checkpoint.wait_for("ready")
|
|
454
561
|
mock_proximl._query.assert_called()
|
|
562
|
+
|
|
563
|
+
@mark.asyncio
|
|
564
|
+
async def test_checkpoint_rename(self, checkpoint, mock_proximl):
|
|
565
|
+
api_response = dict(
|
|
566
|
+
checkpoint_uuid="1",
|
|
567
|
+
name="renamed checkpoint",
|
|
568
|
+
project_uuid="proj-id-1",
|
|
569
|
+
status="ready",
|
|
570
|
+
)
|
|
571
|
+
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
572
|
+
result = await checkpoint.rename("renamed checkpoint")
|
|
573
|
+
mock_proximl._query.assert_called_once_with(
|
|
574
|
+
"/checkpoint/1",
|
|
575
|
+
"PATCH",
|
|
576
|
+
dict(project_uuid="proj-id-1"),
|
|
577
|
+
dict(name="renamed checkpoint"),
|
|
578
|
+
)
|
|
579
|
+
assert result == checkpoint
|
|
580
|
+
assert checkpoint.name == "renamed checkpoint"
|
|
581
|
+
|
|
582
|
+
@mark.asyncio
|
|
583
|
+
async def test_checkpoint_export(self, checkpoint, mock_proximl):
|
|
584
|
+
api_response = dict(
|
|
585
|
+
checkpoint_uuid="1",
|
|
586
|
+
name="first one",
|
|
587
|
+
project_uuid="proj-id-1",
|
|
588
|
+
status="exporting",
|
|
589
|
+
)
|
|
590
|
+
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
591
|
+
result = await checkpoint.export("aws", "s3://bucket/path", dict(key="value"))
|
|
592
|
+
mock_proximl._query.assert_called_once_with(
|
|
593
|
+
"/checkpoint/1/export",
|
|
594
|
+
"POST",
|
|
595
|
+
dict(project_uuid="proj-id-1"),
|
|
596
|
+
dict(
|
|
597
|
+
output_type="aws",
|
|
598
|
+
output_uri="s3://bucket/path",
|
|
599
|
+
output_options=dict(key="value"),
|
|
600
|
+
),
|
|
601
|
+
)
|
|
602
|
+
assert result == checkpoint
|
|
603
|
+
assert checkpoint.status == "exporting"
|
|
604
|
+
|
|
605
|
+
@mark.asyncio
|
|
606
|
+
async def test_checkpoint_export_default_options(self, checkpoint, mock_proximl):
|
|
607
|
+
api_response = dict(
|
|
608
|
+
checkpoint_uuid="1",
|
|
609
|
+
name="first one",
|
|
610
|
+
project_uuid="proj-id-1",
|
|
611
|
+
status="exporting",
|
|
612
|
+
)
|
|
613
|
+
mock_proximl._query = AsyncMock(return_value=api_response)
|
|
614
|
+
result = await checkpoint.export("aws", "s3://bucket/path")
|
|
615
|
+
mock_proximl._query.assert_called_once_with(
|
|
616
|
+
"/checkpoint/1/export",
|
|
617
|
+
"POST",
|
|
618
|
+
dict(project_uuid="proj-id-1"),
|
|
619
|
+
dict(
|
|
620
|
+
output_type="aws",
|
|
621
|
+
output_uri="s3://bucket/path",
|
|
622
|
+
output_options=dict(),
|
|
623
|
+
),
|
|
624
|
+
)
|
|
625
|
+
assert result == checkpoint
|
|
626
|
+
|
|
627
|
+
@mark.asyncio
|
|
628
|
+
async def test_checkpoint_wait_for_timeout_validation(
|
|
629
|
+
self, checkpoint, mock_proximl
|
|
630
|
+
):
|
|
631
|
+
with raises(SpecificationError) as exc_info:
|
|
632
|
+
await checkpoint.wait_for("ready", timeout=25 * 60 * 60) # > 24 hours
|
|
633
|
+
assert "timeout" in str(exc_info.value.attribute).lower()
|
|
634
|
+
assert "less than" in str(exc_info.value.message).lower()
|
|
635
|
+
|
|
636
|
+
def test_checkpoint_billed_size_property(self, checkpoint, mock_proximl):
|
|
637
|
+
"""Test billed_size property access."""
|
|
638
|
+
checkpoint._billed_size = 50000
|
|
639
|
+
assert checkpoint.billed_size == 50000
|