runcloud-sdk 0.8.1__tar.gz → 0.8.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.
Files changed (20) hide show
  1. {runcloud_sdk-0.8.1/runcloud_sdk.egg-info → runcloud_sdk-0.8.2}/PKG-INFO +1 -1
  2. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/pyproject.toml +1 -1
  3. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/client.py +12 -1
  4. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2/runcloud_sdk.egg-info}/PKG-INFO +1 -1
  5. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/tests/test_sdk.py +26 -3
  6. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/LICENSE +0 -0
  7. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/README.md +0 -0
  8. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/__init__.py +0 -0
  9. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/compat/__init__.py +0 -0
  10. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/compat/blaxel.py +0 -0
  11. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/compat/daytona.py +0 -0
  12. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/compat/e2b.py +0 -0
  13. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/compat/modal.py +0 -0
  14. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/compat/sprites.py +0 -0
  15. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud/compat/vercel.py +0 -0
  16. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud_sdk.egg-info/SOURCES.txt +0 -0
  17. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud_sdk.egg-info/dependency_links.txt +0 -0
  18. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud_sdk.egg-info/requires.txt +0 -0
  19. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/runcloud_sdk.egg-info/top_level.txt +0 -0
  20. {runcloud_sdk-0.8.1 → runcloud_sdk-0.8.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runcloud-sdk
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: Python SDK for run.cloud, including sandbox-provider compatibility adapters
5
5
  Author: Newly
6
6
  License-Expression: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "runcloud-sdk"
3
- version = "0.8.1"
3
+ version = "0.8.2"
4
4
  description = "Python SDK for run.cloud, including sandbox-provider compatibility adapters"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"
@@ -20,7 +20,7 @@ from websockets.sync.client import connect as websocket_connect
20
20
  Transport = Callable[[str, str, Any], Any]
21
21
  StreamTransport = Callable[[str, dict[str, Any]], Any]
22
22
  DEFAULT_API_URL = "https://api.run.cloud"
23
- USER_AGENT = "runcloud-python/0.8.1"
23
+ USER_AGENT = "runcloud-python/0.8.2"
24
24
  FILE_CHUNK_BYTES = 512 * 1024
25
25
 
26
26
 
@@ -518,6 +518,17 @@ class Sandbox:
518
518
  )
519
519
  if payload.get("error"):
520
520
  raise RunCloudError(0, str(payload["error"]))
521
+ expected_next_offset = offset + len(chunk)
522
+ next_offset = payload.get("next_offset")
523
+ if chunk and (
524
+ isinstance(next_offset, bool)
525
+ or not isinstance(next_offset, int)
526
+ or next_offset != expected_next_offset
527
+ ):
528
+ raise RunCloudError(
529
+ 0,
530
+ "file write chunk was not acknowledged; the file may be incomplete",
531
+ )
521
532
 
522
533
  def pause(self) -> "Sandbox":
523
534
  self._data = self._client.request(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runcloud-sdk
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: Python SDK for run.cloud, including sandbox-provider compatibility adapters
5
5
  Author: Newly
6
6
  License-Expression: Apache-2.0
@@ -9,7 +9,7 @@ import unittest
9
9
  from pathlib import Path
10
10
  from unittest.mock import patch
11
11
 
12
- from runcloud import Client, UnsupportedCompatibilityFeatureError
12
+ from runcloud import Client, RunCloudError, UnsupportedCompatibilityFeatureError
13
13
  from runcloud.compat import modal
14
14
  from runcloud.compat.blaxel import SandboxInstance, SyncSandboxInstance
15
15
  from runcloud.compat.daytona import Daytona
@@ -30,6 +30,9 @@ class Recorder:
30
30
  if path.endswith("/exec"):
31
31
  return {"exit_code": 0, "stdout": "ok\n", "stderr": ""}
32
32
  if path.endswith("/fs"):
33
+ if body["op"] == "write":
34
+ chunk = base64.b64decode(body["content"])
35
+ return {"next_offset": body["offset"] + len(chunk)}
33
36
  return {"content": base64.b64encode(b"artifact").decode()}
34
37
  if path == "/run-cloud/sandboxes" and method == "GET":
35
38
  return {"items": [SANDBOX]}
@@ -199,6 +202,26 @@ class SDKTests(unittest.TestCase):
199
202
  ],
200
203
  )
201
204
 
205
+ def test_write_file_rejects_an_unacknowledged_continuation_chunk(self):
206
+ write_count = 0
207
+
208
+ def transport(method, path, body):
209
+ nonlocal write_count
210
+ if method == "GET":
211
+ return SANDBOX
212
+ self.assertEqual(path, "/run-cloud/sandboxes/sb_python/fs")
213
+ write_count += 1
214
+ if write_count == 1:
215
+ return {"next_offset": 512 * 1024}
216
+ return {}
217
+
218
+ box = Client(api_key="rc_live_test", transport=transport).get("sb_python")
219
+
220
+ with self.assertRaisesRegex(RunCloudError, "file write chunk was not acknowledged"):
221
+ box.write_file("/tmp/truncated.bin", b"a" * (512 * 1024) + b"tail")
222
+
223
+ self.assertEqual(write_count, 2)
224
+
202
225
  def test_compatibility_adapters_share_the_public_client(self):
203
226
  app = modal.App.lookup("compat", client=self.client)
204
227
  modal_sandbox = modal.Sandbox.create(app=app)
@@ -315,7 +338,7 @@ class SDKTests(unittest.TestCase):
315
338
  Client(api_key="rc_live_test").request("GET", "/run-cloud/account")
316
339
 
317
340
  request = urlopen.call_args.args[0]
318
- self.assertEqual(request.get_header("User-agent"), "runcloud-python/0.8.1")
341
+ self.assertEqual(request.get_header("User-agent"), "runcloud-python/0.8.2")
319
342
 
320
343
  def test_exec_stream_opens_authenticated_websocket_and_sends_command(self):
321
344
  session = WebSocketSession()
@@ -345,7 +368,7 @@ class SDKTests(unittest.TestCase):
345
368
  connect.assert_called_once_with(
346
369
  "wss://api.example.test/run-cloud/sandboxes/sb_1/exec/stream?mode=command",
347
370
  additional_headers={"Authorization": "Bearer rc_live_test"},
348
- user_agent_header="runcloud-python/0.8.1",
371
+ user_agent_header="runcloud-python/0.8.2",
349
372
  open_timeout=60.0,
350
373
  close_timeout=5,
351
374
  max_size=8 << 20,
File without changes
File without changes
File without changes