clouditia-manager 1.2.2__tar.gz → 1.3.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clouditia-manager
3
- Version: 1.2.2
3
+ Version: 1.3.2
4
4
  Summary: Manage GPU sessions on Clouditia platform
5
5
  Home-page: https://clouditia.com
6
6
  Author: Aina KIKI-SAGBE
@@ -191,7 +191,47 @@ print(f"GPU Count: {session.gpu_count}") # 2
191
191
  print(f"GPUs: {session.gpus}") # Liste des configs GPU
192
192
  ```
193
193
 
194
- ### 4. Lister les sessions
194
+ ### 4. Gestion de la disponibilité GPU (allow_partial)
195
+
196
+ Le SDK vérifie automatiquement la disponibilité des GPUs demandés avant de créer la session.
197
+
198
+ ```python
199
+ # Si certains GPUs ne sont pas disponibles, le SDK affiche:
200
+ # ==================================================
201
+ # GPU AVAILABILITY CHECK
202
+ # ==================================================
203
+ # Unavailable GPUs:
204
+ # - nvidia-rtx-4090
205
+ # Available GPUs:
206
+ # - nvidia-rtx-3090
207
+ # ==================================================
208
+ # Continue with 1 available GPU(s)? [y/N]:
209
+
210
+ # Mode interactif (par défaut): demande confirmation
211
+ session = manager.create_session(
212
+ gpus=[
213
+ {'type': 'nvidia-rtx-3090', 'count': 1},
214
+ {'type': 'nvidia-rtx-4090', 'count': 1}
215
+ ],
216
+ vcpu=4,
217
+ ram=16,
218
+ storage=20
219
+ )
220
+
221
+ # Mode automatique: continue avec les GPUs disponibles
222
+ session = manager.create_session(
223
+ gpus=[
224
+ {'type': 'nvidia-rtx-3090', 'count': 1},
225
+ {'type': 'nvidia-rtx-4090', 'count': 1}
226
+ ],
227
+ vcpu=4,
228
+ ram=16,
229
+ storage=20,
230
+ allow_partial=True # Continue avec les GPUs disponibles uniquement
231
+ )
232
+ ```
233
+
234
+ ### 5. Lister les sessions
195
235
 
196
236
  ```python
197
237
  # Toutes les sessions
@@ -264,14 +304,17 @@ session = manager.stop_session(
264
304
  session = manager.stop_session("0e4c713a", wait_stopped=False, verbose=False)
265
305
  ```
266
306
 
267
- ### 8. Consulter l'inventaire GPU
307
+ ### 8. Consulter les GPUs disponibles
268
308
 
269
309
  ```python
270
310
  inventory = manager.get_inventory()
271
311
 
272
- for gpu in inventory:
273
- print(f"{gpu.gpu_name}: {gpu.available}/{gpu.total} disponibles")
274
- print(f" Prix: {gpu.price_per_hour}EUR/h")
312
+ if not inventory:
313
+ print("Aucun GPU disponible actuellement")
314
+ else:
315
+ for gpu in inventory:
316
+ print(f"{gpu.gpu_name}: {gpu.available} disponible(s)")
317
+ print(f" Prix: {gpu.price_per_hour}EUR/h")
275
318
  ```
276
319
 
277
320
  ### 9. Générer une clé SDK (sk_live_)
@@ -356,9 +399,7 @@ except APIError as e:
356
399
  |----------|------|-------------|
357
400
  | `gpu_type` | str | Slug du GPU |
358
401
  | `gpu_name` | str | Nom complet du GPU |
359
- | `total` | int | Stock total |
360
- | `available` | int | Stock disponible |
361
- | `in_use` | int | Stock en utilisation |
402
+ | `available` | int | Nombre de GPUs disponibles |
362
403
  | `price_per_hour` | float | Prix par heure (EUR) |
363
404
 
364
405
  ## License
@@ -149,7 +149,47 @@ print(f"GPU Count: {session.gpu_count}") # 2
149
149
  print(f"GPUs: {session.gpus}") # Liste des configs GPU
150
150
  ```
151
151
 
152
- ### 4. Lister les sessions
152
+ ### 4. Gestion de la disponibilité GPU (allow_partial)
153
+
154
+ Le SDK vérifie automatiquement la disponibilité des GPUs demandés avant de créer la session.
155
+
156
+ ```python
157
+ # Si certains GPUs ne sont pas disponibles, le SDK affiche:
158
+ # ==================================================
159
+ # GPU AVAILABILITY CHECK
160
+ # ==================================================
161
+ # Unavailable GPUs:
162
+ # - nvidia-rtx-4090
163
+ # Available GPUs:
164
+ # - nvidia-rtx-3090
165
+ # ==================================================
166
+ # Continue with 1 available GPU(s)? [y/N]:
167
+
168
+ # Mode interactif (par défaut): demande confirmation
169
+ session = manager.create_session(
170
+ gpus=[
171
+ {'type': 'nvidia-rtx-3090', 'count': 1},
172
+ {'type': 'nvidia-rtx-4090', 'count': 1}
173
+ ],
174
+ vcpu=4,
175
+ ram=16,
176
+ storage=20
177
+ )
178
+
179
+ # Mode automatique: continue avec les GPUs disponibles
180
+ session = manager.create_session(
181
+ gpus=[
182
+ {'type': 'nvidia-rtx-3090', 'count': 1},
183
+ {'type': 'nvidia-rtx-4090', 'count': 1}
184
+ ],
185
+ vcpu=4,
186
+ ram=16,
187
+ storage=20,
188
+ allow_partial=True # Continue avec les GPUs disponibles uniquement
189
+ )
190
+ ```
191
+
192
+ ### 5. Lister les sessions
153
193
 
154
194
  ```python
155
195
  # Toutes les sessions
@@ -222,14 +262,17 @@ session = manager.stop_session(
222
262
  session = manager.stop_session("0e4c713a", wait_stopped=False, verbose=False)
223
263
  ```
224
264
 
225
- ### 8. Consulter l'inventaire GPU
265
+ ### 8. Consulter les GPUs disponibles
226
266
 
227
267
  ```python
228
268
  inventory = manager.get_inventory()
229
269
 
230
- for gpu in inventory:
231
- print(f"{gpu.gpu_name}: {gpu.available}/{gpu.total} disponibles")
232
- print(f" Prix: {gpu.price_per_hour}EUR/h")
270
+ if not inventory:
271
+ print("Aucun GPU disponible actuellement")
272
+ else:
273
+ for gpu in inventory:
274
+ print(f"{gpu.gpu_name}: {gpu.available} disponible(s)")
275
+ print(f" Prix: {gpu.price_per_hour}EUR/h")
233
276
  ```
234
277
 
235
278
  ### 9. Générer une clé SDK (sk_live_)
@@ -314,9 +357,7 @@ except APIError as e:
314
357
  |----------|------|-------------|
315
358
  | `gpu_type` | str | Slug du GPU |
316
359
  | `gpu_name` | str | Nom complet du GPU |
317
- | `total` | int | Stock total |
318
- | `available` | int | Stock disponible |
319
- | `in_use` | int | Stock en utilisation |
360
+ | `available` | int | Nombre de GPUs disponibles |
320
361
  | `price_per_hour` | float | Prix par heure (EUR) |
321
362
 
322
363
  ## License
@@ -46,16 +46,14 @@ class GPUSession:
46
46
 
47
47
  @dataclass
48
48
  class GPUInventory:
49
- """Represents GPU inventory in marketplace"""
49
+ """Represents available GPU in marketplace"""
50
50
  gpu_type: str
51
51
  gpu_name: str
52
- total: int
53
52
  available: int
54
- in_use: int
55
53
  price_per_hour: float
56
54
 
57
55
  def __repr__(self):
58
- return f"GPUInventory(type='{self.gpu_type}', available={self.available}/{self.total})"
56
+ return f"GPUInventory(type='{self.gpu_type}', available={self.available})"
59
57
 
60
58
 
61
59
  class GPUManager:
@@ -129,6 +127,12 @@ class GPUManager:
129
127
  raise AuthenticationError("Access denied")
130
128
  elif response.status_code == 404:
131
129
  raise SessionNotFoundError("Resource not found")
130
+ elif response.status_code == 400:
131
+ # Return JSON response for 400 errors (may contain availability info)
132
+ try:
133
+ return response.json()
134
+ except:
135
+ raise APIError(f"Bad request: {response.text}")
132
136
 
133
137
  response.raise_for_status()
134
138
  return response.json()
@@ -148,7 +152,8 @@ class GPUManager:
148
152
  storage: int = 20,
149
153
  wait_ready: bool = True,
150
154
  timeout: int = 180,
151
- verbose: bool = True
155
+ verbose: bool = True,
156
+ allow_partial: bool = False
152
157
  ) -> GPUSession:
153
158
  """
154
159
  Create a new GPU session.
@@ -165,6 +170,8 @@ class GPUManager:
165
170
  wait_ready: Wait for session to be fully ready (default: True)
166
171
  timeout: Max wait time in seconds (default: 180)
167
172
  verbose: Print status messages (default: True)
173
+ allow_partial: If True, create session with only available GPUs
174
+ when some requested GPUs are unavailable (default: False)
168
175
 
169
176
  Returns:
170
177
  GPUSession object with session details
@@ -177,7 +184,8 @@ class GPUManager:
177
184
  data = {
178
185
  "vcpu": vcpu,
179
186
  "ram": ram,
180
- "storage": storage
187
+ "storage": storage,
188
+ "allow_partial": allow_partial
181
189
  }
182
190
 
183
191
  # Support both single GPU and multiple GPUs
@@ -192,11 +200,67 @@ class GPUManager:
192
200
 
193
201
  if verbose:
194
202
  print(f"Creating GPU session with {gpu_desc}...")
203
+ print(f"Checking GPU availability...")
195
204
 
196
205
  response = self._request("POST", "/api/computing/sessions/create/", data=data)
197
206
 
207
+ # Handle partial availability response
198
208
  if not response.get("success"):
199
209
  error = response.get("error", "Unknown error")
210
+ unavailable = response.get("unavailable_gpus", [])
211
+ available = response.get("available_gpus", [])
212
+
213
+ # Check if this is a partial availability situation
214
+ if unavailable and available:
215
+ if verbose:
216
+ print(f"\n{'='*50}")
217
+ print(f" GPU AVAILABILITY CHECK")
218
+ print(f"{'='*50}")
219
+ print(f" Unavailable GPUs:")
220
+ for gpu in unavailable:
221
+ print(f" - {gpu}")
222
+ print(f" Available GPUs:")
223
+ for gpu in available:
224
+ print(f" - {gpu}")
225
+ print(f"{'='*50}")
226
+
227
+ # Ask user if they want to continue with available GPUs
228
+ try:
229
+ user_input = input(f"\nContinue with {len(available)} available GPU(s)? [y/N]: ").strip().lower()
230
+ if user_input in ['y', 'yes', 'o', 'oui']:
231
+ # Retry with allow_partial=True
232
+ data["allow_partial"] = True
233
+ if verbose:
234
+ print(f"\nCreating session with available GPUs only...")
235
+ response = self._request("POST", "/api/computing/sessions/create/", data=data)
236
+
237
+ if not response.get("success"):
238
+ raise APIError(response.get("error", "Failed to create session"))
239
+ else:
240
+ raise InsufficientResourcesError(
241
+ f"GPUs indisponibles: {', '.join(unavailable)}"
242
+ )
243
+ except EOFError:
244
+ # Non-interactive mode, raise error
245
+ raise InsufficientResourcesError(
246
+ f"GPUs indisponibles: {', '.join(unavailable)}. "
247
+ f"Utilisez allow_partial=True pour continuer avec: {', '.join(available)}"
248
+ )
249
+ else:
250
+ # Not verbose, just raise error with info
251
+ raise InsufficientResourcesError(
252
+ f"GPUs indisponibles: {', '.join(unavailable)}. "
253
+ f"GPUs disponibles: {', '.join(available)}. "
254
+ f"Utilisez allow_partial=True pour continuer."
255
+ )
256
+
257
+ # No GPUs available at all
258
+ elif unavailable and not available:
259
+ raise InsufficientResourcesError(
260
+ f"Aucun GPU disponible. Indisponibles: {', '.join(unavailable)}"
261
+ )
262
+
263
+ # Other error
200
264
  if "disponible" in error.lower() or "available" in error.lower():
201
265
  raise InsufficientResourcesError(error)
202
266
  raise APIError(error)
@@ -464,7 +528,8 @@ class GPUManager:
464
528
  Get available GPU inventory.
465
529
 
466
530
  Returns:
467
- List of GPUInventory objects
531
+ List of GPUInventory objects (only GPUs with available stock)
532
+ Empty list if no GPUs are available
468
533
  """
469
534
  response = self._request("GET", "/api/computing/inventory/")
470
535
 
@@ -473,9 +538,7 @@ class GPUManager:
473
538
  inventory.append(GPUInventory(
474
539
  gpu_type=item.get("gpu_type", ""),
475
540
  gpu_name=item.get("gpu_name", ""),
476
- total=item.get("total", 0),
477
541
  available=item.get("available", 0),
478
- in_use=item.get("in_use", 0),
479
542
  price_per_hour=item.get("price_per_hour", 0.0)
480
543
  ))
481
544
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clouditia-manager
3
- Version: 1.2.2
3
+ Version: 1.3.2
4
4
  Summary: Manage GPU sessions on Clouditia platform
5
5
  Home-page: https://clouditia.com
6
6
  Author: Aina KIKI-SAGBE
@@ -191,7 +191,47 @@ print(f"GPU Count: {session.gpu_count}") # 2
191
191
  print(f"GPUs: {session.gpus}") # Liste des configs GPU
192
192
  ```
193
193
 
194
- ### 4. Lister les sessions
194
+ ### 4. Gestion de la disponibilité GPU (allow_partial)
195
+
196
+ Le SDK vérifie automatiquement la disponibilité des GPUs demandés avant de créer la session.
197
+
198
+ ```python
199
+ # Si certains GPUs ne sont pas disponibles, le SDK affiche:
200
+ # ==================================================
201
+ # GPU AVAILABILITY CHECK
202
+ # ==================================================
203
+ # Unavailable GPUs:
204
+ # - nvidia-rtx-4090
205
+ # Available GPUs:
206
+ # - nvidia-rtx-3090
207
+ # ==================================================
208
+ # Continue with 1 available GPU(s)? [y/N]:
209
+
210
+ # Mode interactif (par défaut): demande confirmation
211
+ session = manager.create_session(
212
+ gpus=[
213
+ {'type': 'nvidia-rtx-3090', 'count': 1},
214
+ {'type': 'nvidia-rtx-4090', 'count': 1}
215
+ ],
216
+ vcpu=4,
217
+ ram=16,
218
+ storage=20
219
+ )
220
+
221
+ # Mode automatique: continue avec les GPUs disponibles
222
+ session = manager.create_session(
223
+ gpus=[
224
+ {'type': 'nvidia-rtx-3090', 'count': 1},
225
+ {'type': 'nvidia-rtx-4090', 'count': 1}
226
+ ],
227
+ vcpu=4,
228
+ ram=16,
229
+ storage=20,
230
+ allow_partial=True # Continue avec les GPUs disponibles uniquement
231
+ )
232
+ ```
233
+
234
+ ### 5. Lister les sessions
195
235
 
196
236
  ```python
197
237
  # Toutes les sessions
@@ -264,14 +304,17 @@ session = manager.stop_session(
264
304
  session = manager.stop_session("0e4c713a", wait_stopped=False, verbose=False)
265
305
  ```
266
306
 
267
- ### 8. Consulter l'inventaire GPU
307
+ ### 8. Consulter les GPUs disponibles
268
308
 
269
309
  ```python
270
310
  inventory = manager.get_inventory()
271
311
 
272
- for gpu in inventory:
273
- print(f"{gpu.gpu_name}: {gpu.available}/{gpu.total} disponibles")
274
- print(f" Prix: {gpu.price_per_hour}EUR/h")
312
+ if not inventory:
313
+ print("Aucun GPU disponible actuellement")
314
+ else:
315
+ for gpu in inventory:
316
+ print(f"{gpu.gpu_name}: {gpu.available} disponible(s)")
317
+ print(f" Prix: {gpu.price_per_hour}EUR/h")
275
318
  ```
276
319
 
277
320
  ### 9. Générer une clé SDK (sk_live_)
@@ -356,9 +399,7 @@ except APIError as e:
356
399
  |----------|------|-------------|
357
400
  | `gpu_type` | str | Slug du GPU |
358
401
  | `gpu_name` | str | Nom complet du GPU |
359
- | `total` | int | Stock total |
360
- | `available` | int | Stock disponible |
361
- | `in_use` | int | Stock en utilisation |
402
+ | `available` | int | Nombre de GPUs disponibles |
362
403
  | `price_per_hour` | float | Prix par heure (EUR) |
363
404
 
364
405
  ## License
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="clouditia-manager",
8
- version="1.2.2",
8
+ version="1.3.2",
9
9
  author="Aina KIKI-SAGBE",
10
10
  author_email="support@clouditia.com",
11
11
  maintainer="Aina KIKI-SAGBE",