runcloud-sdk 0.8.3__tar.gz → 0.9.0__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 (20) hide show
  1. {runcloud_sdk-0.8.3/runcloud_sdk.egg-info → runcloud_sdk-0.9.0}/PKG-INFO +16 -1
  2. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/README.md +15 -0
  3. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/pyproject.toml +1 -1
  4. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/client.py +26 -2
  5. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0/runcloud_sdk.egg-info}/PKG-INFO +16 -1
  6. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/tests/test_sdk.py +29 -0
  7. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/LICENSE +0 -0
  8. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/__init__.py +0 -0
  9. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/compat/__init__.py +0 -0
  10. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/compat/blaxel.py +0 -0
  11. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/compat/daytona.py +0 -0
  12. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/compat/e2b.py +0 -0
  13. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/compat/modal.py +0 -0
  14. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/compat/sprites.py +0 -0
  15. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud/compat/vercel.py +0 -0
  16. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud_sdk.egg-info/SOURCES.txt +0 -0
  17. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud_sdk.egg-info/dependency_links.txt +0 -0
  18. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud_sdk.egg-info/requires.txt +0 -0
  19. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/runcloud_sdk.egg-info/top_level.txt +0 -0
  20. {runcloud_sdk-0.8.3 → runcloud_sdk-0.9.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runcloud-sdk
3
- Version: 0.8.3
3
+ Version: 0.9.0
4
4
  Summary: Python SDK for run.cloud, including sandbox-provider compatibility adapters
5
5
  Author: Newly
6
6
  License-Expression: Apache-2.0
@@ -62,6 +62,21 @@ finally:
62
62
  automation, set `RUN_CLOUD_API_KEY` and optionally `RUN_CLOUD_API_URL`, or pass
63
63
  `api_key` and `api_url` directly.
64
64
 
65
+ A sandbox's name is a label you own: set it at create, change it later, and
66
+ filter on it. Naming plus `resume` is how the same sandbox goes back to the same
67
+ piece of work instead of booting a new one:
68
+
69
+ ```python
70
+ matches = cloud.list(name=f"project-{project_id}")
71
+ box = matches[0].resume() if matches else cloud.create(name=f"project-{project_id}")
72
+
73
+ box.rename(f"project-{project_id}-v2")
74
+ box.rename("") # clears the label
75
+ ```
76
+
77
+ Names are not unique and mean nothing to the platform, so check `state` on a
78
+ match before using it. Renaming works in any state but `destroyed`.
79
+
65
80
  ## Compatibility adapters
66
81
 
67
82
  The same distribution includes migration adapters:
@@ -44,6 +44,21 @@ finally:
44
44
  automation, set `RUN_CLOUD_API_KEY` and optionally `RUN_CLOUD_API_URL`, or pass
45
45
  `api_key` and `api_url` directly.
46
46
 
47
+ A sandbox's name is a label you own: set it at create, change it later, and
48
+ filter on it. Naming plus `resume` is how the same sandbox goes back to the same
49
+ piece of work instead of booting a new one:
50
+
51
+ ```python
52
+ matches = cloud.list(name=f"project-{project_id}")
53
+ box = matches[0].resume() if matches else cloud.create(name=f"project-{project_id}")
54
+
55
+ box.rename(f"project-{project_id}-v2")
56
+ box.rename("") # clears the label
57
+ ```
58
+
59
+ Names are not unique and mean nothing to the platform, so check `state` on a
60
+ match before using it. Renaming works in any state but `destroyed`.
61
+
47
62
  ## Compatibility adapters
48
63
 
49
64
  The same distribution includes migration adapters:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "runcloud-sdk"
3
- version = "0.8.3"
3
+ version = "0.9.0"
4
4
  description = "Python SDK for run.cloud, including sandbox-provider compatibility adapters"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"
@@ -372,8 +372,17 @@ class Client:
372
372
  sid = urllib.parse.quote(sandbox_id, safe="")
373
373
  return Sandbox(self, self.request("GET", f"/run-cloud/sandboxes/{sid}"))
374
374
 
375
- def list(self, state: Optional[str] = None) -> list["Sandbox"]:
376
- query = f"?state={urllib.parse.quote(state, safe='')}" if state else ""
375
+ def list(
376
+ self, state: Optional[str] = None, name: Optional[str] = None
377
+ ) -> list["Sandbox"]:
378
+ # Both filters are applied server-side, so finding a sandbox by the name
379
+ # you gave it does not mean paging the whole fleet and matching locally.
380
+ filters = [
381
+ (key, value)
382
+ for key, value in (("state", state), ("name", name))
383
+ if value
384
+ ]
385
+ query = "?" + urllib.parse.urlencode(filters) if filters else ""
377
386
  payload = self.request("GET", "/run-cloud/sandboxes" + query) or {}
378
387
  return [Sandbox(self, item) for item in payload.get("items", [])]
379
388
 
@@ -548,6 +557,21 @@ class Sandbox:
548
557
  )
549
558
  return self
550
559
 
560
+ def rename(self, name: str) -> "Sandbox":
561
+ """Relabel the sandbox.
562
+
563
+ The name is a label you own and the filter ``list(name=...)`` matches on,
564
+ so this is how a sandbox gets re-tagged without destroying it. Works in
565
+ any state but destroyed; an empty name clears the label. Names are not
566
+ unique and are capped at 128 characters.
567
+ """
568
+ self._data = self._client.request(
569
+ "POST",
570
+ f"/run-cloud/sandboxes/{urllib.parse.quote(self.id, safe='')}/name",
571
+ {"name": name},
572
+ )
573
+ return self
574
+
551
575
  def set_timeout(self, seconds: int) -> "Sandbox":
552
576
  self._data = self._client.request(
553
577
  "POST",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runcloud-sdk
3
- Version: 0.8.3
3
+ Version: 0.9.0
4
4
  Summary: Python SDK for run.cloud, including sandbox-provider compatibility adapters
5
5
  Author: Newly
6
6
  License-Expression: Apache-2.0
@@ -62,6 +62,21 @@ finally:
62
62
  automation, set `RUN_CLOUD_API_KEY` and optionally `RUN_CLOUD_API_URL`, or pass
63
63
  `api_key` and `api_url` directly.
64
64
 
65
+ A sandbox's name is a label you own: set it at create, change it later, and
66
+ filter on it. Naming plus `resume` is how the same sandbox goes back to the same
67
+ piece of work instead of booting a new one:
68
+
69
+ ```python
70
+ matches = cloud.list(name=f"project-{project_id}")
71
+ box = matches[0].resume() if matches else cloud.create(name=f"project-{project_id}")
72
+
73
+ box.rename(f"project-{project_id}-v2")
74
+ box.rename("") # clears the label
75
+ ```
76
+
77
+ Names are not unique and mean nothing to the platform, so check `state` on a
78
+ match before using it. Renaming works in any state but `destroyed`.
79
+
65
80
  ## Compatibility adapters
66
81
 
67
82
  The same distribution includes migration adapters:
@@ -114,6 +114,35 @@ class SDKTests(unittest.TestCase):
114
114
  self.recorder.calls,
115
115
  )
116
116
 
117
+ def test_rename_posts_the_label_and_list_filters_on_it(self):
118
+ box = self.client.create()
119
+ box.rename("proj_42")
120
+ self.assertIn(
121
+ ("POST", "/run-cloud/sandboxes/sb_python/name", {"name": "proj_42"}),
122
+ self.recorder.calls,
123
+ )
124
+ # The response replaces the cached record, so the new name is readable
125
+ # without a second get().
126
+ self.assertEqual(box.name, "compat")
127
+
128
+ # An empty name clears the label rather than being rejected client-side.
129
+ box.rename("")
130
+ self.assertIn(
131
+ ("POST", "/run-cloud/sandboxes/sb_python/name", {"name": ""}),
132
+ self.recorder.calls,
133
+ )
134
+
135
+ self.client.list(name="proj_42")
136
+ self.assertIn(
137
+ ("GET", "/run-cloud/sandboxes?name=proj_42", None),
138
+ self.recorder.calls,
139
+ )
140
+ self.client.list(state="running", name="proj 42")
141
+ self.assertIn(
142
+ ("GET", "/run-cloud/sandboxes?state=running&name=proj+42", None),
143
+ self.recorder.calls,
144
+ )
145
+
117
146
  def test_exec_contract_defaults_legacy_true_and_preserves_false(self):
118
147
  for frame, expected in [
119
148
  ({"stream": "exit"}, 0),
File without changes
File without changes