trainml 0.5.8__py3-none-any.whl → 0.5.11__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.
- tests/integration/projects/__init__.py +0 -0
- tests/integration/projects/conftest.py +10 -0
- tests/integration/projects/test_projects_data_connectors_integration.py +44 -0
- tests/integration/projects/test_projects_datastores_integration.py +42 -0
- tests/integration/{test_projects_integration.py → projects/test_projects_integration.py} +0 -6
- tests/integration/projects/test_projects_keys_integration.py +43 -0
- tests/integration/projects/test_projects_secrets_integration.py +44 -0
- tests/integration/projects/test_projects_services_integration.py +44 -0
- tests/integration/test_checkpoints_integration.py +1 -2
- tests/integration/test_models_integration.py +0 -1
- tests/unit/cli/projects/__init__.py +0 -0
- tests/unit/cli/projects/test_cli_project_data_connector_unit.py +28 -0
- tests/unit/cli/projects/test_cli_project_datastore_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_key_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_secret_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_service_unit.py +26 -0
- tests/unit/cli/projects/test_cli_project_unit.py +19 -0
- tests/unit/cloudbender/test_datastores_unit.py +1 -5
- tests/unit/conftest.py +146 -3
- tests/unit/projects/__init__.py +0 -0
- tests/unit/projects/test_project_data_connectors_unit.py +102 -0
- tests/unit/projects/test_project_datastores_unit.py +96 -0
- tests/unit/projects/test_project_keys_unit.py +96 -0
- tests/unit/projects/test_project_secrets_unit.py +101 -0
- tests/unit/projects/test_project_services_unit.py +102 -0
- tests/unit/projects/test_projects_unit.py +128 -0
- tests/unit/test_checkpoints_unit.py +15 -23
- tests/unit/test_datasets_unit.py +15 -20
- tests/unit/test_models_unit.py +13 -16
- tests/unit/test_volumes_unit.py +3 -0
- trainml/__init__.py +1 -1
- trainml/checkpoints.py +14 -3
- trainml/cli/cloudbender/datastore.py +2 -7
- trainml/cli/project/__init__.py +84 -0
- trainml/cli/project/data_connector.py +61 -0
- trainml/cli/project/datastore.py +61 -0
- trainml/cli/project/key.py +124 -0
- trainml/cli/project/secret.py +71 -0
- trainml/cli/project/service.py +61 -0
- trainml/cloudbender/data_connectors.py +8 -0
- trainml/cloudbender/datastores.py +9 -19
- trainml/cloudbender/nodes.py +44 -1
- trainml/cloudbender/providers.py +53 -0
- trainml/cloudbender/regions.py +48 -0
- trainml/datasets.py +14 -3
- trainml/exceptions.py +51 -0
- trainml/jobs.py +2 -13
- trainml/models.py +14 -3
- trainml/projects/__init__.py +3 -0
- trainml/projects/data_connectors.py +63 -0
- trainml/projects/datastores.py +58 -0
- trainml/projects/keys.py +71 -0
- trainml/projects/projects.py +83 -0
- trainml/projects/secrets.py +70 -0
- trainml/projects/services.py +63 -0
- trainml/volumes.py +15 -3
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/METADATA +1 -1
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/RECORD +64 -38
- tests/unit/cli/cloudbender/test_cli_reservation_unit.py +0 -34
- tests/unit/cli/test_cli_project_unit.py +0 -42
- tests/unit/cloudbender/test_reservations_unit.py +0 -173
- tests/unit/test_projects_unit.py +0 -320
- trainml/cli/cloudbender/reservation.py +0 -159
- trainml/cli/project.py +0 -149
- trainml/cloudbender/reservations.py +0 -126
- trainml/projects.py +0 -228
- /tests/unit/{test_auth.py → test_auth_unit.py} +0 -0
- /tests/unit/{test_trainml.py → test_trainml_unit.py} +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/LICENSE +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/WHEEL +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/entry_points.txt +0 -0
- {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/top_level.txt +0 -0
|
@@ -44,9 +44,7 @@ class CheckpointsTests:
|
|
|
44
44
|
api_response = dict()
|
|
45
45
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
46
46
|
await checkpoints.get("1234")
|
|
47
|
-
mock_trainml._query.assert_called_once_with(
|
|
48
|
-
"/checkpoint/1234", "GET", dict()
|
|
49
|
-
)
|
|
47
|
+
mock_trainml._query.assert_called_once_with("/checkpoint/1234", "GET", dict())
|
|
50
48
|
|
|
51
49
|
@mark.asyncio
|
|
52
50
|
async def test_list_checkpoints(
|
|
@@ -57,9 +55,7 @@ class CheckpointsTests:
|
|
|
57
55
|
api_response = dict()
|
|
58
56
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
59
57
|
await checkpoints.list()
|
|
60
|
-
mock_trainml._query.assert_called_once_with(
|
|
61
|
-
"/checkpoint", "GET", dict()
|
|
62
|
-
)
|
|
58
|
+
mock_trainml._query.assert_called_once_with("/checkpoint", "GET", dict())
|
|
63
59
|
|
|
64
60
|
@mark.asyncio
|
|
65
61
|
async def test_remove_checkpoint(
|
|
@@ -86,11 +82,13 @@ class CheckpointsTests:
|
|
|
86
82
|
name="new checkpoint",
|
|
87
83
|
source_type="aws",
|
|
88
84
|
source_uri="s3://trainml-examples/checkpoints/resnet50",
|
|
85
|
+
type="evefs",
|
|
89
86
|
)
|
|
90
87
|
api_response = {
|
|
91
88
|
"project_uuid": "cus-id-1",
|
|
92
89
|
"checkpoint_uuid": "checkpoint-id-1",
|
|
93
90
|
"name": "new checkpoint",
|
|
91
|
+
"type": "evefs",
|
|
94
92
|
"status": "new",
|
|
95
93
|
"source_type": "aws",
|
|
96
94
|
"source_uri": "s3://trainml-examples/checkpoints/resnet50",
|
|
@@ -135,7 +133,9 @@ class CheckpointTests:
|
|
|
135
133
|
|
|
136
134
|
@mark.asyncio
|
|
137
135
|
async def test_checkpoint_get_log_url(self, checkpoint, mock_trainml):
|
|
138
|
-
api_response =
|
|
136
|
+
api_response = (
|
|
137
|
+
"https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/logs/first_one.zip"
|
|
138
|
+
)
|
|
139
139
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
140
140
|
response = await checkpoint.get_log_url()
|
|
141
141
|
mock_trainml._query.assert_called_once_with(
|
|
@@ -163,7 +163,9 @@ class CheckpointTests:
|
|
|
163
163
|
async def test_checkpoint_get_connection_utility_url(
|
|
164
164
|
self, checkpoint, mock_trainml
|
|
165
165
|
):
|
|
166
|
-
api_response =
|
|
166
|
+
api_response = (
|
|
167
|
+
"https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/vpn/first_one.zip"
|
|
168
|
+
)
|
|
167
169
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
168
170
|
response = await checkpoint.get_connection_utility_url()
|
|
169
171
|
mock_trainml._query.assert_called_once_with(
|
|
@@ -338,9 +340,7 @@ class CheckpointTests:
|
|
|
338
340
|
assert response.id == "data-id-1"
|
|
339
341
|
|
|
340
342
|
@mark.asyncio
|
|
341
|
-
async def test_checkpoint_wait_for_successful(
|
|
342
|
-
self, checkpoint, mock_trainml
|
|
343
|
-
):
|
|
343
|
+
async def test_checkpoint_wait_for_successful(self, checkpoint, mock_trainml):
|
|
344
344
|
api_response = {
|
|
345
345
|
"customer_uuid": "cus-id-1",
|
|
346
346
|
"checkpoint_uuid": "data-id-1",
|
|
@@ -373,9 +373,7 @@ class CheckpointTests:
|
|
|
373
373
|
mock_trainml._query.assert_not_called()
|
|
374
374
|
|
|
375
375
|
@mark.asyncio
|
|
376
|
-
async def test_checkpoint_wait_for_incorrect_status(
|
|
377
|
-
self, checkpoint, mock_trainml
|
|
378
|
-
):
|
|
376
|
+
async def test_checkpoint_wait_for_incorrect_status(self, checkpoint, mock_trainml):
|
|
379
377
|
api_response = None
|
|
380
378
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
381
379
|
with raises(SpecificationError):
|
|
@@ -383,9 +381,7 @@ class CheckpointTests:
|
|
|
383
381
|
mock_trainml._query.assert_not_called()
|
|
384
382
|
|
|
385
383
|
@mark.asyncio
|
|
386
|
-
async def test_checkpoint_wait_for_with_delay(
|
|
387
|
-
self, checkpoint, mock_trainml
|
|
388
|
-
):
|
|
384
|
+
async def test_checkpoint_wait_for_with_delay(self, checkpoint, mock_trainml):
|
|
389
385
|
api_response_initial = dict(
|
|
390
386
|
checkpoint_uuid="1",
|
|
391
387
|
name="first one",
|
|
@@ -441,9 +437,7 @@ class CheckpointTests:
|
|
|
441
437
|
self, checkpoint, mock_trainml
|
|
442
438
|
):
|
|
443
439
|
mock_trainml._query = AsyncMock(
|
|
444
|
-
side_effect=ApiError(
|
|
445
|
-
404, dict(errorMessage="Checkpoint Not Found")
|
|
446
|
-
)
|
|
440
|
+
side_effect=ApiError(404, dict(errorMessage="Checkpoint Not Found"))
|
|
447
441
|
)
|
|
448
442
|
await checkpoint.wait_for("archived")
|
|
449
443
|
mock_trainml._query.assert_called()
|
|
@@ -453,9 +447,7 @@ class CheckpointTests:
|
|
|
453
447
|
self, checkpoint, mock_trainml
|
|
454
448
|
):
|
|
455
449
|
mock_trainml._query = AsyncMock(
|
|
456
|
-
side_effect=ApiError(
|
|
457
|
-
404, dict(errorMessage="Checkpoint Not Found")
|
|
458
|
-
)
|
|
450
|
+
side_effect=ApiError(404, dict(errorMessage="Checkpoint Not Found"))
|
|
459
451
|
)
|
|
460
452
|
with raises(ApiError):
|
|
461
453
|
await checkpoint.wait_for("ready")
|
tests/unit/test_datasets_unit.py
CHANGED
|
@@ -28,6 +28,7 @@ def dataset(mock_trainml):
|
|
|
28
28
|
dataset_uuid="1",
|
|
29
29
|
project_uuid="proj-id-1",
|
|
30
30
|
name="first one",
|
|
31
|
+
type="evefs",
|
|
31
32
|
status="downloading",
|
|
32
33
|
size=100000,
|
|
33
34
|
createdAt="2020-12-31T23:59:59.000Z",
|
|
@@ -103,6 +104,7 @@ class DatasetsTests:
|
|
|
103
104
|
name="new dataset",
|
|
104
105
|
source_type="aws",
|
|
105
106
|
source_uri="s3://trainml-examples/data/cifar10",
|
|
107
|
+
type="evefs",
|
|
106
108
|
)
|
|
107
109
|
api_response = {
|
|
108
110
|
"customer_uuid": "cus-id-1",
|
|
@@ -110,6 +112,7 @@ class DatasetsTests:
|
|
|
110
112
|
"dataset_uuid": "data-id-1",
|
|
111
113
|
"name": "new dataset",
|
|
112
114
|
"status": "new",
|
|
115
|
+
"type": "evefs",
|
|
113
116
|
"source_type": "aws",
|
|
114
117
|
"source_uri": "s3://trainml-examples/data/cifar10",
|
|
115
118
|
"createdAt": "2020-12-20T16:46:23.909Z",
|
|
@@ -139,9 +142,7 @@ class DatasetTests:
|
|
|
139
142
|
def test_dataset_repr(self, dataset):
|
|
140
143
|
string = repr(dataset)
|
|
141
144
|
regex = (
|
|
142
|
-
r"^Dataset\( trainml , \*\*{.*'dataset_uuid': '"
|
|
143
|
-
+ dataset.id
|
|
144
|
-
+ r"'.*}\)$"
|
|
145
|
+
r"^Dataset\( trainml , \*\*{.*'dataset_uuid': '" + dataset.id + r"'.*}\)$"
|
|
145
146
|
)
|
|
146
147
|
assert isinstance(string, str)
|
|
147
148
|
assert re.match(regex, string)
|
|
@@ -153,7 +154,9 @@ class DatasetTests:
|
|
|
153
154
|
|
|
154
155
|
@mark.asyncio
|
|
155
156
|
async def test_dataset_get_log_url(self, dataset, mock_trainml):
|
|
156
|
-
api_response =
|
|
157
|
+
api_response = (
|
|
158
|
+
"https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/logs/first_one.zip"
|
|
159
|
+
)
|
|
157
160
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
158
161
|
response = await dataset.get_log_url()
|
|
159
162
|
mock_trainml._query.assert_called_once_with(
|
|
@@ -178,10 +181,10 @@ class DatasetTests:
|
|
|
178
181
|
assert response == api_response
|
|
179
182
|
|
|
180
183
|
@mark.asyncio
|
|
181
|
-
async def test_dataset_get_connection_utility_url(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
async def test_dataset_get_connection_utility_url(self, dataset, mock_trainml):
|
|
185
|
+
api_response = (
|
|
186
|
+
"https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/vpn/first_one.zip"
|
|
187
|
+
)
|
|
185
188
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
186
189
|
response = await dataset.get_connection_utility_url()
|
|
187
190
|
mock_trainml._query.assert_called_once_with(
|
|
@@ -388,9 +391,7 @@ class DatasetTests:
|
|
|
388
391
|
mock_trainml._query.assert_not_called()
|
|
389
392
|
|
|
390
393
|
@mark.asyncio
|
|
391
|
-
async def test_dataset_wait_for_incorrect_status(
|
|
392
|
-
self, dataset, mock_trainml
|
|
393
|
-
):
|
|
394
|
+
async def test_dataset_wait_for_incorrect_status(self, dataset, mock_trainml):
|
|
394
395
|
api_response = None
|
|
395
396
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
396
397
|
with raises(SpecificationError):
|
|
@@ -435,9 +436,7 @@ class DatasetTests:
|
|
|
435
436
|
mock_trainml._query.assert_called()
|
|
436
437
|
|
|
437
438
|
@mark.asyncio
|
|
438
|
-
async def test_dataset_wait_for_dataset_failed(
|
|
439
|
-
self, dataset, mock_trainml
|
|
440
|
-
):
|
|
439
|
+
async def test_dataset_wait_for_dataset_failed(self, dataset, mock_trainml):
|
|
441
440
|
api_response = dict(
|
|
442
441
|
dataset_uuid="1",
|
|
443
442
|
name="first one",
|
|
@@ -450,9 +449,7 @@ class DatasetTests:
|
|
|
450
449
|
mock_trainml._query.assert_called()
|
|
451
450
|
|
|
452
451
|
@mark.asyncio
|
|
453
|
-
async def test_dataset_wait_for_archived_succeeded(
|
|
454
|
-
self, dataset, mock_trainml
|
|
455
|
-
):
|
|
452
|
+
async def test_dataset_wait_for_archived_succeeded(self, dataset, mock_trainml):
|
|
456
453
|
mock_trainml._query = AsyncMock(
|
|
457
454
|
side_effect=ApiError(404, dict(errorMessage="Dataset Not Found"))
|
|
458
455
|
)
|
|
@@ -460,9 +457,7 @@ class DatasetTests:
|
|
|
460
457
|
mock_trainml._query.assert_called()
|
|
461
458
|
|
|
462
459
|
@mark.asyncio
|
|
463
|
-
async def test_dataset_wait_for_unexpected_api_error(
|
|
464
|
-
self, dataset, mock_trainml
|
|
465
|
-
):
|
|
460
|
+
async def test_dataset_wait_for_unexpected_api_error(self, dataset, mock_trainml):
|
|
466
461
|
mock_trainml._query = AsyncMock(
|
|
467
462
|
side_effect=ApiError(404, dict(errorMessage="Dataset Not Found"))
|
|
468
463
|
)
|
tests/unit/test_models_unit.py
CHANGED
|
@@ -28,6 +28,7 @@ def model(mock_trainml):
|
|
|
28
28
|
model_uuid="1",
|
|
29
29
|
project_uuid="proj-id-1",
|
|
30
30
|
name="first one",
|
|
31
|
+
type="evefs",
|
|
31
32
|
status="downloading",
|
|
32
33
|
size=100000,
|
|
33
34
|
createdAt="2020-12-31T23:59:59.000Z",
|
|
@@ -44,9 +45,7 @@ class ModelsTests:
|
|
|
44
45
|
api_response = dict()
|
|
45
46
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
46
47
|
await models.get("1234")
|
|
47
|
-
mock_trainml._query.assert_called_once_with(
|
|
48
|
-
"/model/1234", "GET", dict()
|
|
49
|
-
)
|
|
48
|
+
mock_trainml._query.assert_called_once_with("/model/1234", "GET", dict())
|
|
50
49
|
|
|
51
50
|
@mark.asyncio
|
|
52
51
|
async def test_list_models(
|
|
@@ -84,12 +83,14 @@ class ModelsTests:
|
|
|
84
83
|
name="new model",
|
|
85
84
|
source_type="aws",
|
|
86
85
|
source_uri="s3://trainml-examples/models/resnet50",
|
|
86
|
+
type="evefs",
|
|
87
87
|
)
|
|
88
88
|
api_response = {
|
|
89
89
|
"customer_uuid": "cus-id-1",
|
|
90
90
|
"model_uuid": "model-id-1",
|
|
91
91
|
"name": "new model",
|
|
92
92
|
"status": "new",
|
|
93
|
+
"type": "evefs",
|
|
93
94
|
"source_type": "aws",
|
|
94
95
|
"source_uri": "s3://trainml-examples/models/resnet50",
|
|
95
96
|
"createdAt": "2020-12-20T16:46:23.909Z",
|
|
@@ -118,11 +119,7 @@ class ModelTests:
|
|
|
118
119
|
|
|
119
120
|
def test_model_repr(self, model):
|
|
120
121
|
string = repr(model)
|
|
121
|
-
regex = (
|
|
122
|
-
r"^Model\( trainml , \*\*{.*'model_uuid': '"
|
|
123
|
-
+ model.id
|
|
124
|
-
+ r"'.*}\)$"
|
|
125
|
-
)
|
|
122
|
+
regex = r"^Model\( trainml , \*\*{.*'model_uuid': '" + model.id + r"'.*}\)$"
|
|
126
123
|
assert isinstance(string, str)
|
|
127
124
|
assert re.match(regex, string)
|
|
128
125
|
|
|
@@ -133,7 +130,9 @@ class ModelTests:
|
|
|
133
130
|
|
|
134
131
|
@mark.asyncio
|
|
135
132
|
async def test_model_get_log_url(self, model, mock_trainml):
|
|
136
|
-
api_response =
|
|
133
|
+
api_response = (
|
|
134
|
+
"https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/logs/first_one.zip"
|
|
135
|
+
)
|
|
137
136
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
138
137
|
response = await model.get_log_url()
|
|
139
138
|
mock_trainml._query.assert_called_once_with(
|
|
@@ -159,7 +158,9 @@ class ModelTests:
|
|
|
159
158
|
|
|
160
159
|
@mark.asyncio
|
|
161
160
|
async def test_model_get_connection_utility_url(self, model, mock_trainml):
|
|
162
|
-
api_response =
|
|
161
|
+
api_response = (
|
|
162
|
+
"https://trainml-jobs-dev.s3.us-east-2.amazonaws.com/1/vpn/first_one.zip"
|
|
163
|
+
)
|
|
163
164
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
164
165
|
response = await model.get_connection_utility_url()
|
|
165
166
|
mock_trainml._query.assert_called_once_with(
|
|
@@ -425,9 +426,7 @@ class ModelTests:
|
|
|
425
426
|
mock_trainml._query.assert_called()
|
|
426
427
|
|
|
427
428
|
@mark.asyncio
|
|
428
|
-
async def test_model_wait_for_archived_succeeded(
|
|
429
|
-
self, model, mock_trainml
|
|
430
|
-
):
|
|
429
|
+
async def test_model_wait_for_archived_succeeded(self, model, mock_trainml):
|
|
431
430
|
mock_trainml._query = AsyncMock(
|
|
432
431
|
side_effect=ApiError(404, dict(errorMessage="Model Not Found"))
|
|
433
432
|
)
|
|
@@ -435,9 +434,7 @@ class ModelTests:
|
|
|
435
434
|
mock_trainml._query.assert_called()
|
|
436
435
|
|
|
437
436
|
@mark.asyncio
|
|
438
|
-
async def test_model_wait_for_unexpected_api_error(
|
|
439
|
-
self, model, mock_trainml
|
|
440
|
-
):
|
|
437
|
+
async def test_model_wait_for_unexpected_api_error(self, model, mock_trainml):
|
|
441
438
|
mock_trainml._query = AsyncMock(
|
|
442
439
|
side_effect=ApiError(404, dict(errorMessage="Model Not Found"))
|
|
443
440
|
)
|
tests/unit/test_volumes_unit.py
CHANGED
|
@@ -26,6 +26,7 @@ def volume(mock_trainml):
|
|
|
26
26
|
yield specimen.Volume(
|
|
27
27
|
mock_trainml,
|
|
28
28
|
id="1",
|
|
29
|
+
type="evefs",
|
|
29
30
|
project_uuid="proj-id-1",
|
|
30
31
|
name="first one",
|
|
31
32
|
status="downloading",
|
|
@@ -86,12 +87,14 @@ class VolumesTests:
|
|
|
86
87
|
source_type="aws",
|
|
87
88
|
source_uri="s3://trainml-examples/volumes/resnet50",
|
|
88
89
|
capacity="10G",
|
|
90
|
+
type="evefs",
|
|
89
91
|
)
|
|
90
92
|
api_response = {
|
|
91
93
|
"project_uuid": "cus-id-1",
|
|
92
94
|
"id": "volume-id-1",
|
|
93
95
|
"name": "new volume",
|
|
94
96
|
"status": "new",
|
|
97
|
+
"type": "evefs",
|
|
95
98
|
"source_type": "aws",
|
|
96
99
|
"capacity": "10G",
|
|
97
100
|
"source_uri": "s3://trainml-examples/volumes/resnet50",
|
trainml/__init__.py
CHANGED
trainml/checkpoints.py
CHANGED
|
@@ -31,13 +31,24 @@ class Checkpoints(object):
|
|
|
31
31
|
datasets = [Checkpoint(self.trainml, **dataset) for dataset in resp]
|
|
32
32
|
return datasets
|
|
33
33
|
|
|
34
|
-
async def create(
|
|
34
|
+
async def create(
|
|
35
|
+
self,
|
|
36
|
+
name,
|
|
37
|
+
source_type,
|
|
38
|
+
source_uri,
|
|
39
|
+
type="evefs",
|
|
40
|
+
project_uuid=None,
|
|
41
|
+
**kwargs,
|
|
42
|
+
):
|
|
43
|
+
if not project_uuid:
|
|
44
|
+
project_uuid = self.trainml.active_project
|
|
35
45
|
data = dict(
|
|
36
46
|
name=name,
|
|
37
47
|
source_type=source_type,
|
|
38
48
|
source_uri=source_uri,
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
project_uuid=project_uuid,
|
|
50
|
+
type=type,
|
|
51
|
+
**kwargs,
|
|
41
52
|
)
|
|
42
53
|
payload = {k: v for k, v in data.items() if v is not None}
|
|
43
54
|
logging.info(f"Creating Checkpoint {name}")
|
|
@@ -29,13 +29,11 @@ def datastore(config):
|
|
|
29
29
|
def list(config, provider, region):
|
|
30
30
|
"""List datastores."""
|
|
31
31
|
data = [
|
|
32
|
-
["ID", "NAME", "TYPE"
|
|
32
|
+
["ID", "NAME", "TYPE"],
|
|
33
33
|
[
|
|
34
34
|
"-" * 80,
|
|
35
35
|
"-" * 80,
|
|
36
36
|
"-" * 80,
|
|
37
|
-
"-" * 80,
|
|
38
|
-
"-" * 80,
|
|
39
37
|
],
|
|
40
38
|
]
|
|
41
39
|
|
|
@@ -51,15 +49,12 @@ def list(config, provider, region):
|
|
|
51
49
|
datastore.id,
|
|
52
50
|
datastore.name,
|
|
53
51
|
datastore.type,
|
|
54
|
-
datastore.uri,
|
|
55
|
-
datastore.root,
|
|
56
52
|
]
|
|
57
53
|
)
|
|
58
54
|
|
|
59
55
|
for row in data:
|
|
60
56
|
click.echo(
|
|
61
|
-
"{: >37.36} {: >29.28} {: >9.8}
|
|
62
|
-
"".format(*row),
|
|
57
|
+
"{: >37.36} {: >29.28} {: >9.8} " "".format(*row),
|
|
63
58
|
file=config.stdout,
|
|
64
59
|
)
|
|
65
60
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from trainml.cli import cli, pass_config, search_by_id_name
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@cli.group()
|
|
6
|
+
@pass_config
|
|
7
|
+
def project(config):
|
|
8
|
+
"""trainML project commands."""
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@project.command()
|
|
13
|
+
@pass_config
|
|
14
|
+
def list(config):
|
|
15
|
+
"""List projects."""
|
|
16
|
+
data = [
|
|
17
|
+
["ID", "NAME", "OWNER", "MINE"],
|
|
18
|
+
[
|
|
19
|
+
"-" * 80,
|
|
20
|
+
"-" * 80,
|
|
21
|
+
"-" * 80,
|
|
22
|
+
"-" * 80,
|
|
23
|
+
],
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
projects = config.trainml.run(config.trainml.client.projects.list())
|
|
27
|
+
|
|
28
|
+
for project in projects:
|
|
29
|
+
data.append(
|
|
30
|
+
[
|
|
31
|
+
project.id,
|
|
32
|
+
project.name,
|
|
33
|
+
project.owner_name,
|
|
34
|
+
"X" if project.is_owner else "",
|
|
35
|
+
]
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
for row in data:
|
|
39
|
+
click.echo(
|
|
40
|
+
"{: >38.36} {: >30.28} {: >15.13} {: >4.4}" "".format(*row),
|
|
41
|
+
file=config.stdout,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@project.command()
|
|
46
|
+
@click.argument("name", type=click.STRING)
|
|
47
|
+
@pass_config
|
|
48
|
+
def create(config, name):
|
|
49
|
+
"""
|
|
50
|
+
Create a project.
|
|
51
|
+
|
|
52
|
+
Project is created with the specified NAME.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
return config.trainml.run(
|
|
56
|
+
config.trainml.client.projects.create(
|
|
57
|
+
name=name,
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@project.command()
|
|
63
|
+
@click.argument("project", type=click.STRING)
|
|
64
|
+
@pass_config
|
|
65
|
+
def remove(config, project):
|
|
66
|
+
"""
|
|
67
|
+
Remove a project.
|
|
68
|
+
|
|
69
|
+
PROJECT may be specified by name or ID, but ID is preferred.
|
|
70
|
+
"""
|
|
71
|
+
projects = config.trainml.run(config.trainml.client.projects.list())
|
|
72
|
+
|
|
73
|
+
found = search_by_id_name(project, projects)
|
|
74
|
+
if None is found:
|
|
75
|
+
raise click.UsageError("Cannot find specified project.")
|
|
76
|
+
|
|
77
|
+
return config.trainml.run(found.remove())
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
from trainml.cli.project.secret import secret
|
|
81
|
+
from trainml.cli.project.key import key
|
|
82
|
+
from trainml.cli.project.data_connector import data_connector
|
|
83
|
+
from trainml.cli.project.datastore import datastore
|
|
84
|
+
from trainml.cli.project.service import service
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
import base64
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from trainml.cli import pass_config
|
|
7
|
+
from trainml.cli.project import project
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@project.group()
|
|
11
|
+
@pass_config
|
|
12
|
+
def data_connector(config):
|
|
13
|
+
"""trainML project data_connector commands."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@data_connector.command()
|
|
18
|
+
@pass_config
|
|
19
|
+
def list(config):
|
|
20
|
+
"""List project data_connectors."""
|
|
21
|
+
data = [
|
|
22
|
+
["ID", "NAME", "TYPE", "REGION_UUID"],
|
|
23
|
+
[
|
|
24
|
+
"-" * 80,
|
|
25
|
+
"-" * 80,
|
|
26
|
+
"-" * 80,
|
|
27
|
+
"-" * 80,
|
|
28
|
+
],
|
|
29
|
+
]
|
|
30
|
+
project = config.trainml.run(
|
|
31
|
+
config.trainml.client.projects.get(config.trainml.client.project)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
data_connectors = config.trainml.run(project.data_connectors.list())
|
|
35
|
+
|
|
36
|
+
for data_connector in data_connectors:
|
|
37
|
+
data.append(
|
|
38
|
+
[
|
|
39
|
+
data_connector.id,
|
|
40
|
+
data_connector.name,
|
|
41
|
+
data_connector.type,
|
|
42
|
+
data_connector.region_uuid,
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
for row in data:
|
|
47
|
+
click.echo(
|
|
48
|
+
"{: >38.36} {: >30.28} {: >15.13} {: >38.36}" "".format(*row),
|
|
49
|
+
file=config.stdout,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@data_connector.command()
|
|
54
|
+
@pass_config
|
|
55
|
+
def refresh(config):
|
|
56
|
+
"""
|
|
57
|
+
Refresh project data_connector list.
|
|
58
|
+
"""
|
|
59
|
+
project = config.trainml.run(config.trainml.client.projects.get_current())
|
|
60
|
+
|
|
61
|
+
return config.trainml.run(project.data_connectors.refresh())
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import os
|
|
3
|
+
import json
|
|
4
|
+
import base64
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from trainml.cli import pass_config
|
|
7
|
+
from trainml.cli.project import project
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@project.group()
|
|
11
|
+
@pass_config
|
|
12
|
+
def datastore(config):
|
|
13
|
+
"""trainML project datastore commands."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@datastore.command()
|
|
18
|
+
@pass_config
|
|
19
|
+
def list(config):
|
|
20
|
+
"""List project datastores."""
|
|
21
|
+
data = [
|
|
22
|
+
["ID", "NAME", "TYPE", "REGION_UUID"],
|
|
23
|
+
[
|
|
24
|
+
"-" * 80,
|
|
25
|
+
"-" * 80,
|
|
26
|
+
"-" * 80,
|
|
27
|
+
"-" * 80,
|
|
28
|
+
],
|
|
29
|
+
]
|
|
30
|
+
project = config.trainml.run(
|
|
31
|
+
config.trainml.client.projects.get(config.trainml.client.project)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
datastores = config.trainml.run(project.datastores.list())
|
|
35
|
+
|
|
36
|
+
for datastore in datastores:
|
|
37
|
+
data.append(
|
|
38
|
+
[
|
|
39
|
+
datastore.id,
|
|
40
|
+
datastore.name,
|
|
41
|
+
datastore.type,
|
|
42
|
+
datastore.region_uuid,
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
for row in data:
|
|
47
|
+
click.echo(
|
|
48
|
+
"{: >38.36} {: >30.28} {: >15.13} {: >38.36}" "".format(*row),
|
|
49
|
+
file=config.stdout,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@datastore.command()
|
|
54
|
+
@pass_config
|
|
55
|
+
def refresh(config):
|
|
56
|
+
"""
|
|
57
|
+
Refresh project datastore list.
|
|
58
|
+
"""
|
|
59
|
+
project = config.trainml.run(config.trainml.client.projects.get_current())
|
|
60
|
+
|
|
61
|
+
return config.trainml.run(project.datastores.refresh())
|