trainml 0.5.4__py3-none-any.whl → 0.5.6__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/test_checkpoints_integration.py +7 -5
- tests/integration/test_datasets_integration.py +4 -5
- tests/integration/test_jobs_integration.py +40 -2
- tests/integration/test_models_integration.py +8 -10
- tests/integration/test_projects_integration.py +2 -6
- tests/integration/test_volumes_integration.py +100 -0
- tests/unit/cli/cloudbender/test_cli_reservation_unit.py +10 -14
- tests/unit/cli/test_cli_project_unit.py +5 -9
- tests/unit/cli/test_cli_volume_unit.py +20 -0
- tests/unit/cloudbender/test_services_unit.py +161 -0
- tests/unit/conftest.py +94 -21
- tests/unit/test_projects_unit.py +34 -48
- tests/unit/test_volumes_unit.py +447 -0
- trainml/__init__.py +1 -1
- trainml/cli/__init__.py +3 -6
- trainml/cli/cloudbender/__init__.py +1 -1
- trainml/cli/cloudbender/service.py +129 -0
- trainml/cli/project.py +10 -15
- trainml/cli/volume.py +235 -0
- trainml/cloudbender/cloudbender.py +2 -2
- trainml/cloudbender/services.py +115 -0
- trainml/exceptions.py +21 -12
- trainml/jobs.py +36 -39
- trainml/projects.py +19 -30
- trainml/trainml.py +7 -15
- trainml/volumes.py +255 -0
- {trainml-0.5.4.dist-info → trainml-0.5.6.dist-info}/METADATA +1 -1
- {trainml-0.5.4.dist-info → trainml-0.5.6.dist-info}/RECORD +32 -29
- tests/integration/test_providers_integration.py +0 -46
- tests/unit/test_providers_unit.py +0 -125
- trainml/cli/job.py +0 -173
- trainml/cli/provider.py +0 -75
- trainml/providers.py +0 -63
- {trainml-0.5.4.dist-info → trainml-0.5.6.dist-info}/LICENSE +0 -0
- {trainml-0.5.4.dist-info → trainml-0.5.6.dist-info}/WHEEL +0 -0
- {trainml-0.5.4.dist-info → trainml-0.5.6.dist-info}/entry_points.txt +0 -0
- {trainml-0.5.4.dist-info → trainml-0.5.6.dist-info}/top_level.txt +0 -0
tests/unit/conftest.py
CHANGED
|
@@ -7,6 +7,7 @@ from trainml.trainml import TrainML
|
|
|
7
7
|
from trainml.auth import Auth
|
|
8
8
|
from trainml.datasets import Dataset, Datasets
|
|
9
9
|
from trainml.checkpoints import Checkpoint, Checkpoints
|
|
10
|
+
from trainml.volumes import Volume, Volumes
|
|
10
11
|
from trainml.models import Model, Models
|
|
11
12
|
from trainml.gpu_types import GpuType, GpuTypes
|
|
12
13
|
from trainml.environments import Environment, Environments
|
|
@@ -16,7 +17,7 @@ from trainml.projects import (
|
|
|
16
17
|
Projects,
|
|
17
18
|
Project,
|
|
18
19
|
ProjectDatastore,
|
|
19
|
-
|
|
20
|
+
ProjectService,
|
|
20
21
|
)
|
|
21
22
|
from trainml.cloudbender import Cloudbender
|
|
22
23
|
from trainml.cloudbender.providers import Provider, Providers
|
|
@@ -24,7 +25,7 @@ from trainml.cloudbender.regions import Region, Regions
|
|
|
24
25
|
from trainml.cloudbender.nodes import Node, Nodes
|
|
25
26
|
from trainml.cloudbender.devices import Device, Devices
|
|
26
27
|
from trainml.cloudbender.datastores import Datastore, Datastores
|
|
27
|
-
from trainml.cloudbender.
|
|
28
|
+
from trainml.cloudbender.services import Service, Services
|
|
28
29
|
from trainml.cloudbender.device_configs import DeviceConfig, DeviceConfigs
|
|
29
30
|
|
|
30
31
|
|
|
@@ -258,6 +259,79 @@ def mock_models():
|
|
|
258
259
|
]
|
|
259
260
|
|
|
260
261
|
|
|
262
|
+
@fixture(scope="session")
|
|
263
|
+
def mock_my_volumes():
|
|
264
|
+
trainml = Mock()
|
|
265
|
+
yield [
|
|
266
|
+
Volume(
|
|
267
|
+
trainml,
|
|
268
|
+
id="1",
|
|
269
|
+
project_uuid="proj-id-1",
|
|
270
|
+
name="first one",
|
|
271
|
+
status="ready",
|
|
272
|
+
capacity="10G",
|
|
273
|
+
used_size=100000000,
|
|
274
|
+
billed_size=100000000,
|
|
275
|
+
createdAt="2020-12-31T23:59:59.000Z",
|
|
276
|
+
),
|
|
277
|
+
Volume(
|
|
278
|
+
trainml,
|
|
279
|
+
id="2",
|
|
280
|
+
project_uuid="proj-id-1",
|
|
281
|
+
name="second one",
|
|
282
|
+
status="ready",
|
|
283
|
+
capacity="10G",
|
|
284
|
+
used_size=100000000,
|
|
285
|
+
billed_size=100000000,
|
|
286
|
+
createdAt="2021-01-01T00:00:01.000Z",
|
|
287
|
+
),
|
|
288
|
+
Volume(
|
|
289
|
+
trainml,
|
|
290
|
+
id="3",
|
|
291
|
+
project_uuid="proj-id-1",
|
|
292
|
+
name="first one",
|
|
293
|
+
status="ready",
|
|
294
|
+
capacity="10G",
|
|
295
|
+
used_size=100000000,
|
|
296
|
+
billed_size=100000000,
|
|
297
|
+
createdAt="2021-01-01T00:00:01.000Z",
|
|
298
|
+
),
|
|
299
|
+
Volume(
|
|
300
|
+
trainml,
|
|
301
|
+
id="4",
|
|
302
|
+
project_uuid="proj-id-1",
|
|
303
|
+
name="other one",
|
|
304
|
+
status="ready",
|
|
305
|
+
capacity="10G",
|
|
306
|
+
used_size=100000000,
|
|
307
|
+
billed_size=100000000,
|
|
308
|
+
createdAt="2020-12-31T23:59:59.000Z",
|
|
309
|
+
),
|
|
310
|
+
Volume(
|
|
311
|
+
trainml,
|
|
312
|
+
id="5",
|
|
313
|
+
project_uuid="proj-id-1",
|
|
314
|
+
name="not ready",
|
|
315
|
+
status="new",
|
|
316
|
+
capacity="10G",
|
|
317
|
+
used_size=100000000,
|
|
318
|
+
billed_size=100000000,
|
|
319
|
+
createdAt="2021-01-01T00:00:01.000Z",
|
|
320
|
+
),
|
|
321
|
+
Volume(
|
|
322
|
+
trainml,
|
|
323
|
+
id="6",
|
|
324
|
+
project_uuid="proj-id-1",
|
|
325
|
+
name="failed",
|
|
326
|
+
status="failed",
|
|
327
|
+
capacity="10G",
|
|
328
|
+
used_size=100000000,
|
|
329
|
+
billed_size=100000000,
|
|
330
|
+
createdAt="2021-01-01T00:00:01.000Z",
|
|
331
|
+
),
|
|
332
|
+
]
|
|
333
|
+
|
|
334
|
+
|
|
261
335
|
@fixture(scope="session")
|
|
262
336
|
def mock_gpu_types():
|
|
263
337
|
trainml = Mock()
|
|
@@ -813,27 +887,27 @@ def mock_project_datastores():
|
|
|
813
887
|
|
|
814
888
|
|
|
815
889
|
@fixture(scope="session")
|
|
816
|
-
def
|
|
890
|
+
def mock_services():
|
|
817
891
|
trainml = Mock()
|
|
818
892
|
yield [
|
|
819
|
-
|
|
893
|
+
Service(
|
|
820
894
|
trainml,
|
|
821
895
|
**{
|
|
822
896
|
"provider_uuid": "prov-id-1",
|
|
823
897
|
"region_uuid": "reg-id-1",
|
|
824
|
-
"
|
|
898
|
+
"service_id": "res-id-1",
|
|
825
899
|
"type": "port",
|
|
826
900
|
"name": "On-Prem Service A",
|
|
827
901
|
"resource": "8001",
|
|
828
902
|
"hostname": "service-a.local",
|
|
829
903
|
},
|
|
830
904
|
),
|
|
831
|
-
|
|
905
|
+
Service(
|
|
832
906
|
trainml,
|
|
833
907
|
**{
|
|
834
908
|
"provider_uuid": "prov-id-2",
|
|
835
909
|
"region_uuid": "reg-id-2",
|
|
836
|
-
"
|
|
910
|
+
"service_id": "res-id-2",
|
|
837
911
|
"type": "port",
|
|
838
912
|
"name": "Cloud Service B",
|
|
839
913
|
"resource": "8001",
|
|
@@ -844,10 +918,10 @@ def mock_reservations():
|
|
|
844
918
|
|
|
845
919
|
|
|
846
920
|
@fixture(scope="session")
|
|
847
|
-
def
|
|
921
|
+
def mock_project_services():
|
|
848
922
|
trainml = Mock()
|
|
849
923
|
yield [
|
|
850
|
-
|
|
924
|
+
ProjectService(
|
|
851
925
|
trainml,
|
|
852
926
|
**{
|
|
853
927
|
"project_uuid": "proj-id-1",
|
|
@@ -859,7 +933,7 @@ def mock_project_reservations():
|
|
|
859
933
|
"hostname": "service-a.local",
|
|
860
934
|
},
|
|
861
935
|
),
|
|
862
|
-
|
|
936
|
+
ProjectService(
|
|
863
937
|
trainml,
|
|
864
938
|
**{
|
|
865
939
|
"project_uuid": "proj-id-1",
|
|
@@ -903,6 +977,9 @@ def mock_device_configs():
|
|
|
903
977
|
def mock_trainml(
|
|
904
978
|
mock_my_datasets,
|
|
905
979
|
mock_public_datasets,
|
|
980
|
+
mock_my_checkpoints,
|
|
981
|
+
mock_public_checkpoints,
|
|
982
|
+
mock_my_volumes,
|
|
906
983
|
mock_models,
|
|
907
984
|
mock_gpu_types,
|
|
908
985
|
mock_environments,
|
|
@@ -913,7 +990,7 @@ def mock_trainml(
|
|
|
913
990
|
mock_nodes,
|
|
914
991
|
mock_devices,
|
|
915
992
|
mock_datastores,
|
|
916
|
-
|
|
993
|
+
mock_services,
|
|
917
994
|
mock_device_configs,
|
|
918
995
|
):
|
|
919
996
|
trainml = create_autospec(TrainML)
|
|
@@ -921,6 +998,7 @@ def mock_trainml(
|
|
|
921
998
|
trainml.project = "proj-id-1"
|
|
922
999
|
trainml.datasets = create_autospec(Datasets)
|
|
923
1000
|
trainml.checkpoints = create_autospec(Checkpoints)
|
|
1001
|
+
trainml.volumes = create_autospec(Volumes)
|
|
924
1002
|
trainml.models = create_autospec(Models)
|
|
925
1003
|
trainml.gpu_types = create_autospec(GpuTypes)
|
|
926
1004
|
trainml.environments = create_autospec(Environments)
|
|
@@ -930,10 +1008,9 @@ def mock_trainml(
|
|
|
930
1008
|
trainml.datasets.list = AsyncMock(return_value=mock_my_datasets)
|
|
931
1009
|
trainml.datasets.list_public = AsyncMock(return_value=mock_public_datasets)
|
|
932
1010
|
trainml.checkpoints.list = AsyncMock(return_value=mock_my_checkpoints)
|
|
933
|
-
trainml.checkpoints.list_public = AsyncMock(
|
|
934
|
-
return_value=mock_public_checkpoints
|
|
935
|
-
)
|
|
1011
|
+
trainml.checkpoints.list_public = AsyncMock(return_value=mock_public_checkpoints)
|
|
936
1012
|
trainml.models.list = AsyncMock(return_value=mock_models)
|
|
1013
|
+
trainml.volumes.list = AsyncMock(return_value=mock_my_volumes)
|
|
937
1014
|
trainml.gpu_types.list = AsyncMock(return_value=mock_gpu_types)
|
|
938
1015
|
trainml.environments.list = AsyncMock(return_value=mock_environments)
|
|
939
1016
|
trainml.jobs.list = AsyncMock(return_value=mock_jobs)
|
|
@@ -950,13 +1027,9 @@ def mock_trainml(
|
|
|
950
1027
|
trainml.cloudbender.devices = create_autospec(Nodes)
|
|
951
1028
|
trainml.cloudbender.devices.list = AsyncMock(return_value=mock_devices)
|
|
952
1029
|
trainml.cloudbender.datastores = create_autospec(Datastores)
|
|
953
|
-
trainml.cloudbender.datastores.list = AsyncMock(
|
|
954
|
-
|
|
955
|
-
)
|
|
956
|
-
trainml.cloudbender.reservations = create_autospec(Reservations)
|
|
957
|
-
trainml.cloudbender.reservations.list = AsyncMock(
|
|
958
|
-
return_value=mock_reservations
|
|
959
|
-
)
|
|
1030
|
+
trainml.cloudbender.datastores.list = AsyncMock(return_value=mock_datastores)
|
|
1031
|
+
trainml.cloudbender.services = create_autospec(Services)
|
|
1032
|
+
trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
|
|
960
1033
|
trainml.cloudbender.device_configs = create_autospec(DeviceConfigs)
|
|
961
1034
|
trainml.cloudbender.device_configs.list = AsyncMock(
|
|
962
1035
|
return_value=mock_device_configs
|
tests/unit/test_projects_unit.py
CHANGED
|
@@ -49,11 +49,11 @@ def project_datastore(mock_trainml):
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
@fixture
|
|
52
|
-
def
|
|
53
|
-
yield specimen.
|
|
52
|
+
def project_service(mock_trainml):
|
|
53
|
+
yield specimen.ProjectService(
|
|
54
54
|
mock_trainml,
|
|
55
55
|
id="res-id-1",
|
|
56
|
-
name="
|
|
56
|
+
name="service 1",
|
|
57
57
|
project_uuid="proj-id-1",
|
|
58
58
|
region_uuid="reg-id-1",
|
|
59
59
|
type="port",
|
|
@@ -72,9 +72,7 @@ class ProjectsTests:
|
|
|
72
72
|
api_response = dict()
|
|
73
73
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
74
74
|
await projects.get("1234")
|
|
75
|
-
mock_trainml._query.assert_called_once_with(
|
|
76
|
-
"/project/1234", "GET", dict()
|
|
77
|
-
)
|
|
75
|
+
mock_trainml._query.assert_called_once_with("/project/1234", "GET", dict())
|
|
78
76
|
|
|
79
77
|
@mark.asyncio
|
|
80
78
|
async def test_list_projects(
|
|
@@ -96,9 +94,7 @@ class ProjectsTests:
|
|
|
96
94
|
api_response = dict()
|
|
97
95
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
98
96
|
await projects.remove("4567")
|
|
99
|
-
mock_trainml._query.assert_called_once_with(
|
|
100
|
-
"/project/4567", "DELETE", dict()
|
|
101
|
-
)
|
|
97
|
+
mock_trainml._query.assert_called_once_with("/project/4567", "DELETE", dict())
|
|
102
98
|
|
|
103
99
|
@mark.asyncio
|
|
104
100
|
async def test_create_project_simple(self, projects, mock_trainml):
|
|
@@ -156,36 +152,36 @@ class ProjectDatastoreTests:
|
|
|
156
152
|
assert not bool(empty_project_datastore)
|
|
157
153
|
|
|
158
154
|
|
|
159
|
-
class
|
|
160
|
-
def
|
|
161
|
-
assert isinstance(
|
|
162
|
-
assert isinstance(
|
|
163
|
-
assert isinstance(
|
|
164
|
-
assert isinstance(
|
|
165
|
-
assert isinstance(
|
|
166
|
-
assert isinstance(
|
|
167
|
-
assert isinstance(
|
|
155
|
+
class ProjectServiceTests:
|
|
156
|
+
def test_project_service_properties(self, project_service):
|
|
157
|
+
assert isinstance(project_service.id, str)
|
|
158
|
+
assert isinstance(project_service.name, str)
|
|
159
|
+
assert isinstance(project_service.project_uuid, str)
|
|
160
|
+
assert isinstance(project_service.type, str)
|
|
161
|
+
assert isinstance(project_service.hostname, str)
|
|
162
|
+
assert isinstance(project_service.resource, str)
|
|
163
|
+
assert isinstance(project_service.region_uuid, str)
|
|
168
164
|
|
|
169
|
-
def
|
|
170
|
-
string = str(
|
|
171
|
-
regex = r"^{.*\"id\": \"" +
|
|
165
|
+
def test_project_service_str(self, project_service):
|
|
166
|
+
string = str(project_service)
|
|
167
|
+
regex = r"^{.*\"id\": \"" + project_service.id + r"\".*}$"
|
|
172
168
|
assert isinstance(string, str)
|
|
173
169
|
assert re.match(regex, string)
|
|
174
170
|
|
|
175
|
-
def
|
|
176
|
-
string = repr(
|
|
171
|
+
def test_project_service_repr(self, project_service):
|
|
172
|
+
string = repr(project_service)
|
|
177
173
|
regex = (
|
|
178
|
-
r"^
|
|
179
|
-
+
|
|
174
|
+
r"^ProjectService\( trainml , \*\*{.*'id': '"
|
|
175
|
+
+ project_service.id
|
|
180
176
|
+ r"'.*}\)$"
|
|
181
177
|
)
|
|
182
178
|
assert isinstance(string, str)
|
|
183
179
|
assert re.match(regex, string)
|
|
184
180
|
|
|
185
|
-
def
|
|
186
|
-
|
|
187
|
-
assert bool(
|
|
188
|
-
assert not bool(
|
|
181
|
+
def test_project_service_bool(self, project_service, mock_trainml):
|
|
182
|
+
empty_project_service = specimen.ProjectService(mock_trainml)
|
|
183
|
+
assert bool(project_service)
|
|
184
|
+
assert not bool(empty_project_service)
|
|
189
185
|
|
|
190
186
|
|
|
191
187
|
class ProjectTests:
|
|
@@ -203,9 +199,7 @@ class ProjectTests:
|
|
|
203
199
|
|
|
204
200
|
def test_project_repr(self, project):
|
|
205
201
|
string = repr(project)
|
|
206
|
-
regex = (
|
|
207
|
-
r"^Project\( trainml , \*\*{.*'id': '" + project.id + r"'.*}\)$"
|
|
208
|
-
)
|
|
202
|
+
regex = r"^Project\( trainml , \*\*{.*'id': '" + project.id + r"'.*}\)$"
|
|
209
203
|
assert isinstance(string, str)
|
|
210
204
|
assert re.match(regex, string)
|
|
211
205
|
|
|
@@ -226,18 +220,14 @@ class ProjectTests:
|
|
|
226
220
|
api_response = dict()
|
|
227
221
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
228
222
|
await project.refresh_datastores()
|
|
229
|
-
mock_trainml._query.assert_called_once_with(
|
|
230
|
-
"/project/1/datastores", "PATCH"
|
|
231
|
-
)
|
|
223
|
+
mock_trainml._query.assert_called_once_with("/project/1/datastores", "PATCH")
|
|
232
224
|
|
|
233
225
|
@mark.asyncio
|
|
234
|
-
async def
|
|
226
|
+
async def test_project_refresh_services(self, project, mock_trainml):
|
|
235
227
|
api_response = dict()
|
|
236
228
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
237
|
-
await project.
|
|
238
|
-
mock_trainml._query.assert_called_once_with(
|
|
239
|
-
"/project/1/reservations", "PATCH"
|
|
240
|
-
)
|
|
229
|
+
await project.refresh_services()
|
|
230
|
+
mock_trainml._query.assert_called_once_with("/project/1/services", "PATCH")
|
|
241
231
|
|
|
242
232
|
@mark.asyncio
|
|
243
233
|
async def test_project_list_datastores(self, project, mock_trainml):
|
|
@@ -259,13 +249,11 @@ class ProjectTests:
|
|
|
259
249
|
]
|
|
260
250
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
261
251
|
resp = await project.list_datastores()
|
|
262
|
-
mock_trainml._query.assert_called_once_with(
|
|
263
|
-
"/project/1/datastores", "GET"
|
|
264
|
-
)
|
|
252
|
+
mock_trainml._query.assert_called_once_with("/project/1/datastores", "GET")
|
|
265
253
|
assert len(resp) == 2
|
|
266
254
|
|
|
267
255
|
@mark.asyncio
|
|
268
|
-
async def
|
|
256
|
+
async def test_project_list_services(self, project, mock_trainml):
|
|
269
257
|
api_response = [
|
|
270
258
|
{
|
|
271
259
|
"project_uuid": "proj-id-1",
|
|
@@ -287,8 +275,6 @@ class ProjectTests:
|
|
|
287
275
|
},
|
|
288
276
|
]
|
|
289
277
|
mock_trainml._query = AsyncMock(return_value=api_response)
|
|
290
|
-
resp = await project.
|
|
291
|
-
mock_trainml._query.assert_called_once_with(
|
|
292
|
-
"/project/1/reservations", "GET"
|
|
293
|
-
)
|
|
278
|
+
resp = await project.list_services()
|
|
279
|
+
mock_trainml._query.assert_called_once_with("/project/1/services", "GET")
|
|
294
280
|
assert len(resp) == 2
|