proximl 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.
proximl/jobs.py CHANGED
@@ -77,8 +77,7 @@ class Jobs(object):
77
77
  model=model,
78
78
  endpoint=endpoint,
79
79
  source_job_uuid=kwargs.get("source_job_uuid"),
80
- project_uuid=kwargs.get("project_uuid")
81
- or self.proximl.active_project,
80
+ project_uuid=kwargs.get("project_uuid") or self.proximl.active_project,
82
81
  )
83
82
  payload = {
84
83
  k: v
@@ -103,9 +102,7 @@ class Jobs(object):
103
102
  return job
104
103
 
105
104
  async def remove(self, id, **kwargs):
106
- await self.proximl._query(
107
- f"/job/{id}", "DELETE", dict(**kwargs, force=True)
108
- )
105
+ await self.proximl._query(f"/job/{id}", "DELETE", dict(**kwargs, force=True))
109
106
 
110
107
 
111
108
  class Job:
@@ -308,18 +305,26 @@ class Job:
308
305
  entity_type="job",
309
306
  project_uuid=self._job.get("project_uuid"),
310
307
  cidr=self.dict.get("vpn").get("cidr"),
311
- ssh_port=self._job.get("vpn").get("client").get("ssh_port")
312
- if self._job.get("vpn").get("client")
313
- else None,
314
- model_path=self._job.get("model").get("source_uri")
315
- if self._job.get("model").get("source_type") == "local"
316
- else None,
317
- input_path=self._job.get("data").get("input_uri")
318
- if self._job.get("data").get("input_type") == "local"
319
- else None,
320
- output_path=self._job.get("data").get("output_uri")
321
- if self._job.get("data").get("output_type") == "local"
322
- else None,
308
+ ssh_port=(
309
+ self._job.get("vpn").get("client").get("ssh_port")
310
+ if self._job.get("vpn").get("client")
311
+ else None
312
+ ),
313
+ model_path=(
314
+ self._job.get("model").get("source_uri")
315
+ if self._job.get("model").get("source_type") == "local"
316
+ else None
317
+ ),
318
+ input_path=(
319
+ self._job.get("data").get("input_uri")
320
+ if self._job.get("data").get("input_type") == "local"
321
+ else None
322
+ ),
323
+ output_path=(
324
+ self._job.get("data").get("output_uri")
325
+ if self._job.get("data").get("output_type") == "local"
326
+ else None
327
+ ),
323
328
  )
324
329
  return details
325
330
 
@@ -396,8 +401,7 @@ class Job:
396
401
 
397
402
  def _get_msg_handler(self, msg_handler):
398
403
  worker_numbers = {
399
- w.get("job_worker_uuid"): ind + 1
400
- for ind, w in enumerate(self._workers)
404
+ w.get("job_worker_uuid"): ind + 1 for ind, w in enumerate(self._workers)
401
405
  }
402
406
  worker_numbers["data_worker"] = 0
403
407
 
@@ -407,9 +411,7 @@ class Job:
407
411
  if msg_handler:
408
412
  msg_handler(data)
409
413
  else:
410
- timestamp = datetime.fromtimestamp(
411
- int(data.get("time")) / 1000
412
- )
414
+ timestamp = datetime.fromtimestamp(int(data.get("time")) / 1000)
413
415
  if len(self._workers) > 1:
414
416
  print(
415
417
  f"{timestamp.strftime('%m/%d/%Y, %H:%M:%S')}: Worker {data.get('worker_number')} - {data.get('msg').rstrip()}"
@@ -422,10 +424,7 @@ class Job:
422
424
  return handler
423
425
 
424
426
  async def attach(self, msg_handler=None):
425
- if (
426
- self.type == "notebook"
427
- and self.status != "waiting for data/model download"
428
- ):
427
+ if self.type == "notebook" and self.status != "waiting for data/model download":
429
428
  raise SpecificationError(
430
429
  "type",
431
430
  "Notebooks cannot be attached to after model download is complete. Use open() instead.",
@@ -442,9 +441,7 @@ class Job:
442
441
  async def copy(self, name, **kwargs):
443
442
  logging.debug(f"copy request - name: {name} ; kwargs: {kwargs}")
444
443
  if self.type != "notebook":
445
- raise SpecificationError(
446
- "job", "Only notebook job types can be copied"
447
- )
444
+ raise SpecificationError("job", "Only notebook job types can be copied")
448
445
 
449
446
  job = await self.proximl.jobs.create(
450
447
  name,
@@ -504,9 +501,7 @@ class Job:
504
501
 
505
502
  POLL_INTERVAL_MIN = 5
506
503
  POLL_INTERVAL_MAX = 60
507
- POLL_INTERVAL = max(
508
- min(timeout / 60, POLL_INTERVAL_MAX), POLL_INTERVAL_MIN
509
- )
504
+ POLL_INTERVAL = max(min(timeout / 60, POLL_INTERVAL_MAX), POLL_INTERVAL_MIN)
510
505
  retry_count = math.ceil(timeout / POLL_INTERVAL)
511
506
  count = 0
512
507
  while count < retry_count:
@@ -519,23 +514,25 @@ class Job:
519
514
  raise e
520
515
  if (
521
516
  self.status == status
522
- or (
523
- self.type == "training"
524
- and status == "finished"
525
- and self.status == "stopped"
526
- )
527
517
  or (
528
518
  status
529
519
  in [
530
520
  "waiting for GPUs",
531
521
  "waiting for resources",
532
522
  ] ## this status could be very short and the polling could miss it
533
- and self.status in ["starting", "provisioning", "running"]
523
+ and self.status
524
+ not in ["new", "waiting for GPUs", "waiting for resources"]
534
525
  )
535
526
  or (
536
527
  status
537
528
  == "waiting for data/model download" ## this status could be very short and the polling could miss it
538
- and self.status in ["starting", "provisioning", "running"]
529
+ and self.status
530
+ not in [
531
+ "new",
532
+ "waiting for GPUs",
533
+ "waiting for resources",
534
+ "waiting for data/model download",
535
+ ]
539
536
  )
540
537
  ):
541
538
  return self
proximl/proximl.py CHANGED
@@ -10,6 +10,7 @@ from proximl.auth import Auth
10
10
  from proximl.datasets import Datasets
11
11
  from proximl.models import Models
12
12
  from proximl.checkpoints import Checkpoints
13
+ from proximl.volumes import Volumes
13
14
  from proximl.jobs import Jobs
14
15
  from proximl.gpu_types import GpuTypes
15
16
  from proximl.environments import Environments
@@ -66,6 +67,7 @@ class ProxiML(object):
66
67
  self.datasets = Datasets(self)
67
68
  self.models = Models(self)
68
69
  self.checkpoints = Checkpoints(self)
70
+ self.volumes = Volumes(self)
69
71
  self.jobs = Jobs(self)
70
72
  self.gpu_types = GpuTypes(self)
71
73
  self.environments = Environments(self)
@@ -117,9 +119,7 @@ class ProxiML(object):
117
119
  )
118
120
  if params:
119
121
  if not isinstance(params, dict):
120
- raise ProxiMLException(
121
- "Query parameters must be a valid dictionary"
122
- )
122
+ raise ProxiMLException("Query parameters must be a valid dictionary")
123
123
  params = {
124
124
  k: (str(v).lower() if isinstance(v, bool) else v)
125
125
  for k, v in params.items()
@@ -155,13 +155,9 @@ class ProxiML(object):
155
155
  content_type = resp.headers.get("content-type", "")
156
156
  resp.close()
157
157
  if content_type == "application/json":
158
- raise ApiError(
159
- resp.status, json.loads(what.decode("utf8"))
160
- )
158
+ raise ApiError(resp.status, json.loads(what.decode("utf8")))
161
159
  else:
162
- raise ApiError(
163
- resp.status, {"message": what.decode("utf8")}
164
- )
160
+ raise ApiError(resp.status, {"message": what.decode("utf8")})
165
161
  results = await resp.json()
166
162
  return results
167
163
 
@@ -273,15 +269,11 @@ class ProxiML(object):
273
269
  logging.debug(f"Websocket Disconnected. Done? {done}")
274
270
  except Exception as e:
275
271
  connection_tries += 1
276
- logging.debug(
277
- f"Connection error: {traceback.format_exc()}"
278
- )
272
+ logging.debug(f"Connection error: {traceback.format_exc()}")
279
273
  if connection_tries == 5:
280
274
  raise ApiError(
281
275
  500,
282
- {
283
- "message": f"Connection error: {traceback.format_exc()}"
284
- },
276
+ {"message": f"Connection error: {traceback.format_exc()}"},
285
277
  )
286
278
 
287
279
  def set_active_project(self, project_uuid):
proximl/volumes.py ADDED
@@ -0,0 +1,255 @@
1
+ import json
2
+ import logging
3
+ import math
4
+ import asyncio
5
+ from datetime import datetime
6
+
7
+ from .exceptions import (
8
+ VolumeError,
9
+ ApiError,
10
+ SpecificationError,
11
+ ProxiMLException,
12
+ )
13
+ from .connections import Connection
14
+
15
+
16
+ class Volumes(object):
17
+ def __init__(self, proximl):
18
+ self.proximl = proximl
19
+
20
+ async def get(self, id, **kwargs):
21
+ resp = await self.proximl._query(f"/volume/{id}", "GET", kwargs)
22
+ return Volume(self.proximl, **resp)
23
+
24
+ async def list(self, **kwargs):
25
+ resp = await self.proximl._query(f"/volume", "GET", kwargs)
26
+ volumes = [Volume(self.proximl, **volume) for volume in resp]
27
+ return volumes
28
+
29
+ async def create(self, name, source_type, source_uri, capacity, **kwargs):
30
+ data = dict(
31
+ name=name,
32
+ source_type=source_type,
33
+ source_uri=source_uri,
34
+ capacity=capacity,
35
+ source_options=kwargs.get("source_options"),
36
+ project_uuid=kwargs.get("project_uuid") or self.proximl.active_project,
37
+ )
38
+ payload = {k: v for k, v in data.items() if v is not None}
39
+ logging.info(f"Creating Volume {name}")
40
+ resp = await self.proximl._query("/volume", "POST", None, payload)
41
+ volume = Volume(self.proximl, **resp)
42
+ logging.info(f"Created Volume {name} with id {volume.id}")
43
+
44
+ return volume
45
+
46
+ async def remove(self, id, **kwargs):
47
+ await self.proximl._query(f"/volume/{id}", "DELETE", dict(**kwargs, force=True))
48
+
49
+
50
+ class Volume:
51
+ def __init__(self, proximl, **kwargs):
52
+ self.proximl = proximl
53
+ self._volume = kwargs
54
+ self._id = self._volume.get("id", self._volume.get("id"))
55
+ self._status = self._volume.get("status")
56
+ self._name = self._volume.get("name")
57
+ self._capacity = self._volume.get("capacity")
58
+ self._used_size = self._volume.get("used_size")
59
+ self._billed_size = self._volume.get("billed_size")
60
+ self._project_uuid = self._volume.get("project_uuid")
61
+
62
+ @property
63
+ def id(self) -> str:
64
+ return self._id
65
+
66
+ @property
67
+ def status(self) -> str:
68
+ return self._status
69
+
70
+ @property
71
+ def name(self) -> str:
72
+ return self._name
73
+
74
+ @property
75
+ def capacity(self) -> str:
76
+ return self._capacity
77
+
78
+ @property
79
+ def used_size(self) -> int:
80
+ return self._used_size
81
+
82
+ @property
83
+ def billed_size(self) -> int:
84
+ return self._billed_size
85
+
86
+ def __str__(self):
87
+ return json.dumps({k: v for k, v in self._volume.items()})
88
+
89
+ def __repr__(self):
90
+ return f"Volume( proximl , **{self._volume.__repr__()})"
91
+
92
+ def __bool__(self):
93
+ return bool(self._id)
94
+
95
+ async def get_log_url(self):
96
+ resp = await self.proximl._query(
97
+ f"/volume/{self._id}/logs",
98
+ "GET",
99
+ dict(project_uuid=self._project_uuid),
100
+ )
101
+ return resp
102
+
103
+ async def get_details(self):
104
+ resp = await self.proximl._query(
105
+ f"/volume/{self._id}/details",
106
+ "GET",
107
+ dict(project_uuid=self._project_uuid),
108
+ )
109
+ return resp
110
+
111
+ async def get_connection_utility_url(self):
112
+ resp = await self.proximl._query(
113
+ f"/volume/{self._id}/download",
114
+ "GET",
115
+ dict(project_uuid=self._project_uuid),
116
+ )
117
+ return resp
118
+
119
+ def get_connection_details(self):
120
+ if self._volume.get("vpn"):
121
+ details = dict(
122
+ entity_type="volume",
123
+ project_uuid=self._volume.get("project_uuid"),
124
+ cidr=self._volume.get("vpn").get("cidr"),
125
+ ssh_port=self._volume.get("vpn").get("client").get("ssh_port"),
126
+ input_path=(
127
+ self._volume.get("source_uri")
128
+ if self.status in ["new", "downloading"]
129
+ else None
130
+ ),
131
+ output_path=(
132
+ self._volume.get("output_uri")
133
+ if self.status == "exporting"
134
+ else None
135
+ ),
136
+ )
137
+ else:
138
+ details = dict()
139
+ return details
140
+
141
+ async def connect(self):
142
+ if self.status in ["ready", "failed"]:
143
+ raise SpecificationError(
144
+ "status",
145
+ f"You can only connect to downloading or exporting volumes.",
146
+ )
147
+ if self.status == "new":
148
+ await self.wait_for("downloading")
149
+ connection = Connection(
150
+ self.proximl, entity_type="volume", id=self.id, entity=self
151
+ )
152
+ await connection.start()
153
+ return connection.status
154
+
155
+ async def disconnect(self):
156
+ connection = Connection(
157
+ self.proximl, entity_type="volume", id=self.id, entity=self
158
+ )
159
+ await connection.stop()
160
+ return connection.status
161
+
162
+ async def remove(self, force=False):
163
+ await self.proximl._query(
164
+ f"/volume/{self._id}",
165
+ "DELETE",
166
+ dict(project_uuid=self._project_uuid, force=force),
167
+ )
168
+
169
+ async def rename(self, name):
170
+ resp = await self.proximl._query(
171
+ f"/volume/{self._id}",
172
+ "PATCH",
173
+ dict(project_uuid=self._project_uuid),
174
+ dict(name=name),
175
+ )
176
+ self.__init__(self.proximl, **resp)
177
+ return self
178
+
179
+ async def export(self, output_type, output_uri, output_options=dict()):
180
+ resp = await self.proximl._query(
181
+ f"/volume/{self._id}/export",
182
+ "POST",
183
+ dict(project_uuid=self._project_uuid),
184
+ dict(
185
+ output_type=output_type,
186
+ output_uri=output_uri,
187
+ output_options=output_options,
188
+ ),
189
+ )
190
+ self.__init__(self.proximl, **resp)
191
+ return self
192
+
193
+ def _get_msg_handler(self, msg_handler):
194
+ def handler(data):
195
+ if data.get("type") == "subscription":
196
+ if msg_handler:
197
+ msg_handler(data)
198
+ else:
199
+ timestamp = datetime.fromtimestamp(int(data.get("time")) / 1000)
200
+ print(
201
+ f"{timestamp.strftime('%m/%d/%Y, %H:%M:%S')}: {data.get('msg').rstrip()}"
202
+ )
203
+
204
+ return handler
205
+
206
+ async def attach(self, msg_handler=None):
207
+ await self.refresh()
208
+ if self.status not in ["ready", "failed"]:
209
+ await self.proximl._ws_subscribe(
210
+ "volume",
211
+ self._project_uuid,
212
+ self.id,
213
+ self._get_msg_handler(msg_handler),
214
+ )
215
+
216
+ async def refresh(self):
217
+ resp = await self.proximl._query(
218
+ f"/volume/{self.id}",
219
+ "GET",
220
+ dict(project_uuid=self._project_uuid),
221
+ )
222
+ self.__init__(self.proximl, **resp)
223
+ return self
224
+
225
+ async def wait_for(self, status, timeout=300):
226
+ valid_statuses = ["downloading", "ready", "archived"]
227
+ if not status in valid_statuses:
228
+ raise SpecificationError(
229
+ "status",
230
+ f"Invalid wait_for status {status}. Valid statuses are: {valid_statuses}",
231
+ )
232
+ if self.status == status:
233
+ return
234
+ POLL_INTERVAL_MIN = 5
235
+ POLL_INTERVAL_MAX = 60
236
+ POLL_INTERVAL = max(min(timeout / 60, POLL_INTERVAL_MAX), POLL_INTERVAL_MIN)
237
+ retry_count = math.ceil(timeout / POLL_INTERVAL)
238
+ count = 0
239
+ while count < retry_count:
240
+ await asyncio.sleep(POLL_INTERVAL)
241
+ try:
242
+ await self.refresh()
243
+ except ApiError as e:
244
+ if status == "archived" and e.status == 404:
245
+ return
246
+ raise e
247
+ if self.status == status:
248
+ return self
249
+ elif self.status == "failed":
250
+ raise VolumeError(self.status, self)
251
+ else:
252
+ count += 1
253
+ logging.debug(f"self: {self}, retry count {count}")
254
+
255
+ raise ProxiMLException(f"Timeout waiting for {status}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: proximl
3
- Version: 0.5.4
3
+ Version: 0.5.6
4
4
  Summary: proxiML client SDK and command line utilities
5
5
  Home-page: https://github.com/proxiML/python-sdk
6
6
  Author: proxiML
@@ -2,20 +2,21 @@ examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  examples/create_dataset_and_training_job.py,sha256=Fqueoz2KD1MTxnU960iqHUdxvo68Xe64HT5XS55lI9w,1178
3
3
  examples/local_storage.py,sha256=6K6LMO7ZPI7N2KdBcgqXSvdsqJfjISzN4yRO9YrJqbA,1745
4
4
  examples/training_inference_pipeline.py,sha256=pxux0QUUtRXxKj2rX-6fPEKBIi43mhRd1zJ-Lf1ZJGI,2334
5
- proximl/__init__.py,sha256=CW5DS3tZElDWIqGtqV8IS_5QxZk8vO7KIZcfdZ8g0gU,432
5
+ proximl/__init__.py,sha256=3gq9ZsAAIsysDGCFRY4rF-eaMA6i7uPpZDDQ39rjBKM,432
6
6
  proximl/__main__.py,sha256=JgErYkiskih8Y6oRwowALtR-rwQhAAdqOYWjQraRIPI,59
7
7
  proximl/auth.py,sha256=LacGBDAVel5HcJx7JXp1wVn3s0gZc7nf--vDfSFOXYU,26565
8
8
  proximl/checkpoints.py,sha256=JPSq9iTSb6dBu0JFKJZgMqDBt9kSGxfl2OaxKehk4QY,8274
9
9
  proximl/connections.py,sha256=0C8VJSkDturQVlzg_3yAkQz8W9NAmgzDCBRK_SrzeUI,20035
10
10
  proximl/datasets.py,sha256=RB7IiDkWZPuwFw1o0xKQn10HS_3ui_BZf7tVlAvCIHA,7935
11
11
  proximl/environments.py,sha256=L_cRmau1wJxpGvnJAqgms-GiNdDhiuOntrlBqsdoE3A,1507
12
- proximl/exceptions.py,sha256=amVbfciOptsivh_z5rORxKGSj1QdeZx09myfQxObFZ8,3724
12
+ proximl/exceptions.py,sha256=3q8qj-sahwEEHeYyjY89GrytVAgHDApN8HSCB3dhnf4,4094
13
13
  proximl/gpu_types.py,sha256=V-EZzE-hDLi5eVQ2_9yGLTm8-Qk1AnnzctfSVC44yLY,1901
14
- proximl/jobs.py,sha256=F-CMcU1l0RTPFT9NI5t5RtCdmU_gP2N3c7QHTnPY9cY,17807
14
+ proximl/jobs.py,sha256=kQbC9ojrMEvRAysFfftwLdVtNDjpiFBfji4bz1To82E,17838
15
15
  proximl/models.py,sha256=QLtkIoznww5cZE_Eqoy7IaEgCEfNbJOe_21hdoExO-k,7750
16
16
  proximl/projects.py,sha256=87Fsce8BkPJLN_cEsZ3FLequpBgmd8WtjY7Vs7uZkO4,5209
17
- proximl/proximl.py,sha256=FAfAq6P8UOspuIavAEdYcXkM12TARgt86V5uB-zygTo,11045
18
- proximl/cli/__init__.py,sha256=G408VR_7LNs2Jww_hiLhFEPs0IHYAVOYEJ9barZcdLM,4338
17
+ proximl/proximl.py,sha256=yzKbJ7ak8YiVv6q7CEagPufECNU4YTNeul6N3OuyH1M,10864
18
+ proximl/volumes.py,sha256=VnlgTeQwoDKGpZRhMrSKtxe4EWzb4qQ-OdDyaJohH5Y,8094
19
+ proximl/cli/__init__.py,sha256=R_8ExAKQp67N2xtwGM00gtK3zSoWPGruHAP_XFLddSI,4346
19
20
  proximl/cli/checkpoint.py,sha256=Iv1i1EAt2LJey2wy2ioQ6-ZysqwRG4kFj0lnE6INZCM,7170
20
21
  proximl/cli/connection.py,sha256=YiWqRIB9ZfTl30DjDFaJEpXuDrA-Ldl9PEzFFdZ_hFI,1700
21
22
  proximl/cli/dataset.py,sha256=ueoeicBY8aMLpvpKUIBICnS9GsEnDOj7ZlFmOfjjY4c,6871
@@ -23,6 +24,7 @@ proximl/cli/environment.py,sha256=nh7oYbG5oOrZEpZkMkKgvzFXmQJWnFTMw1-YbuvkdFU,10
23
24
  proximl/cli/gpu.py,sha256=xL8eqM5ca_Ueaj8cWit1iKn34KhaR0StrubVeRU2YQY,883
24
25
  proximl/cli/model.py,sha256=xdjveIaRPK7MdfrnFygPEuwYRJRW9VqheZ-11XnXDcE,6111
25
26
  proximl/cli/project.py,sha256=Er1twSiWQSAKir-hBIT9fRo2fc_UGqFoIJOwwjQGmlo,3522
27
+ proximl/cli/volume.py,sha256=uyIrKov4zwCjyLyZrEJYoEbIkS0zdU3xSyWZk2BM1kA,6246
26
28
  proximl/cli/cloudbender/__init__.py,sha256=vxj62MyM3sC9h8M4ii3szH4s9JvEhicOQ0D0m7eNwPA,534
27
29
  proximl/cli/cloudbender/datastore.py,sha256=_vQOj-NfrL_nj4HfxNJL63TJZjLgfDyztRLyaRU58v8,3478
28
30
  proximl/cli/cloudbender/device.py,sha256=FdQZPESP6YBfUSzXq1Byu7eNMKi59qSOICONK-TEljI,3453
@@ -30,6 +32,7 @@ proximl/cli/cloudbender/node.py,sha256=xxzj68YvpRey2vZQasgYTnwv3x7TnwpuPSSf8Ma5a
30
32
  proximl/cli/cloudbender/provider.py,sha256=qhWbDK1tWi00wQWEYqGw7yGoZx0nEjV40GLHRuuE86c,1726
31
33
  proximl/cli/cloudbender/region.py,sha256=WnSkY4dXKRJ-FNaoxMfmoh6iuUx5dXCNJmEFT34Xtao,2892
32
34
  proximl/cli/cloudbender/reservation.py,sha256=xzHs5l8BbmYgKUq6kfFU-jEtRQY0j_vYnmRVcL4wwDo,3569
35
+ proximl/cli/cloudbender/service.py,sha256=YimwXQml82-PKKQIqu9Cvggo9wOKLVTJPxMvDf4pgn8,2869
33
36
  proximl/cli/job/__init__.py,sha256=s8mU2PvCWDcv4gGT3EmjHn8MIZlXBAoayoZKmnKpXnY,6545
34
37
  proximl/cli/job/create.py,sha256=sGvbenY0yxvxHo-FZVbdw8FaZx5D4ekTCjD7P4YHG4g,34288
35
38
  proximl/cloudbender/__init__.py,sha256=iE29obtC0_9f0IhRvHQcG5aY58fVhVYipTakpjAhdss,64
@@ -41,19 +44,21 @@ proximl/cloudbender/nodes.py,sha256=QeWUaWW1HNvCune1lhakcve6LJyMzOy7cjCtvyOiaTs,
41
44
  proximl/cloudbender/providers.py,sha256=cH5lCew5WCFpXYS93vuoGNWkZyx7T_mdMH6YNWp2QGs,2036
42
45
  proximl/cloudbender/regions.py,sha256=Nu1LT6nuLD8Nt-5-7_FLlxDNZoDDAY6QduTdEBqfxJA,3570
43
46
  proximl/cloudbender/reservations.py,sha256=14ImJRLWQGG7CXDYhDnOI2W8pnP6CVVG2aVpysQVN0E,3586
47
+ proximl/cloudbender/services.py,sha256=KR0EQ-BUVk1ov9Q195NsnfiSiMb9vOYD8XyxD87RRvw,3222
44
48
  tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
49
  tests/integration/conftest.py,sha256=zRWpherX-yfbpk7xqZk9bIZCyJ-dwVeszY_7kekn2M4,1134
46
- tests/integration/test_checkpoints_integration.py,sha256=QJq6C1PHhS3MtmFIH3dX0aGNw4OvqBpVjvIzwLqPf4E,3128
47
- tests/integration/test_datasets_integration.py,sha256=yLAM2FUlMOIYN4WZYN82uumXHcXJacmwSgzmy88IIkg,3424
50
+ tests/integration/test_checkpoints_integration.py,sha256=DUA6ZlX0gsnKCEvFmWCKbKkfJG3dQG6uD8T3fgo7y0M,3230
51
+ tests/integration/test_datasets_integration.py,sha256=Ndp8itnncDSjVH0t5BM5R_-_yL4qt6JrkQAVOTMi1R8,3499
48
52
  tests/integration/test_environments_integration.py,sha256=7P6pKSyxA7rTwyNCD9HEaM2ablMG8WcBesOzkG-BgsQ,1403
49
53
  tests/integration/test_gpu_types_integration.py,sha256=Zv-yrHcAgKau9BJQvzi92bdrRHhLPl_hbhhzNLEWJ9w,1256
50
- tests/integration/test_jobs_integration.py,sha256=23bUE9Q0gLu41CrhCqLvoNSNMXj7_dWpg2O1--YumxI,23341
51
- tests/integration/test_models_integration.py,sha256=qbSzhCbxvrZQEFOvHJVBSmLr3fxoGD8PYwTcPyTX7J0,2848
52
- tests/integration/test_projects_integration.py,sha256=2iJ_I_LbV2jsGziWdwJ0H9o83IS24EGmS48wQrQHkbw,1492
54
+ tests/integration/test_jobs_integration.py,sha256=fMqYfdzHOxUxtRGe0XZlsFhjUGoeo0Prxbq5_yQvroc,24730
55
+ tests/integration/test_models_integration.py,sha256=JFgX6V652iMobpNKfn0XdP9_TDg5pnVtG8lL6yrEOZk,2902
56
+ tests/integration/test_projects_integration.py,sha256=XdGGqvOQby77kMfoD_zAukKvN6tN7v1QydZ4hFp7u_s,1446
57
+ tests/integration/test_volumes_integration.py,sha256=Xo2Whw2U-7jyvESIkyex3f0SMXKlExe3kLmsbpXTHhQ,3270
53
58
  tests/integration/cloudbender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
59
  tests/integration/cloudbender/test_providers_integration.py,sha256=gFqPQom-Cn1iZC50_ChQ2us2_f4tIPATQSAUcWdf7ss,1473
55
60
  tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
- tests/unit/conftest.py,sha256=Hy2_Wz73PQak2b6MCDyz75sGZhbndRquifAFELJlSjE,29059
61
+ tests/unit/conftest.py,sha256=dilDp7ZSmyg9tJbkJoGcqUF07JBTdkNoULOR6qK7NsU,31197
57
62
  tests/unit/test_auth.py,sha256=IJZHT5CZLNfu3MybTdEWIsKlvxNfFYpZ6oWYzbS856g,858
58
63
  tests/unit/test_checkpoints_unit.py,sha256=WfFE6HvQHglBKfcJ3B0IYXdXpaNmcL2BDurRQmIbFAU,16008
59
64
  tests/unit/test_connections_unit.py,sha256=LFAZzlrvL9oM8rZJTiC1oA9quw1KA2vMUCc3LV6SjXs,5507
@@ -65,6 +70,7 @@ tests/unit/test_jobs_unit.py,sha256=kCrm2FdogqYgji0Coe9KGaODYEsXmvuV46FN2mUE1Ts,
65
70
  tests/unit/test_models_unit.py,sha256=wgwdvJLt6QZ_IKCvp6Kmt2Z4b_CvIN8KCuFqlBaxDe8,15064
66
71
  tests/unit/test_projects_unit.py,sha256=_SwPFhy2Xl6HRt6w5_HYrqtZJHAzFzoCZ3kqAS1Zn3c,9530
67
72
  tests/unit/test_proximl.py,sha256=E-er5V1O-4ZVfTO2R-2wGsKN80q0_BVG5ho9Ab9lnE4,1701
73
+ tests/unit/test_volumes_unit.py,sha256=YcyrGPCq7XfAtCdKdp44723o7mLGIu5_hKOdhAFVYV4,15305
68
74
  tests/unit/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
75
  tests/unit/cli/conftest.py,sha256=w6p_2URicywJKUCtY79tSD_mx8cwJtxHbK_Lu3grOYs,236
70
76
  tests/unit/cli/test_cli_checkpoint_unit.py,sha256=Z4v80C2gqzRXdHons3_82lNC_VqL_YOt53HrUQnzReI,702
@@ -74,6 +80,7 @@ tests/unit/cli/test_cli_gpu_unit.py,sha256=xdwIZEZJcJlWSuLBEcLhZXXH9EogZoKRiJlMR
74
80
  tests/unit/cli/test_cli_job_unit.py,sha256=UioSx_ZRY0qh4AJf90rIepputVUPBZ0KSqNR_u592UY,611
75
81
  tests/unit/cli/test_cli_model_unit.py,sha256=AucngxvYjW6GidDGBPHnKyYOb82ff7xMX5mVVUcbrCA,629
76
82
  tests/unit/cli/test_cli_project_unit.py,sha256=ms9gJ8pgMNGeIMdFcvBcwSPmb0i2qo9-rk9CCF53-9M,1756
83
+ tests/unit/cli/test_cli_volume_unit.py,sha256=VeYb9PHuD45E23JCybF-C7ZaHsuERw7me2OUmYnmAAg,644
77
84
  tests/unit/cli/cloudbender/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
85
  tests/unit/cli/cloudbender/test_cli_datastore_unit.py,sha256=sUZWnzzCCG7NdgzEHsQ2zHpEb-ZD6FDIazca6FqMOc0,1381
79
86
  tests/unit/cli/cloudbender/test_cli_device_unit.py,sha256=o1vrPlbaanYK1iJG5pE6tDwgmOXDuLUY0VH8DxtaPYI,1342
@@ -89,9 +96,10 @@ tests/unit/cloudbender/test_nodes_unit.py,sha256=ehOHkNroiLKNTR09SbnBPpwELE72GcG
89
96
  tests/unit/cloudbender/test_providers_unit.py,sha256=y63VCqHXb4Yu8sh0kW30-ojRvv9aUa5j1jNkmb46KTc,4373
90
97
  tests/unit/cloudbender/test_regions_unit.py,sha256=9bvP268gpNyygjh1IEpSSiUt2aP6okv7QOsV1XoaIS0,6299
91
98
  tests/unit/cloudbender/test_reservations_unit.py,sha256=ICuFT5sexnLvS7taoC18yQYuDZHpBRrNuCj3Uq_Arwo,5624
92
- proximl-0.5.4.dist-info/LICENSE,sha256=ADFxLEZDxKY0j4MdyUd5GNuhQ18rnWH5rOz1ZG7yiOA,1069
93
- proximl-0.5.4.dist-info/METADATA,sha256=z0_DE7Fbt70q0F1oEKF-br_S5ZqiUCL9j2Ieo-tJZgs,7344
94
- proximl-0.5.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
95
- proximl-0.5.4.dist-info/entry_points.txt,sha256=HmI311IIabkZReMCXu-nGbvIEW-KfaduAOyfiSqt5SY,63
96
- proximl-0.5.4.dist-info/top_level.txt,sha256=-TWqc9tAaxmWmW4c7uYsmzPEYUIoh6z02xxqPbv7Kys,23
97
- proximl-0.5.4.dist-info/RECORD,,
99
+ tests/unit/cloudbender/test_services_unit.py,sha256=iYaQpyCXDg77GQEIhmgiVwKX83jyvIf-4-4oya5WA_o,5043
100
+ proximl-0.5.6.dist-info/LICENSE,sha256=ADFxLEZDxKY0j4MdyUd5GNuhQ18rnWH5rOz1ZG7yiOA,1069
101
+ proximl-0.5.6.dist-info/METADATA,sha256=wS2y66puGjq7ZkG2GsyFIJWCiSjbDiA5uUdA8PzlIqw,7344
102
+ proximl-0.5.6.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
103
+ proximl-0.5.6.dist-info/entry_points.txt,sha256=HmI311IIabkZReMCXu-nGbvIEW-KfaduAOyfiSqt5SY,63
104
+ proximl-0.5.6.dist-info/top_level.txt,sha256=-TWqc9tAaxmWmW4c7uYsmzPEYUIoh6z02xxqPbv7Kys,23
105
+ proximl-0.5.6.dist-info/RECORD,,
@@ -54,18 +54,20 @@ class GetCheckpointTests:
54
54
 
55
55
  @mark.create
56
56
  @mark.asyncio
57
- async def test_checkpoint_aws(proximl, capsys):
57
+ async def test_checkpoint_wasabi(proximl, capsys):
58
58
  checkpoint = await proximl.checkpoints.create(
59
- name="CLI Automated AWS",
60
- source_type="aws",
61
- source_uri="s3://proximl-examples/models/mxnet-model.zip",
59
+ name="CLI Automated Wasabi",
60
+ source_type="wasabi",
61
+ source_uri="s3://proximl-example/models/proximl-examples",
62
+ capacity="10G",
63
+ source_options=dict(endpoint_url="https://s3.wasabisys.com"),
62
64
  )
63
65
  checkpoint = await checkpoint.wait_for("ready", 300)
64
66
  status = checkpoint.status
65
67
  size = checkpoint.size
66
68
  await checkpoint.remove()
67
69
  assert status == "ready"
68
- assert size >= 1000000
70
+ assert size >= 500000
69
71
 
70
72
 
71
73
  @mark.create
@@ -13,8 +13,9 @@ class GetDatasetTests:
13
13
  async def dataset(self, proximl):
14
14
  dataset = await proximl.datasets.create(
15
15
  name="CLI Automated",
16
- source_type="aws",
17
- source_uri="s3://proximl-examples/data/cifar10",
16
+ source_type="wasabi",
17
+ source_uri="s3://proximl-example/input/cifar-10/cifar-10-batches-bin",
18
+ source_options=dict(endpoint_url="https://s3.wasabisys.com"),
18
19
  )
19
20
  dataset = await dataset.wait_for("ready", 300)
20
21
  yield dataset
@@ -48,9 +49,7 @@ class GetDatasetTests:
48
49
  async def test_dataset_repr(self, dataset):
49
50
  string = repr(dataset)
50
51
  regex = (
51
- r"^Dataset\( proximl , \*\*{.*'dataset_uuid': '"
52
- + dataset.id
53
- + r"'.*}\)$"
52
+ r"^Dataset\( proximl , \*\*{.*'dataset_uuid': '" + dataset.id + r"'.*}\)$"
54
53
  )
55
54
  assert isinstance(string, str)
56
55
  assert re.match(regex, string)