podstack 1.3.1__tar.gz → 1.3.3__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.
Files changed (32) hide show
  1. {podstack-1.3.1 → podstack-1.3.3}/PKG-INFO +1 -1
  2. {podstack-1.3.1 → podstack-1.3.3}/podstack/__init__.py +3 -1
  3. {podstack-1.3.1 → podstack-1.3.3}/podstack/annotations.py +15 -11
  4. {podstack-1.3.1 → podstack-1.3.3}/podstack/gpu_runner.py +39 -9
  5. {podstack-1.3.1 → podstack-1.3.3}/podstack.egg-info/PKG-INFO +1 -1
  6. {podstack-1.3.1 → podstack-1.3.3}/pyproject.toml +1 -1
  7. {podstack-1.3.1 → podstack-1.3.3}/LICENSE +0 -0
  8. {podstack-1.3.1 → podstack-1.3.3}/README.md +0 -0
  9. {podstack-1.3.1 → podstack-1.3.3}/podstack/client.py +0 -0
  10. {podstack-1.3.1 → podstack-1.3.3}/podstack/exceptions.py +0 -0
  11. {podstack-1.3.1 → podstack-1.3.3}/podstack/execution.py +0 -0
  12. {podstack-1.3.1 → podstack-1.3.3}/podstack/models.py +0 -0
  13. {podstack-1.3.1 → podstack-1.3.3}/podstack/notebook.py +0 -0
  14. {podstack-1.3.1 → podstack-1.3.3}/podstack/registry/__init__.py +0 -0
  15. {podstack-1.3.1 → podstack-1.3.3}/podstack/registry/client.py +0 -0
  16. {podstack-1.3.1 → podstack-1.3.3}/podstack/registry/exceptions.py +0 -0
  17. {podstack-1.3.1 → podstack-1.3.3}/podstack/registry/experiment.py +0 -0
  18. {podstack-1.3.1 → podstack-1.3.3}/podstack/registry/model.py +0 -0
  19. {podstack-1.3.1 → podstack-1.3.3}/podstack/registry/model_utils.py +0 -0
  20. {podstack-1.3.1 → podstack-1.3.3}/podstack.egg-info/SOURCES.txt +0 -0
  21. {podstack-1.3.1 → podstack-1.3.3}/podstack.egg-info/dependency_links.txt +0 -0
  22. {podstack-1.3.1 → podstack-1.3.3}/podstack.egg-info/requires.txt +0 -0
  23. {podstack-1.3.1 → podstack-1.3.3}/podstack.egg-info/top_level.txt +0 -0
  24. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/__init__.py +0 -0
  25. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/app.py +0 -0
  26. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/exceptions.py +0 -0
  27. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/image.py +0 -0
  28. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/runner.py +0 -0
  29. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/secret.py +0 -0
  30. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/utils.py +0 -0
  31. {podstack-1.3.1 → podstack-1.3.3}/podstack_gpu/volume.py +0 -0
  32. {podstack-1.3.1 → podstack-1.3.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: podstack
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Official Python SDK for Podstack GPU Notebook Platform
5
5
  Author-email: Podstack <support@podstack.ai>
6
6
  License-Expression: MIT
@@ -54,7 +54,7 @@ Decorators:
54
54
  ...
55
55
  """
56
56
 
57
- __version__ = "1.3.1"
57
+ __version__ = "1.3.2"
58
58
 
59
59
  from .client import Client
60
60
  from .notebook import Notebook, NotebookStatus
@@ -83,6 +83,7 @@ from . import gpu_runner
83
83
  from .gpu_runner import (
84
84
  GPURunner,
85
85
  GPUExecutionResult,
86
+ RunnerList,
86
87
  run as run_on_gpu,
87
88
  list_runners,
88
89
  )
@@ -209,6 +210,7 @@ __all__ = [
209
210
  "gpu_runner",
210
211
  "GPURunner",
211
212
  "GPUExecutionResult",
213
+ "RunnerList",
212
214
  "run_on_gpu",
213
215
  "list_runners",
214
216
  # Annotations
@@ -142,6 +142,12 @@ class GPUConfig:
142
142
 
143
143
  def __call__(self, func: Callable) -> Callable:
144
144
  """Decorator usage - executes function on remote GPU."""
145
+ # Capture runner config at decoration time so it survives across
146
+ # multiple calls (the global is cleared after the first call).
147
+ global _current_runner_config
148
+ _captured_runner_config = _current_runner_config
149
+ _current_runner_config = None # clear here, not inside wrapper
150
+
145
151
  @functools.wraps(func)
146
152
  def wrapper(*args, **kwargs):
147
153
  if not self.remote:
@@ -213,22 +219,20 @@ if __podstack_result__ is not None:
213
219
  print(repr(__podstack_result__))
214
220
  """
215
221
 
216
- # Check for active runner config from @podstack.runner() decorator
217
- global _current_runner_config
222
+ # Use the runner config captured at decoration time
218
223
  runner_name = None
219
224
  effective_pip = self.pip
220
225
  effective_uv = self.uv
221
226
  effective_conda = self.conda
222
- if _current_runner_config is not None:
223
- runner_name = _current_runner_config.get("image")
227
+ if _captured_runner_config is not None:
228
+ runner_name = _captured_runner_config.get("image")
224
229
  # Merge package lists from runner config
225
- if _current_runner_config.get("pip") and not effective_pip:
226
- effective_pip = _current_runner_config["pip"]
227
- if _current_runner_config.get("uv") and not effective_uv:
228
- effective_uv = _current_runner_config["uv"]
229
- if _current_runner_config.get("conda") and not effective_conda:
230
- effective_conda = _current_runner_config["conda"]
231
- _current_runner_config = None # Clear after use
230
+ if _captured_runner_config.get("pip") and not effective_pip:
231
+ effective_pip = _captured_runner_config["pip"]
232
+ if _captured_runner_config.get("uv") and not effective_uv:
233
+ effective_uv = _captured_runner_config["uv"]
234
+ if _captured_runner_config.get("conda") and not effective_conda:
235
+ effective_conda = _captured_runner_config["conda"]
232
236
 
233
237
  # Execute on remote GPU with improved error handling
234
238
  # Auto-enable streaming in Jupyter notebooks for real-time output
@@ -35,6 +35,33 @@ def is_jupyter() -> bool:
35
35
  return False
36
36
 
37
37
 
38
+ class RunnerList(list):
39
+ """A list of runners with a .show() method for tabular display."""
40
+
41
+ def show(self):
42
+ """Print runners in a formatted table with S.NO."""
43
+ if not self:
44
+ print("No runners available.")
45
+ return
46
+
47
+ # Column widths
48
+ no_w = 5
49
+ name_w = 45
50
+ type_w = 6
51
+ desc_w = 50
52
+
53
+ header = f"{'S.NO':<{no_w}} {'Name':<{name_w}} {'Type':<{type_w}} {'Description'}"
54
+ print(header)
55
+ print("-" * (no_w + name_w + type_w + desc_w + 3))
56
+ for i, r in enumerate(self, 1):
57
+ name = r.get("name", "")
58
+ rtype = r.get("type", "")
59
+ desc = r.get("description", "")
60
+ if len(desc) > desc_w:
61
+ desc = desc[:desc_w - 3] + "..."
62
+ print(f"{i:<{no_w}} {name:<{name_w}} {rtype:<{type_w}} {desc}")
63
+
64
+
38
65
  class OutputStreamer:
39
66
  """Handles real-time output streaming from GPU executions."""
40
67
 
@@ -184,7 +211,7 @@ class GPUExecutionResult:
184
211
  output=data.get("output", ""),
185
212
  error=data.get("error"),
186
213
  gpu_seconds=data.get("gpu_seconds", 0.0),
187
- cost_paise=data.get("actual_cost_paise", 0),
214
+ cost_paise=data.get("cost_cents", data.get("cost_paise", data.get("actual_cost_paise", 0))),
188
215
  gpu_type=data.get("gpu_type", ""),
189
216
  gpu_count=data.get("gpu_count", 1),
190
217
  success=data.get("status") == "completed"
@@ -978,12 +1005,16 @@ _stream_install(
978
1005
  # Fallback: use the same base URL
979
1006
  return self.api_url
980
1007
 
981
- def list_runners(self) -> list:
1008
+ def list_runners(self) -> RunnerList:
982
1009
  """
983
1010
  List available GPU/CPU runners.
984
1011
 
985
1012
  Returns:
986
- List of runner dictionaries with name, type, description, image, libraries, scenarios.
1013
+ RunnerList of runner dictionaries. Call .show() for tabular display.
1014
+
1015
+ Example:
1016
+ podstack.list_runners().show() # Print table with S.NO
1017
+ runners = podstack.list_runners() # Just fetch list
987
1018
  """
988
1019
  platform_url = self._get_platform_url()
989
1020
  url = f"{platform_url}/api/v1/runners"
@@ -1004,7 +1035,7 @@ _stream_install(
1004
1035
  raise RuntimeError(f"Failed to list runners: {error_msg}")
1005
1036
 
1006
1037
  try:
1007
- return response.json()
1038
+ return RunnerList(response.json())
1008
1039
  except Exception:
1009
1040
  raise RuntimeError(f"Invalid JSON response: {response.text[:200]}")
1010
1041
 
@@ -1181,17 +1212,16 @@ def run(
1181
1212
  )
1182
1213
 
1183
1214
 
1184
- def list_runners() -> list:
1215
+ def list_runners() -> RunnerList:
1185
1216
  """
1186
1217
  List available GPU/CPU runners.
1187
1218
 
1188
1219
  Returns:
1189
- List of runner dictionaries with name, type, description, image, libraries, scenarios.
1220
+ RunnerList of runner dicts. Call .show() for tabular display.
1190
1221
 
1191
1222
  Example:
1192
- runners = podstack.gpu_runner.list_runners()
1193
- for r in runners:
1194
- print(f"{r['name']} ({r['type']}): {r['description']}")
1223
+ podstack.list_runners().show() # Print table with S.NO
1224
+ runners = podstack.list_runners() # Just fetch list
1195
1225
  """
1196
1226
  return get_runner().list_runners()
1197
1227
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: podstack
3
- Version: 1.3.1
3
+ Version: 1.3.3
4
4
  Summary: Official Python SDK for Podstack GPU Notebook Platform
5
5
  Author-email: Podstack <support@podstack.ai>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "podstack"
7
- version = "1.3.1"
7
+ version = "1.3.3"
8
8
  description = "Official Python SDK for Podstack GPU Notebook Platform"
9
9
  readme = "README.md"
10
10
  license = "MIT"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes