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.
Files changed (72) hide show
  1. tests/integration/projects/__init__.py +0 -0
  2. tests/integration/projects/conftest.py +10 -0
  3. tests/integration/projects/test_projects_data_connectors_integration.py +44 -0
  4. tests/integration/projects/test_projects_datastores_integration.py +42 -0
  5. tests/integration/{test_projects_integration.py → projects/test_projects_integration.py} +0 -6
  6. tests/integration/projects/test_projects_keys_integration.py +43 -0
  7. tests/integration/projects/test_projects_secrets_integration.py +44 -0
  8. tests/integration/projects/test_projects_services_integration.py +44 -0
  9. tests/integration/test_checkpoints_integration.py +1 -2
  10. tests/integration/test_models_integration.py +0 -1
  11. tests/unit/cli/projects/__init__.py +0 -0
  12. tests/unit/cli/projects/test_cli_project_data_connector_unit.py +28 -0
  13. tests/unit/cli/projects/test_cli_project_datastore_unit.py +26 -0
  14. tests/unit/cli/projects/test_cli_project_key_unit.py +26 -0
  15. tests/unit/cli/projects/test_cli_project_secret_unit.py +26 -0
  16. tests/unit/cli/projects/test_cli_project_service_unit.py +26 -0
  17. tests/unit/cli/projects/test_cli_project_unit.py +19 -0
  18. tests/unit/cloudbender/test_datastores_unit.py +1 -5
  19. tests/unit/conftest.py +146 -3
  20. tests/unit/projects/__init__.py +0 -0
  21. tests/unit/projects/test_project_data_connectors_unit.py +102 -0
  22. tests/unit/projects/test_project_datastores_unit.py +96 -0
  23. tests/unit/projects/test_project_keys_unit.py +96 -0
  24. tests/unit/projects/test_project_secrets_unit.py +101 -0
  25. tests/unit/projects/test_project_services_unit.py +102 -0
  26. tests/unit/projects/test_projects_unit.py +128 -0
  27. tests/unit/test_checkpoints_unit.py +15 -23
  28. tests/unit/test_datasets_unit.py +15 -20
  29. tests/unit/test_models_unit.py +13 -16
  30. tests/unit/test_volumes_unit.py +3 -0
  31. trainml/__init__.py +1 -1
  32. trainml/checkpoints.py +14 -3
  33. trainml/cli/cloudbender/datastore.py +2 -7
  34. trainml/cli/project/__init__.py +84 -0
  35. trainml/cli/project/data_connector.py +61 -0
  36. trainml/cli/project/datastore.py +61 -0
  37. trainml/cli/project/key.py +124 -0
  38. trainml/cli/project/secret.py +71 -0
  39. trainml/cli/project/service.py +61 -0
  40. trainml/cloudbender/data_connectors.py +8 -0
  41. trainml/cloudbender/datastores.py +9 -19
  42. trainml/cloudbender/nodes.py +44 -1
  43. trainml/cloudbender/providers.py +53 -0
  44. trainml/cloudbender/regions.py +48 -0
  45. trainml/datasets.py +14 -3
  46. trainml/exceptions.py +51 -0
  47. trainml/jobs.py +2 -13
  48. trainml/models.py +14 -3
  49. trainml/projects/__init__.py +3 -0
  50. trainml/projects/data_connectors.py +63 -0
  51. trainml/projects/datastores.py +58 -0
  52. trainml/projects/keys.py +71 -0
  53. trainml/projects/projects.py +83 -0
  54. trainml/projects/secrets.py +70 -0
  55. trainml/projects/services.py +63 -0
  56. trainml/volumes.py +15 -3
  57. {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/METADATA +1 -1
  58. {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/RECORD +64 -38
  59. tests/unit/cli/cloudbender/test_cli_reservation_unit.py +0 -34
  60. tests/unit/cli/test_cli_project_unit.py +0 -42
  61. tests/unit/cloudbender/test_reservations_unit.py +0 -173
  62. tests/unit/test_projects_unit.py +0 -320
  63. trainml/cli/cloudbender/reservation.py +0 -159
  64. trainml/cli/project.py +0 -149
  65. trainml/cloudbender/reservations.py +0 -126
  66. trainml/projects.py +0 -228
  67. /tests/unit/{test_auth.py → test_auth_unit.py} +0 -0
  68. /tests/unit/{test_trainml.py → test_trainml_unit.py} +0 -0
  69. {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/LICENSE +0 -0
  70. {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/WHEEL +0 -0
  71. {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/entry_points.txt +0 -0
  72. {trainml-0.5.8.dist-info → trainml-0.5.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,63 @@
1
+ import json
2
+ import logging
3
+
4
+
5
+ class ProjectDataConnectors(object):
6
+ def __init__(self, trainml, project_id):
7
+ self.trainml = trainml
8
+ self.project_id = project_id
9
+
10
+ async def list(self, **kwargs):
11
+ resp = await self.trainml._query(
12
+ f"/project/{self.project_id}/data_connectors", "GET", kwargs
13
+ )
14
+ data_connectors = [
15
+ ProjectDataConnector(self.trainml, **data_connector)
16
+ for data_connector in resp
17
+ ]
18
+ return data_connectors
19
+
20
+ async def refresh(self):
21
+ await self.trainml._query(
22
+ f"/project/{self.project_id}/data_connectors", "PATCH"
23
+ )
24
+
25
+
26
+ class ProjectDataConnector:
27
+ def __init__(self, trainml, **kwargs):
28
+ self.trainml = trainml
29
+ self._entity = kwargs
30
+ self._id = self._entity.get("id")
31
+ self._project_uuid = self._entity.get("project_uuid")
32
+ self._name = self._entity.get("name")
33
+ self._type = self._entity.get("type")
34
+ self._region_uuid = self._entity.get("region_uuid")
35
+
36
+ @property
37
+ def id(self) -> str:
38
+ return self._id
39
+
40
+ @property
41
+ def project_uuid(self) -> str:
42
+ return self._project_uuid
43
+
44
+ @property
45
+ def name(self) -> str:
46
+ return self._name
47
+
48
+ @property
49
+ def type(self) -> str:
50
+ return self._type
51
+
52
+ @property
53
+ def region_uuid(self) -> str:
54
+ return self._region_uuid
55
+
56
+ def __str__(self):
57
+ return json.dumps({k: v for k, v in self._entity.items()})
58
+
59
+ def __repr__(self):
60
+ return f"ProjectDataConnector( trainml , **{self._entity.__repr__()})"
61
+
62
+ def __bool__(self):
63
+ return bool(self._id)
@@ -0,0 +1,58 @@
1
+ import json
2
+ import logging
3
+
4
+
5
+ class ProjectDatastores(object):
6
+ def __init__(self, trainml, project_id):
7
+ self.trainml = trainml
8
+ self.project_id = project_id
9
+
10
+ async def list(self, **kwargs):
11
+ resp = await self.trainml._query(
12
+ f"/project/{self.project_id}/datastores", "GET", kwargs
13
+ )
14
+ datastores = [ProjectDatastore(self.trainml, **datastore) for datastore in resp]
15
+ return datastores
16
+
17
+ async def refresh(self):
18
+ await self.trainml._query(f"/project/{self.project_id}/datastores", "PATCH")
19
+
20
+
21
+ class ProjectDatastore:
22
+ def __init__(self, trainml, **kwargs):
23
+ self.trainml = trainml
24
+ self._entity = kwargs
25
+ self._id = self._entity.get("id")
26
+ self._project_uuid = self._entity.get("project_uuid")
27
+ self._name = self._entity.get("name")
28
+ self._type = self._entity.get("type")
29
+ self._region_uuid = self._entity.get("region_uuid")
30
+
31
+ @property
32
+ def id(self) -> str:
33
+ return self._id
34
+
35
+ @property
36
+ def project_uuid(self) -> str:
37
+ return self._project_uuid
38
+
39
+ @property
40
+ def name(self) -> str:
41
+ return self._name
42
+
43
+ @property
44
+ def type(self) -> str:
45
+ return self._type
46
+
47
+ @property
48
+ def region_uuid(self) -> str:
49
+ return self._region_uuid
50
+
51
+ def __str__(self):
52
+ return json.dumps({k: v for k, v in self._entity.items()})
53
+
54
+ def __repr__(self):
55
+ return f"ProjectDatastore( trainml , **{self._entity.__repr__()})"
56
+
57
+ def __bool__(self):
58
+ return bool(self._id)
@@ -0,0 +1,71 @@
1
+ import json
2
+ import logging
3
+ from datetime import datetime
4
+ from dateutil import parser, tz
5
+
6
+
7
+ class ProjectKeys(object):
8
+ def __init__(self, trainml, project_id):
9
+ self.trainml = trainml
10
+ self.project_id = project_id
11
+
12
+ async def list(self, **kwargs):
13
+ resp = await self.trainml._query(
14
+ f"/project/{self.project_id}/keys", "GET", kwargs
15
+ )
16
+ keys = [ProjectKey(self.trainml, **service) for service in resp]
17
+ return keys
18
+
19
+ async def put(self, type, key_id, secret, tenant=None, **kwargs):
20
+ data = dict(key_id=key_id, secret=secret, tenant=tenant)
21
+ payload = {k: v for k, v in data.items() if v is not None}
22
+ logging.info(f"Creating Project Key {type}")
23
+ resp = await self.trainml._query(
24
+ f"/project/{self.project_id}/key/{type}", "PUT", None, payload
25
+ )
26
+ key = ProjectKey(self.trainml, **resp)
27
+ logging.info(f"Created Project Key {type} in project {self.project_id}")
28
+
29
+ return key
30
+
31
+ async def remove(self, type, **kwargs):
32
+ await self.trainml._query(
33
+ f"/project/{self.project_id}/key/{type}", "DELETE", kwargs
34
+ )
35
+
36
+
37
+ class ProjectKey:
38
+ def __init__(self, trainml, **kwargs):
39
+ self.trainml = trainml
40
+ self._entity = kwargs
41
+ self._type = self._entity.get("type")
42
+ self._project_uuid = self._entity.get("project_uuid")
43
+ self._key_id = self._entity.get("key_id")
44
+ self._updated_at = self._entity.get("updatedAt")
45
+
46
+ @property
47
+ def type(self) -> str:
48
+ return self._type
49
+
50
+ @property
51
+ def project_uuid(self) -> str:
52
+ return self._project_uuid
53
+
54
+ @property
55
+ def key_id(self) -> str:
56
+ return self._key_id
57
+
58
+ @property
59
+ def updated_at(self) -> datetime:
60
+ timestamp = parser.isoparse(self._updated_at)
61
+ timezone = tz.tzlocal()
62
+ return timestamp.astimezone(timezone)
63
+
64
+ def __str__(self):
65
+ return json.dumps({k: v for k, v in self._entity.items()})
66
+
67
+ def __repr__(self):
68
+ return f"ProjectKey( trainml , **{self._entity.__repr__()})"
69
+
70
+ def __bool__(self):
71
+ return bool(self._type)
@@ -0,0 +1,83 @@
1
+ import json
2
+ import logging
3
+ from .datastores import ProjectDatastores
4
+ from .data_connectors import ProjectDataConnectors
5
+ from .services import ProjectServices
6
+ from .keys import ProjectKeys
7
+ from .secrets import ProjectSecrets
8
+
9
+
10
+ class Projects(object):
11
+ def __init__(self, trainml):
12
+ self.trainml = trainml
13
+
14
+ async def get(self, id, **kwargs):
15
+ resp = await self.trainml._query(f"/project/{id}", "GET", kwargs)
16
+ return Project(self.trainml, **resp)
17
+
18
+ async def get_current(self, **kwargs):
19
+ resp = await self.trainml._query(
20
+ f"/project/{self.trainml.project}", "GET", kwargs
21
+ )
22
+ return Project(self.trainml, **resp)
23
+
24
+ async def list(self, **kwargs):
25
+ resp = await self.trainml._query(f"/project", "GET", kwargs)
26
+ projects = [Project(self.trainml, **project) for project in resp]
27
+ return projects
28
+
29
+ async def create(self, name, copy_keys=False, copy_secrets=False, **kwargs):
30
+ data = dict(name=name, copy_keys=copy_keys, copy_secrets=copy_secrets)
31
+ payload = {k: v for k, v in data.items() if v is not None}
32
+ logging.info(f"Creating Project {name}")
33
+ resp = await self.trainml._query("/project", "POST", None, payload)
34
+ project = Project(self.trainml, **resp)
35
+ logging.info(f"Created Project {name} with id {project.id}")
36
+
37
+ return project
38
+
39
+ async def remove(self, id, **kwargs):
40
+ await self.trainml._query(f"/project/{id}", "DELETE", kwargs)
41
+
42
+
43
+ class Project:
44
+ def __init__(self, trainml, **kwargs):
45
+ self.trainml = trainml
46
+ self._entity = kwargs
47
+ self._id = self._entity.get("id")
48
+ self._name = self._entity.get("name")
49
+ self._is_owner = self._entity.get("owner")
50
+ self._owner_name = self._entity.get("owner_name")
51
+ self.datastores = ProjectDatastores(self.trainml, self._id)
52
+ self.data_connectors = ProjectDataConnectors(self.trainml, self._id)
53
+ self.services = ProjectServices(self.trainml, self._id)
54
+ self.keys = ProjectKeys(self.trainml, self._id)
55
+ self.secrets = ProjectSecrets(self.trainml, self._id)
56
+
57
+ @property
58
+ def id(self) -> str:
59
+ return self._id
60
+
61
+ @property
62
+ def name(self) -> str:
63
+ return self._name
64
+
65
+ @property
66
+ def is_owner(self) -> bool:
67
+ return self._is_owner
68
+
69
+ @property
70
+ def owner_name(self) -> str:
71
+ return self._owner_name
72
+
73
+ def __str__(self):
74
+ return json.dumps({k: v for k, v in self._entity.items()})
75
+
76
+ def __repr__(self):
77
+ return f"Project( trainml , **{self._entity.__repr__()})"
78
+
79
+ def __bool__(self):
80
+ return bool(self._id)
81
+
82
+ async def remove(self):
83
+ await self.trainml._query(f"/project/{self._id}", "DELETE")
@@ -0,0 +1,70 @@
1
+ import json
2
+ import logging
3
+ from datetime import datetime
4
+ from dateutil import parser, tz
5
+
6
+
7
+ class ProjectSecrets(object):
8
+ def __init__(self, trainml, project_id):
9
+ self.trainml = trainml
10
+ self.project_id = project_id
11
+
12
+ async def list(self, **kwargs):
13
+ resp = await self.trainml._query(
14
+ f"/project/{self.project_id}/secrets", "GET", kwargs
15
+ )
16
+ secrets = [ProjectSecret(self.trainml, **service) for service in resp]
17
+ return secrets
18
+
19
+ async def put(self, name, value, **kwargs):
20
+ data = dict(value=value)
21
+ payload = {k: v for k, v in data.items() if v is not None}
22
+ logging.info(f"Creating Project Secret {name}")
23
+ resp = await self.trainml._query(
24
+ f"/project/{self.project_id}/secret/{name}", "PUT", None, payload
25
+ )
26
+ secret = ProjectSecret(self.trainml, **resp)
27
+ logging.info(f"Created Project Key {name} in project {self.project_id}")
28
+ return secret
29
+
30
+ async def remove(self, name, **kwargs):
31
+ await self.trainml._query(
32
+ f"/project/{self.project_id}/secret/{name}", "DELETE", kwargs
33
+ )
34
+
35
+
36
+ class ProjectSecret:
37
+ def __init__(self, trainml, **kwargs):
38
+ self.trainml = trainml
39
+ self._entity = kwargs
40
+ self._name = self._entity.get("name")
41
+ self._project_uuid = self._entity.get("project_uuid")
42
+ self._created_by = self._entity.get("created_by")
43
+ self._updated_at = self._entity.get("updatedAt")
44
+
45
+ @property
46
+ def name(self) -> str:
47
+ return self._name
48
+
49
+ @property
50
+ def project_uuid(self) -> str:
51
+ return self._project_uuid
52
+
53
+ @property
54
+ def created_by(self) -> str:
55
+ return self._created_by
56
+
57
+ @property
58
+ def updated_at(self) -> datetime:
59
+ timestamp = parser.isoparse(self._updated_at)
60
+ timezone = tz.tzlocal()
61
+ return timestamp.astimezone(timezone)
62
+
63
+ def __str__(self):
64
+ return json.dumps({k: v for k, v in self._entity.items()})
65
+
66
+ def __repr__(self):
67
+ return f"ProjectSecret( trainml , **{self._entity.__repr__()})"
68
+
69
+ def __bool__(self):
70
+ return bool(self._name)
@@ -0,0 +1,63 @@
1
+ import json
2
+ import logging
3
+
4
+
5
+ class ProjectServices(object):
6
+ def __init__(self, trainml, project_id):
7
+ self.trainml = trainml
8
+ self.project_id = project_id
9
+
10
+ async def list(self, **kwargs):
11
+ resp = await self.trainml._query(
12
+ f"/project/{self.project_id}/services", "GET", kwargs
13
+ )
14
+ services = [ProjectService(self.trainml, **service) for service in resp]
15
+ return services
16
+
17
+ async def refresh(self):
18
+ await self.trainml._query(f"/project/{self.project_id}/services", "PATCH")
19
+
20
+
21
+ class ProjectService:
22
+ def __init__(self, trainml, **kwargs):
23
+ self.trainml = trainml
24
+ self._entity = kwargs
25
+ self._id = self._entity.get("id")
26
+ self._project_uuid = self._entity.get("project_uuid")
27
+ self._name = self._entity.get("name")
28
+ self._hostname = self._entity.get("hostname")
29
+ self._public = self._entity.get("public")
30
+ self._region_uuid = self._entity.get("region_uuid")
31
+
32
+ @property
33
+ def id(self) -> str:
34
+ return self._id
35
+
36
+ @property
37
+ def project_uuid(self) -> str:
38
+ return self._project_uuid
39
+
40
+ @property
41
+ def name(self) -> str:
42
+ return self._name
43
+
44
+ @property
45
+ def hostname(self) -> str:
46
+ return self._hostname
47
+
48
+ @property
49
+ def public(self) -> bool:
50
+ return self._public
51
+
52
+ @property
53
+ def region_uuid(self) -> str:
54
+ return self._region_uuid
55
+
56
+ def __str__(self):
57
+ return json.dumps({k: v for k, v in self._entity.items()})
58
+
59
+ def __repr__(self):
60
+ return f"ProjectService( trainml , **{self._entity.__repr__()})"
61
+
62
+ def __bool__(self):
63
+ return bool(self._id)
trainml/volumes.py CHANGED
@@ -26,14 +26,26 @@ class Volumes(object):
26
26
  volumes = [Volume(self.trainml, **volume) for volume in resp]
27
27
  return volumes
28
28
 
29
- async def create(self, name, source_type, source_uri, capacity, **kwargs):
29
+ async def create(
30
+ self,
31
+ name,
32
+ source_type,
33
+ source_uri,
34
+ capacity,
35
+ type="evefs",
36
+ project_uuid=None,
37
+ **kwargs,
38
+ ):
39
+ if not project_uuid:
40
+ project_uuid = self.trainml.active_project
30
41
  data = dict(
31
42
  name=name,
32
43
  source_type=source_type,
33
44
  source_uri=source_uri,
34
45
  capacity=capacity,
35
- source_options=kwargs.get("source_options"),
36
- project_uuid=kwargs.get("project_uuid") or self.trainml.active_project,
46
+ project_uuid=project_uuid,
47
+ type=type,
48
+ **kwargs,
37
49
  )
38
50
  payload = {k: v for k, v in data.items() if v is not None}
39
51
  logging.info(f"Creating Volume {name}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: trainml
3
- Version: 0.5.8
3
+ Version: 0.5.11
4
4
  Summary: trainML client SDK and command line utilities
5
5
  Home-page: https://github.com/trainML/trainml-cli
6
6
  Author: trainML
@@ -4,30 +4,36 @@ examples/local_storage.py,sha256=w8iAeqr5CLOCOkNrqGzEDtybjDGGY7SQUqeE0ibMUrM,174
4
4
  examples/training_inference_pipeline.py,sha256=SNr4RFT9y69F9G9tMD8ONUbJmXRFrq1yxynq-FbfEf8,2334
5
5
  tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  tests/integration/conftest.py,sha256=VWWTfofsFcBOdSCXQxNYbMcDEEaErDi2wFFMn--LE4Y,1134
7
- tests/integration/test_checkpoints_integration.py,sha256=mLha1BhVZ916OJIDOKF6vah3kxJXQu7pbAsHq7lsNCE,3230
7
+ tests/integration/test_checkpoints_integration.py,sha256=Giy5Z6WyselfXzskDGR7Z0ks2KK2U7WGQBDPfyqQ6dk,3206
8
8
  tests/integration/test_datasets_integration.py,sha256=zdHOevduuMUWvVxaHBslpmH8AdvPdqEJ95MdqCC5_rw,3499
9
9
  tests/integration/test_environments_integration.py,sha256=0IckhJvQhd8j4Ouiu0hMq2b7iA1dbZpZYmknyfWjsFM,1403
10
10
  tests/integration/test_gpu_types_integration.py,sha256=V2OncokZWWVq_l5FSmKEDM4EsWrmpB-zKiVPt-we0aY,1256
11
11
  tests/integration/test_jobs_integration.py,sha256=N2peEQGYHteGMd0J7NK4gJaaTyps5jjuiKq2ENnD8SY,25117
12
- tests/integration/test_models_integration.py,sha256=UPRAz0lcpzGihsnDUARoafbd5sZ6OM8TIeh8HNN6Bg0,2902
13
- tests/integration/test_projects_integration.py,sha256=BX-LqLfzawTQUhtx--5dw7QqR8kl_CJvwSCyNXDUQTw,1446
12
+ tests/integration/test_models_integration.py,sha256=u6KVnX-F00TqwiU-gEoZJP1oKfAblqnyRptOc9vNGJ4,2878
14
13
  tests/integration/test_volumes_integration.py,sha256=gOmZpwwFxqeOAVmfKWSTmuyshx8nb2zu_0xv1RUEepM,3270
15
14
  tests/integration/cloudbender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
15
  tests/integration/cloudbender/test_providers_integration.py,sha256=oV8ydFsosDZ_Z1Dkg2IN-ZhWuIl5e_HkHAORMsOsAJc,1473
16
+ tests/integration/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ tests/integration/projects/conftest.py,sha256=IaCvq3G_2uBm-DAfqTUF2K_km06af711bzmp-OMwZBs,242
18
+ tests/integration/projects/test_projects_data_connectors_integration.py,sha256=R90v7HVN4i9k-AOEl17AvnbWIwnD9Fl1OK9IGOV847o,1630
19
+ tests/integration/projects/test_projects_datastores_integration.py,sha256=S9aSvryVjrcoEDezr33x4T5aPjEhUwL9O1-1eyzhQ-s,1469
20
+ tests/integration/projects/test_projects_integration.py,sha256=HP4jPAyTqGt7pwk42bxQsqGp0olgai6sI-S1XXcXoJs,1241
21
+ tests/integration/projects/test_projects_keys_integration.py,sha256=O-a9OwBxIM2l0vi__GMlWP8ncNswxGBJvEhgo8PoalQ,1423
22
+ tests/integration/projects/test_projects_secrets_integration.py,sha256=XMMov60dVyklZH0FzcHgVKOu5zpNH4z7GriOp-wawgI,1478
23
+ tests/integration/projects/test_projects_services_integration.py,sha256=lBnrqFpjsL3zfaJJmFh2rCWfNmmX-TjyOPCR3KobDAc,1530
17
24
  tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- tests/unit/conftest.py,sha256=QW9K3c-rEB8epqOW0tUwTGqcfJv14AW0ovLNqdstpAc,31129
19
- tests/unit/test_auth.py,sha256=nfhlOCR7rUsn_MaD8QQtBc2v0k8pIxqbzGgRAZK1WGc,858
20
- tests/unit/test_checkpoints_unit.py,sha256=4Add2DXZCuriSZ0atvOXc8fsEGMaEfPhYmT8Q3UgP5E,16008
25
+ tests/unit/conftest.py,sha256=IIdY88sGlvFuH2ZZHysWi3QCZ1-oAZ1yG6npKMRjCzI,35521
26
+ tests/unit/test_auth_unit.py,sha256=nfhlOCR7rUsn_MaD8QQtBc2v0k8pIxqbzGgRAZK1WGc,858
27
+ tests/unit/test_checkpoints_unit.py,sha256=7bgpEnjkfETgbEHmYApyD_htEWAUVZdposyYVClU3tQ,15965
21
28
  tests/unit/test_connections_unit.py,sha256=FzN2ddQxNpjxzNGUsXhjTk0HnD24wSPelPTL4o_r-Ho,5507
22
- tests/unit/test_datasets_unit.py,sha256=lVNoBZu4RIiJK26gbUPOUAra_k0YS2GcnjJDnT7UV6Y,15879
29
+ tests/unit/test_datasets_unit.py,sha256=YL_wU-NiXvPFOK_jM8l9q5cZGztsMkgQorggYaLt6Lc,15910
23
30
  tests/unit/test_environments_unit.py,sha256=1QFGf1xwM0yKCyVHT_Xi0DX8g0Aelr0mcqAImEXJfQU,1882
24
31
  tests/unit/test_exceptions.py,sha256=3tAok6kAU1QRjN7qTNVYuSGWDg7IEoK__OXFLyzLr7k,906
25
32
  tests/unit/test_gpu_types_unit.py,sha256=c9ie6YSYT5onBnlmHvHWON9WgQiJ1eO2C-4Tk-UPQHg,2054
26
33
  tests/unit/test_jobs_unit.py,sha256=bZxN9HUfHCyQCjZCZGn6WFIhu8S5FU1z5ZG9sgH2XEg,26835
27
- tests/unit/test_models_unit.py,sha256=uezWF7FUHGmCSQBtpyyKhBttTnCTRjxU22NsHdJLYYg,15064
28
- tests/unit/test_projects_unit.py,sha256=uqMs3v4mNevUSh5QgP54_R88ctqOXdD73t0AgjTWXbg,10743
29
- tests/unit/test_trainml.py,sha256=8vAKvFD1xYsx_VY4HFVa0b1MUlMoNApY6TO8r7vI-UQ,1701
30
- tests/unit/test_volumes_unit.py,sha256=KHVmdbQIiX8tEE09U-XsH-vl6wfYGVoRzR_UQJlhOVE,15305
34
+ tests/unit/test_models_unit.py,sha256=Wg2QsoKqtSFSVf-1tt4sA6OcwMTkSHYPcUBQQOmZCgY,15091
35
+ tests/unit/test_trainml_unit.py,sha256=8vAKvFD1xYsx_VY4HFVa0b1MUlMoNApY6TO8r7vI-UQ,1701
36
+ tests/unit/test_volumes_unit.py,sha256=DF3kFtkIfuZjwacBRpdmMGlPvV7vxaxUAhlstWj2V4w,15382
31
37
  tests/unit/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
38
  tests/unit/cli/conftest.py,sha256=w6p_2URicywJKUCtY79tSD_mx8cwJtxHbK_Lu3grOYs,236
33
39
  tests/unit/cli/test_cli_checkpoint_unit.py,sha256=6gO6PWWxNJiL520mhTFkSUJT7p5-dptLwUgDjPeHNrA,702
@@ -36,7 +42,6 @@ tests/unit/cli/test_cli_environment_unit.py,sha256=7FFKFPVa6yqJqujTXD_tsSUDruW5K
36
42
  tests/unit/cli/test_cli_gpu_unit.py,sha256=FIq3tQIDmeD-pvxkhJKMykfnlWcVxho2vRkoCMXgQxE,650
37
43
  tests/unit/cli/test_cli_job_unit.py,sha256=xUqkLFDIyI1ExiVVgr-218gQSlFSYCm4RRX_eyipJhY,611
38
44
  tests/unit/cli/test_cli_model_unit.py,sha256=fE-CRVg8gbtDlwrKBkf-hc9x7EhFlYeE3jlum1E27EA,629
39
- tests/unit/cli/test_cli_project_unit.py,sha256=pi0N-XVH5wsJQ6idFcRsIofWSAdj8KtK1gwf1J3l2JY,1688
40
45
  tests/unit/cli/test_cli_volume_unit.py,sha256=oggGL2eLiaExP6rSdFmQevxLp6nw5o7SKUEqMKBmy_A,644
41
46
  tests/unit/cli/cloudbender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
47
  tests/unit/cli/cloudbender/test_cli_datastore_unit.py,sha256=DQWDjqg4viBZRONi00nVzqF9rJ5qKOKRub9pKbTmMWU,1381
@@ -44,32 +49,43 @@ tests/unit/cli/cloudbender/test_cli_device_unit.py,sha256=2BSMyXQ8fOzNKh_-pa_tx7
44
49
  tests/unit/cli/cloudbender/test_cli_node_unit.py,sha256=KbK7axJ1L4y4sN7KQRpOVIqphnNpi0aFW4-HlYLtwnI,1316
45
50
  tests/unit/cli/cloudbender/test_cli_provider_unit.py,sha256=Rm-tRNPbTTB7ZzkkIpLfDp_pEYfqihjB0ZYk_EPQUfs,781
46
51
  tests/unit/cli/cloudbender/test_cli_region_unit.py,sha256=iH5AbrzZ-R2EJ-Bd2HFN7FN2lTpkr3-pCLR59ZVvdQU,1262
47
- tests/unit/cli/cloudbender/test_cli_reservation_unit.py,sha256=4LDOJDXygMuho2cdI2K59eq4oyiry9hNaG0avEr0_tw,1311
48
52
  tests/unit/cli/cloudbender/test_cli_service_unit.py,sha256=4LDOJDXygMuho2cdI2K59eq4oyiry9hNaG0avEr0_tw,1311
53
+ tests/unit/cli/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ tests/unit/cli/projects/test_cli_project_data_connector_unit.py,sha256=_NgnxV8zTIycpHKe7dyL6EXq774puFHQjvgCKsiEMO0,993
55
+ tests/unit/cli/projects/test_cli_project_datastore_unit.py,sha256=E_kLoIZ5U92LQaPcYAKDyUqpjM1Xe6PVPvofU1Yn6Yk,936
56
+ tests/unit/cli/projects/test_cli_project_key_unit.py,sha256=Ma5HjsZt2RaHKgmMdGY59EIc2WdAgbWKWn2LvlYeDqQ,894
57
+ tests/unit/cli/projects/test_cli_project_secret_unit.py,sha256=QBkq1gVqkjGUni2xCihL994bvseNcA-dyUWaJVU9GjI,915
58
+ tests/unit/cli/projects/test_cli_project_service_unit.py,sha256=TRNOwK3RUCtktYdCGzfhQE3fE_mn8LweCN5E4gRn1h4,922
59
+ tests/unit/cli/projects/test_cli_project_unit.py,sha256=0IynsMwFsXBZn-u0gX2iir7AjPsNraHe68PuAe-Lkaw,627
49
60
  tests/unit/cloudbender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
61
  tests/unit/cloudbender/test_data_connectors_unit.py,sha256=qy97mNAcy_xEkh8obBobHt16B3e1N3QcBSyfV9xJwPI,5783
51
- tests/unit/cloudbender/test_datastores_unit.py,sha256=54mPokxhrRjlkBfqpmeA_q-PLml-HUNNit91aQVTpCg,5398
62
+ tests/unit/cloudbender/test_datastores_unit.py,sha256=5XUczUrOQ2Zgfb2IbJeEtYxbBWRltEVJ1KIC_UeQjEY,5281
52
63
  tests/unit/cloudbender/test_device_configs_unit.py,sha256=lzyCuF7MRoQrtJVTQFL27lqPnRwQFv25htPgJqDuQI8,5714
53
64
  tests/unit/cloudbender/test_devices_unit.py,sha256=QBWnlOe1tw_XNA_i-yDHkmpGvtK36f2u1HhoXquoVaE,9103
54
65
  tests/unit/cloudbender/test_nodes_unit.py,sha256=BDpfJXCBNNpLt5rhJMk2BVXDQ_4QSmxoVrO_YPs6xBU,6231
55
66
  tests/unit/cloudbender/test_providers_unit.py,sha256=OgxifgC1IqLH8DNMKXy1Ne9_7a75ea6kHEOfRSRoQuQ,4373
56
67
  tests/unit/cloudbender/test_regions_unit.py,sha256=BbJICLIQmlotpA1UmLD0KTW_H9g2UW0J8ZYzQk1_Xjc,6299
57
- tests/unit/cloudbender/test_reservations_unit.py,sha256=nWEZ_p9EF2C49nbgL7Dt4NG2Irmyt94ZqJJQDyNfGFI,5624
58
68
  tests/unit/cloudbender/test_services_unit.py,sha256=fYJx-W89HD-EYkO32_v33X40VxipUfWQCy13FZO2fcA,5220
59
- trainml/__init__.py,sha256=yWyb_WZ7O_z0-KNr8wIIOStr9Te6Hc4DA9mhlXOqwms,432
69
+ tests/unit/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
+ tests/unit/projects/test_project_data_connectors_unit.py,sha256=uQPFx6rwYMWZz1IJkns_LdM5gccyHSIaKb3k8zmfSkY,3385
71
+ tests/unit/projects/test_project_datastores_unit.py,sha256=kcoaSs54gGqJ9gwPMpP6KHAPRvDJtdJpm49s4aYYt3E,3129
72
+ tests/unit/projects/test_project_keys_unit.py,sha256=2-w_VwmWxWHoLWBCoBAfg5WozyeYJHV361ZndlA0xk4,3161
73
+ tests/unit/projects/test_project_secrets_unit.py,sha256=StVlY-ZR3CKxXAt9NL8hTkXUEdgGESH0m6foEPXKE-4,3276
74
+ tests/unit/projects/test_project_services_unit.py,sha256=ZK5nz78RAmmaCrAwYBd34t87dh6etU-7snLB_xukZHM,3331
75
+ tests/unit/projects/test_projects_unit.py,sha256=4Jczapaj5pZOYKmRYN8MEygzyNwULCaOyYSyiNUBsq8,3823
76
+ trainml/__init__.py,sha256=vzWg68mF2ggaSj8F_z_riREX-rzGbJcPhGIDE1jG3yE,433
60
77
  trainml/__main__.py,sha256=JgErYkiskih8Y6oRwowALtR-rwQhAAdqOYWjQraRIPI,59
61
78
  trainml/auth.py,sha256=gruZv27nhttrCbhcVQTH9kZkF2uMm1E06SwA_2pQAHQ,26565
62
- trainml/checkpoints.py,sha256=TF_dZ-umcGiGmEF8cl0bhqChl1Tnp2QsDd-MqhiIcQs,8667
79
+ trainml/checkpoints.py,sha256=Hg3_Si7ohzsv4_8JIjoj9pMRpHNZRWKC5R2gtgmp01s,8790
63
80
  trainml/connections.py,sha256=h-S1NZbOkaXpIlpRStA6q-3eXc_OMlFWOLzF8R9SVG8,20029
64
- trainml/datasets.py,sha256=aIXsn-6ItzSwunT_xt7874XGznCPBMkXk49BDix-nqE,8477
81
+ trainml/datasets.py,sha256=dxTZbK-cnr8eoq48KAx2TZNK1ndcFveTVBtaNK2QyJ0,8600
65
82
  trainml/environments.py,sha256=OH4o08zXZ7IJ2CiA1rPnys2Fl45r8qvQHfM2mCBRAIc,1507
66
- trainml/exceptions.py,sha256=MG1FkcjRacv3HoPuBS1IWLCUk0wGHEQ6DaOzXNymsNI,4094
83
+ trainml/exceptions.py,sha256=Qdof2fKRvbMiwarX1VSw1XJXXJjY71H4U3v05nE7-7g,5468
67
84
  trainml/gpu_types.py,sha256=mm-dwfYc02192bmYPIJmzesndyBcoOdkKYBaYZXOUwU,1901
68
- trainml/jobs.py,sha256=28U0kyqczGhzP-tuRGAk6lNTeOzYdElZ7VpiHgz81rg,18056
69
- trainml/models.py,sha256=UqWoO6pVrSwxnRb1BTQH8czTLkkdTiC_cOsIjz9P8Pk,8161
70
- trainml/projects.py,sha256=ZVsVJtUPTYsQAkCLimjYF3DAwFwQV4ucLila-N-jSJo,6585
85
+ trainml/jobs.py,sha256=5wHiEmHfri1btgIn6zbFp9kIO6EU5FCOVkNMP0-WuYM,17632
86
+ trainml/models.py,sha256=SpVNt9oZMu70m_3VjO9j_QYexw_z-yRqMhIuJXPs4Vg,8284
71
87
  trainml/trainml.py,sha256=EBnqQ3Q291xrPKYuN6xKm5yt0mJQOJ3b7GAlR-fl8NI,10864
72
- trainml/volumes.py,sha256=1EAPOuYhs8WsOZDb0k0qhpqn2WJnoFxDTQ5tv9ZABUw,8312
88
+ trainml/volumes.py,sha256=7T0ZN_Xq3qk4yzw7YYxC0rxH3KqlqADd6HOZCkAfCR4,8443
73
89
  trainml/cli/__init__.py,sha256=Gvj6oGSEtgpb40ACtiVeMD93GM-uy15MG6VlX6rwdwA,4346
74
90
  trainml/cli/checkpoint.py,sha256=8Rh4bmFwJ4DKlIjHK-FLTeRynABqKCgIUGRtbQhAsX4,7170
75
91
  trainml/cli/connection.py,sha256=ELV6bPL30dzttFNxDU7Fb74R8oPL_E70k7TcJEzbwtQ,1700
@@ -77,33 +93,43 @@ trainml/cli/dataset.py,sha256=Pc00M6t7hGoRzCxznmmkijsWhG4PhIfG7UkrwtwykTY,6871
77
93
  trainml/cli/environment.py,sha256=dfm_T8OlCM5M8dLyOQBapJl3eFuVIku2P4JO6V0cYVQ,1019
78
94
  trainml/cli/gpu.py,sha256=CMcQyl2qbUgc2bc-gvUVT6X7bq2-sgiCHl3hyZ6kFWM,883
79
95
  trainml/cli/model.py,sha256=hR23E6ttRXcLk-RofkPK6wUXMO7OU6sT6jTEHTmUg9Q,6111
80
- trainml/cli/project.py,sha256=f772bHs68AVRY60l7dbVKgeDmDC3u2bZjqrz7zm7xvQ,3314
81
96
  trainml/cli/volume.py,sha256=kDUss93N78DT-YlLjC6I3jEq5nBWfRNNR5M4tY_F_Zg,6246
82
97
  trainml/cli/cloudbender/__init__.py,sha256=tKkL8TzD9nEeRtf1OEYM4XZJWb0-rGMPTmLIdA5G_SY,592
83
98
  trainml/cli/cloudbender/data_connector.py,sha256=q0Hqeh5w00Zkmh61fzO3pNR6EmQfoLQ2DbgJ5ZBx1UM,3606
84
- trainml/cli/cloudbender/datastore.py,sha256=gJ-comfAq65uiPoONQ35UIDLNVN7QKMf3l_2EcTN6zY,3478
99
+ trainml/cli/cloudbender/datastore.py,sha256=j67VUoYZOFWP0F7WK8V7fft8HlT4uqauAu0WH-9Dkes,3323
85
100
  trainml/cli/cloudbender/device.py,sha256=KGZCFwwvS4tWsWuudrhlvquu_IFtV7LCUAOmCajicic,3453
86
101
  trainml/cli/cloudbender/node.py,sha256=iN_WaPCxOhtgDtnSsIFAEMGADG4MKiLjWoez6YSYwZI,3843
87
102
  trainml/cli/cloudbender/provider.py,sha256=oFjZWKfFQjNY7OtDu7nUdfv-RTmQc_Huuug963D3BdA,1726
88
103
  trainml/cli/cloudbender/region.py,sha256=X6-FYOb-pGpOEazn-NbsYSwa9ergB7FGATFkTe4a8Pk,2892
89
- trainml/cli/cloudbender/reservation.py,sha256=z2oMYwp-w_Keo1DepKUtuRnwiGz2VscVHDYWEFap1gs,3569
90
104
  trainml/cli/cloudbender/service.py,sha256=Wh6ycEuECiKL7qpFhc4IyO1rR5lvLtIHk3S475_R6pk,3147
91
105
  trainml/cli/job/__init__.py,sha256=ljY-ELeXhXQ7txASbJEKGBom7OXfNyy7sWILz3nxRAE,6545
92
106
  trainml/cli/job/create.py,sha256=pfOCqs5Vfk4PAI5KZpXHJ1vp3DDe4ccvYzieh0oFexY,34288
107
+ trainml/cli/project/__init__.py,sha256=XOBLQMQqlkzMUNoUejXXIP7bY5ebSWKlUn5XGkQVbPw,1904
108
+ trainml/cli/project/data_connector.py,sha256=KLDhpNJfwcJkcmyuJRgcVH70Jf73619O9ddYP8vhMvk,1411
109
+ trainml/cli/project/datastore.py,sha256=IwF0LqsSFn7DrKPRdxQs6kturk9MCI52A1aoWeb7ClA,1336
110
+ trainml/cli/project/key.py,sha256=kQlCs_N-5c27hOyGkmT22_J47x8U6CZaSardsaPYGbw,3203
111
+ trainml/cli/project/secret.py,sha256=LdEd6qJwfRs3JIjoOaNxkDcDuCdYB9GPKHW_vcOBal8,1621
112
+ trainml/cli/project/service.py,sha256=FzcyGI9MN-UvnjdKW7GmXLTXLUIXtuTFAISR_FmCmJo,1310
93
113
  trainml/cloudbender/__init__.py,sha256=iE29obtC0_9f0IhRvHQcG5aY58fVhVYipTakpjAhdss,64
94
114
  trainml/cloudbender/cloudbender.py,sha256=ekJZHSQ1F4HF8y0sAJ3MDB_hiC8QxPv9-O7U24z_RR4,717
95
- trainml/cloudbender/data_connectors.py,sha256=Qr-p9nukBeIaCg2v2plgZTBiBznAIBqDejzWpqHx310,3297
96
- trainml/cloudbender/datastores.py,sha256=biVGifedc3r1DcuxsfCQh-f1Tw4HcJMMJfdgHxPfkKM,3506
115
+ trainml/cloudbender/data_connectors.py,sha256=e0KAkKtcOcxW-UFHHUdF6deAYtP1SFv2PH9VyvizHek,3420
116
+ trainml/cloudbender/datastores.py,sha256=HGD0SLd0KYxkwl_r9NpnkcfKmQJ0q86BaxWwwyQT9W0,3255
97
117
  trainml/cloudbender/device_configs.py,sha256=DJWiGFaOE4C4xLE1BLDAiEjeL4T00R3FA_pb1xnSOr4,3399
98
118
  trainml/cloudbender/devices.py,sha256=QORNmKdLJoqGZmeWXRnivC1JmNBIw-ebvf4bsoem3r8,5660
99
- trainml/cloudbender/nodes.py,sha256=7HV2VLmxiUcJ-Kc6AAXS3M8C_XO-HKmaVgJpPdVnBQk,4332
100
- trainml/cloudbender/providers.py,sha256=-gkdiTu6Ah2znUuyyc3ZuRALagW8s1-OgqVjtlvc1AU,2036
101
- trainml/cloudbender/regions.py,sha256=Aqc_MeLVAeEv21e-lR5u8x1eintqUhZT2DBiQG3AcEE,3570
102
- trainml/cloudbender/reservations.py,sha256=rOrGXWIUHON4ad2aufEcvK4Yv_Mv3dDoScUtLJE8LWw,3586
119
+ trainml/cloudbender/nodes.py,sha256=U2sTIL2fuBVsNFPsJrvB2JbBcuLULF1-AwJ4dp5ChmM,5924
120
+ trainml/cloudbender/providers.py,sha256=22ymUl1KLC8UlyoWMsIrOKhUDOwnhklhHQ3EZ_V6eWA,3738
121
+ trainml/cloudbender/regions.py,sha256=nfSY9fIWp_AaRE_1Y0qwXX6WVSyPKxpji-zUfM3BNUo,5157
103
122
  trainml/cloudbender/services.py,sha256=KC3VcyljvnazUUG-Tzwm6Ab6d0--yuccXjOaMgYB5uA,5126
104
- trainml-0.5.8.dist-info/LICENSE,sha256=s0lpBxhSSUEpMavwde-Vb6K_K7xDCTTvSpNznVqVGR0,1069
105
- trainml-0.5.8.dist-info/METADATA,sha256=Ko9Ekastl7ICUzyWzRirhCW2Q73n24_C5fU1tTxPQLw,7345
106
- trainml-0.5.8.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
107
- trainml-0.5.8.dist-info/entry_points.txt,sha256=OzBDm2wXby1bSGF02jTVxzRFZLejnbFiLHXhKdW3Bds,63
108
- trainml-0.5.8.dist-info/top_level.txt,sha256=Y1kLFRWKUW7RG8BX7cvejHF_yW8wBOaRYF1JQHENY4w,23
109
- trainml-0.5.8.dist-info/RECORD,,
123
+ trainml/projects/__init__.py,sha256=6NKCcHtQMeGB1IyU-djANphfnDX6MEkrXUM5Fyq9fWg,75
124
+ trainml/projects/data_connectors.py,sha256=Y8lJNF9K5JZlwfKTtN9gh7eSRAivgiPWe_lx05pGM2U,1662
125
+ trainml/projects/datastores.py,sha256=oyRffW8L7Z1tdqspl58Zf1ces0p-Stk0EbnMRaenkUw,1560
126
+ trainml/projects/keys.py,sha256=qcQAdysTbfVW19tzzxZDvBBWjU9DG0dkViLmG_S0SyM,2157
127
+ trainml/projects/projects.py,sha256=mxMGmBppoFbwebMitczZjeNEODrzt0AuNm1LGNegyPo,2755
128
+ trainml/projects/secrets.py,sha256=5qNPWITH8qtlXKkPWnFOzH0HPU7Z0K1OeW-9p7haOzM,2157
129
+ trainml/projects/services.py,sha256=ZP-6CDXktIe6p89Hshgs91HLWXQPNWeU7VFtoKUPHXo,1679
130
+ trainml-0.5.11.dist-info/LICENSE,sha256=s0lpBxhSSUEpMavwde-Vb6K_K7xDCTTvSpNznVqVGR0,1069
131
+ trainml-0.5.11.dist-info/METADATA,sha256=z5-C7kUq2eL3_WS_uLwEIILAIBF0FAAErmoI1EYKaiw,7346
132
+ trainml-0.5.11.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
133
+ trainml-0.5.11.dist-info/entry_points.txt,sha256=OzBDm2wXby1bSGF02jTVxzRFZLejnbFiLHXhKdW3Bds,63
134
+ trainml-0.5.11.dist-info/top_level.txt,sha256=Y1kLFRWKUW7RG8BX7cvejHF_yW8wBOaRYF1JQHENY4w,23
135
+ trainml-0.5.11.dist-info/RECORD,,
@@ -1,34 +0,0 @@
1
- import re
2
- import json
3
- import click
4
- from unittest.mock import AsyncMock, patch
5
- from pytest import mark, fixture, raises
6
-
7
- pytestmark = [mark.cli, mark.unit, mark.cloudbender, mark.services]
8
-
9
- from trainml.cli.cloudbender import service as specimen
10
- from trainml.cloudbender.services import Service
11
-
12
-
13
- def test_list(runner, mock_services):
14
- with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
15
- mock_trainml.cloudbender = AsyncMock()
16
- mock_trainml.cloudbender.services = AsyncMock()
17
- mock_trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
18
- result = runner.invoke(
19
- specimen,
20
- args=["list", "--provider=prov-id-1", "--region=reg-id-1"],
21
- )
22
- assert result.exit_code == 0
23
- mock_trainml.cloudbender.services.list.assert_called_once_with(
24
- provider_uuid="prov-id-1", region_uuid="reg-id-1"
25
- )
26
-
27
-
28
- def test_list_no_provider(runner, mock_services):
29
- with patch("trainml.cli.TrainML", new=AsyncMock) as mock_trainml:
30
- mock_trainml.cloudbender = AsyncMock()
31
- mock_trainml.cloudbender.services = AsyncMock()
32
- mock_trainml.cloudbender.services.list = AsyncMock(return_value=mock_services)
33
- result = runner.invoke(specimen, ["list"])
34
- assert result.exit_code != 0