scalebox-sdk 0.1.25__py3-none-any.whl → 1.0.2__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.
- scalebox/__init__.py +2 -2
- scalebox/api/__init__.py +3 -1
- scalebox/api/client/api/sandboxes/get_sandboxes.py +1 -1
- scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
- scalebox/api/client/models/connect_sandbox.py +59 -0
- scalebox/api/client/models/error.py +2 -2
- scalebox/api/client/models/listed_sandbox.py +24 -3
- scalebox/api/client/models/new_sandbox.py +10 -0
- scalebox/api/client/models/sandbox.py +13 -0
- scalebox/api/client/models/sandbox_detail.py +24 -0
- scalebox/cli.py +125 -125
- scalebox/client/aclient.py +57 -57
- scalebox/client/client.py +102 -102
- scalebox/code_interpreter/__init__.py +12 -12
- scalebox/code_interpreter/charts.py +230 -230
- scalebox/code_interpreter/code_interpreter_async.py +3 -1
- scalebox/code_interpreter/code_interpreter_sync.py +3 -1
- scalebox/code_interpreter/constants.py +3 -3
- scalebox/code_interpreter/exceptions.py +13 -13
- scalebox/code_interpreter/models.py +485 -485
- scalebox/connection_config.py +36 -1
- scalebox/csx_connect/__init__.py +1 -1
- scalebox/csx_connect/client.py +485 -485
- scalebox/csx_desktop/main.py +651 -651
- scalebox/exceptions.py +83 -83
- scalebox/generated/api.py +61 -61
- scalebox/generated/api_pb2.py +203 -203
- scalebox/generated/api_pb2.pyi +956 -956
- scalebox/generated/api_pb2_connect.py +1407 -1407
- scalebox/generated/rpc.py +50 -50
- scalebox/sandbox/main.py +146 -139
- scalebox/sandbox/sandbox_api.py +105 -91
- scalebox/sandbox/signature.py +40 -40
- scalebox/sandbox/utils.py +34 -34
- scalebox/sandbox_async/main.py +226 -44
- scalebox/sandbox_async/sandbox_api.py +124 -3
- scalebox/sandbox_sync/main.py +205 -130
- scalebox/sandbox_sync/sandbox_api.py +119 -3
- scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -323
- scalebox/test/README.md +329 -329
- scalebox/test/bedrock_openai_adapter.py +73 -0
- scalebox/test/code_interpreter_test.py +34 -34
- scalebox/test/code_interpreter_test_sync.py +34 -34
- scalebox/test/run_stress_code_interpreter_sync.py +178 -0
- scalebox/test/simple_upload_example.py +131 -0
- scalebox/test/stabitiy_test.py +323 -0
- scalebox/test/test_browser_use.py +27 -0
- scalebox/test/test_browser_use_scalebox.py +62 -0
- scalebox/test/test_code_interpreter_execcode.py +289 -211
- scalebox/test/test_code_interpreter_sync_comprehensive.py +116 -69
- scalebox/test/test_connect_pause_async.py +300 -0
- scalebox/test/test_connect_pause_sync.py +300 -0
- scalebox/test/test_csx_desktop_examples.py +3 -3
- scalebox/test/test_desktop_sandbox_sf.py +112 -0
- scalebox/test/test_download_url.py +41 -0
- scalebox/test/test_existing_sandbox.py +1037 -0
- scalebox/test/test_sandbox_async_comprehensive.py +5 -3
- scalebox/test/test_sandbox_object_storage_example.py +151 -0
- scalebox/test/test_sandbox_object_storage_example_async.py +159 -0
- scalebox/test/test_sandbox_sync_comprehensive.py +1 -1
- scalebox/test/test_sf.py +141 -0
- scalebox/test/test_watch_dir_async.py +58 -0
- scalebox/test/testacreate.py +1 -1
- scalebox/test/testagetinfo.py +1 -3
- scalebox/test/testcomputeuse.py +243 -243
- scalebox/test/testsandbox_api.py +5 -5
- scalebox/test/testsandbox_async.py +17 -47
- scalebox/test/testsandbox_sync.py +19 -15
- scalebox/test/upload_100mb_example.py +377 -0
- scalebox/utils/httpcoreclient.py +297 -297
- scalebox/utils/httpxclient.py +403 -403
- scalebox/version.py +2 -2
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/METADATA +1 -1
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/RECORD +78 -60
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/WHEEL +1 -1
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/entry_points.txt +0 -0
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Test cases for connect and pause functionality (synchronous version).
|
|
4
|
+
|
|
5
|
+
This test suite validates:
|
|
6
|
+
- Creating a sandbox
|
|
7
|
+
- Adding and deleting files before pause
|
|
8
|
+
- Pausing the sandbox
|
|
9
|
+
- Connecting to the paused sandbox
|
|
10
|
+
- Verifying file operations after connect
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import time
|
|
14
|
+
|
|
15
|
+
from scalebox.sandbox.filesystem.filesystem import WriteInfo, FileType
|
|
16
|
+
from scalebox.sandbox_sync.main import Sandbox
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ConnectPauseSyncTest:
|
|
20
|
+
"""Test suite for connect and pause functionality (sync)."""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
self.sandbox = None
|
|
24
|
+
self.sandbox_id = None
|
|
25
|
+
self.test_results = []
|
|
26
|
+
|
|
27
|
+
def log_test_result(self, test_name: str, success: bool, message: str = ""):
|
|
28
|
+
"""记录测试结果"""
|
|
29
|
+
status = "✅ PASS" if success else "❌ FAIL"
|
|
30
|
+
result = {
|
|
31
|
+
"test": test_name,
|
|
32
|
+
"success": success,
|
|
33
|
+
"message": message,
|
|
34
|
+
}
|
|
35
|
+
self.test_results.append(result)
|
|
36
|
+
print(f"{status} {test_name}: {message}")
|
|
37
|
+
|
|
38
|
+
def test_connect_pause_with_files(self):
|
|
39
|
+
"""测试connect和pause功能,包含文件操作"""
|
|
40
|
+
try:
|
|
41
|
+
# 1. 创建沙箱
|
|
42
|
+
print("Step 1: Creating sandbox...")
|
|
43
|
+
self.sandbox = Sandbox.create(
|
|
44
|
+
template="code-interpreter",
|
|
45
|
+
timeout=3600,
|
|
46
|
+
metadata={"test": "connect_pause_sync"},
|
|
47
|
+
envs={"TEST_ENV": "sync_test"},
|
|
48
|
+
)
|
|
49
|
+
self.sandbox_id = self.sandbox.sandbox_id
|
|
50
|
+
assert self.sandbox is not None
|
|
51
|
+
assert self.sandbox_id is not None
|
|
52
|
+
print(f"Created sandbox with ID: {self.sandbox_id}")
|
|
53
|
+
|
|
54
|
+
# 2. 在pause之前增加文件
|
|
55
|
+
print("Step 2: Adding files before pause...")
|
|
56
|
+
test_files = {
|
|
57
|
+
"/tmp/test_file1.txt": "Content of test file 1",
|
|
58
|
+
"/tmp/test_file2.txt": "Content of test file 2",
|
|
59
|
+
"/tmp/test_file3.bin": b"Binary content for test file 3",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for file_path, content in test_files.items():
|
|
63
|
+
result = self.sandbox.files.write(file_path, content)
|
|
64
|
+
print(result)
|
|
65
|
+
assert isinstance(result, WriteInfo)
|
|
66
|
+
assert self.sandbox.files.exists(file_path)
|
|
67
|
+
print(f"Created file: {file_path}")
|
|
68
|
+
|
|
69
|
+
# 3. 在pause之前删除一个文件
|
|
70
|
+
print("Step 3: Deleting a file before pause...")
|
|
71
|
+
file_to_delete = "/tmp/test_file2.txt"
|
|
72
|
+
self.sandbox.files.remove(file_to_delete)
|
|
73
|
+
assert not self.sandbox.files.exists(file_to_delete)
|
|
74
|
+
print(f"Deleted file: {file_to_delete}")
|
|
75
|
+
|
|
76
|
+
# 4. 创建目录和文件
|
|
77
|
+
print("Step 4: Creating directory and nested files...")
|
|
78
|
+
self.sandbox.files.make_dir("/tmp/test_dir")
|
|
79
|
+
self.sandbox.files.write(
|
|
80
|
+
"/tmp/test_dir/nested_file.txt", "Nested file content"
|
|
81
|
+
)
|
|
82
|
+
assert self.sandbox.files.exists("/tmp/test_dir")
|
|
83
|
+
assert self.sandbox.files.exists("/tmp/test_dir/nested_file.txt")
|
|
84
|
+
print("Created directory and nested file")
|
|
85
|
+
|
|
86
|
+
# 5. Pause沙箱
|
|
87
|
+
print("Step 5: Pausing sandbox...")
|
|
88
|
+
self.sandbox.beta_pause()
|
|
89
|
+
print("Sandbox paused successfully")
|
|
90
|
+
|
|
91
|
+
# 等待一小段时间确保pause完成
|
|
92
|
+
time.sleep(1)
|
|
93
|
+
|
|
94
|
+
# 6. Connect到暂停的沙箱
|
|
95
|
+
print("Step 6: Connecting to paused sandbox...")
|
|
96
|
+
connected_sandbox = Sandbox.connect(self.sandbox_id)
|
|
97
|
+
print(connected_sandbox)
|
|
98
|
+
assert connected_sandbox.sandbox_id == self.sandbox_id
|
|
99
|
+
print("Connected to sandbox successfully")
|
|
100
|
+
|
|
101
|
+
# 等待一小段时间确保connect完成
|
|
102
|
+
time.sleep(2)
|
|
103
|
+
|
|
104
|
+
# 7. 在connect之后校验文件操作结果
|
|
105
|
+
print("Step 7: Verifying file operations after connect...")
|
|
106
|
+
|
|
107
|
+
# 校验应该存在的文件
|
|
108
|
+
assert connected_sandbox.files.exists(
|
|
109
|
+
"/tmp/test_file1.txt"
|
|
110
|
+
), "test_file1.txt should exist"
|
|
111
|
+
file1_content = connected_sandbox.files.read(
|
|
112
|
+
"/tmp/test_file1.txt", format="text"
|
|
113
|
+
)
|
|
114
|
+
assert "Content of test file 1" in file1_content
|
|
115
|
+
print("✅ Verified test_file1.txt exists and content is correct")
|
|
116
|
+
|
|
117
|
+
assert connected_sandbox.files.exists(
|
|
118
|
+
"/tmp/test_file3.bin"
|
|
119
|
+
), "test_file3.bin should exist"
|
|
120
|
+
file3_content = connected_sandbox.files.read(
|
|
121
|
+
"/tmp/test_file3.bin", format="bytes"
|
|
122
|
+
)
|
|
123
|
+
assert bytes(file3_content) == b"Binary content for test file 3"
|
|
124
|
+
print("✅ Verified test_file3.bin exists and content is correct")
|
|
125
|
+
|
|
126
|
+
# 校验应该不存在的文件(被删除的)
|
|
127
|
+
assert not connected_sandbox.files.exists(
|
|
128
|
+
"/tmp/test_file2.txt"
|
|
129
|
+
), "test_file2.txt should not exist"
|
|
130
|
+
print("✅ Verified test_file2.txt was deleted correctly")
|
|
131
|
+
|
|
132
|
+
# 校验目录和嵌套文件
|
|
133
|
+
assert connected_sandbox.files.exists(
|
|
134
|
+
"/tmp/test_dir"
|
|
135
|
+
), "test_dir should exist"
|
|
136
|
+
assert connected_sandbox.files.exists(
|
|
137
|
+
"/tmp/test_dir/nested_file.txt"
|
|
138
|
+
), "nested_file.txt should exist"
|
|
139
|
+
nested_content = connected_sandbox.files.read(
|
|
140
|
+
"/tmp/test_dir/nested_file.txt", format="text"
|
|
141
|
+
)
|
|
142
|
+
assert "Nested file content" in nested_content
|
|
143
|
+
print("✅ Verified directory and nested file exist and content is correct")
|
|
144
|
+
|
|
145
|
+
# 8. 在connect后的沙箱中执行一些操作验证功能正常
|
|
146
|
+
print("Step 8: Verifying sandbox functionality after connect...")
|
|
147
|
+
result = connected_sandbox.commands.run("echo 'Test command after connect'")
|
|
148
|
+
assert result.exit_code == 0
|
|
149
|
+
assert "Test command after connect" in result.stdout
|
|
150
|
+
print("✅ Verified sandbox commands work after connect")
|
|
151
|
+
|
|
152
|
+
# 9. 创建新文件验证写入功能正常
|
|
153
|
+
print("Step 9: Testing file write after connect...")
|
|
154
|
+
new_file_path = "/tmp/new_file_after_connect.txt"
|
|
155
|
+
connected_sandbox.files.write(
|
|
156
|
+
new_file_path, "New file created after connect"
|
|
157
|
+
)
|
|
158
|
+
assert connected_sandbox.files.exists(new_file_path)
|
|
159
|
+
new_content = connected_sandbox.files.read(new_file_path, format="text")
|
|
160
|
+
assert "New file created after connect" in new_content
|
|
161
|
+
print("✅ Verified file write works after connect")
|
|
162
|
+
|
|
163
|
+
self.log_test_result(
|
|
164
|
+
"Connect and Pause with Files", True, "All verifications passed"
|
|
165
|
+
)
|
|
166
|
+
return True
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
self.log_test_result("Connect and Pause with Files", False, str(e))
|
|
170
|
+
print(f"Test failed with error: {e}")
|
|
171
|
+
import traceback
|
|
172
|
+
|
|
173
|
+
traceback.print_exc()
|
|
174
|
+
return False
|
|
175
|
+
|
|
176
|
+
def test_connect_pause_multiple_operations(self):
|
|
177
|
+
"""测试多次pause和connect操作"""
|
|
178
|
+
try:
|
|
179
|
+
# 1. 创建沙箱
|
|
180
|
+
print("Test 2: Creating sandbox for multiple operations test...")
|
|
181
|
+
sandbox = Sandbox.create(
|
|
182
|
+
template="base",
|
|
183
|
+
timeout=3600,
|
|
184
|
+
metadata={"test": "connect_pause_multiple_sync"},
|
|
185
|
+
)
|
|
186
|
+
sandbox_id = sandbox.sandbox_id
|
|
187
|
+
print(f"Created sandbox with ID: {sandbox_id}")
|
|
188
|
+
|
|
189
|
+
# 2. 第一次操作:创建文件
|
|
190
|
+
print("First operation: Creating files...")
|
|
191
|
+
sandbox.files.write("/tmp/multi_test1.txt", "First batch")
|
|
192
|
+
sandbox.files.write("/tmp/multi_test2.txt", "First batch")
|
|
193
|
+
|
|
194
|
+
# 3. 第一次pause
|
|
195
|
+
print("First pause...")
|
|
196
|
+
sandbox.beta_pause()
|
|
197
|
+
time.sleep(2)
|
|
198
|
+
|
|
199
|
+
# 4. 第一次connect
|
|
200
|
+
print("First connect...")
|
|
201
|
+
sandbox = Sandbox.connect(sandbox_id)
|
|
202
|
+
time.sleep(2)
|
|
203
|
+
|
|
204
|
+
# 5. 验证第一次的文件存在
|
|
205
|
+
assert sandbox.files.exists("/tmp/multi_test1.txt")
|
|
206
|
+
assert sandbox.files.exists("/tmp/multi_test2.txt")
|
|
207
|
+
|
|
208
|
+
# 6. 第二次操作:删除一个文件,创建新文件
|
|
209
|
+
print("Second operation: Deleting and creating files...")
|
|
210
|
+
sandbox.files.remove("/tmp/multi_test1.txt")
|
|
211
|
+
sandbox.files.write("/tmp/multi_test3.txt", "Second batch")
|
|
212
|
+
|
|
213
|
+
# 7. 第二次pause
|
|
214
|
+
print("Second pause...")
|
|
215
|
+
sandbox.beta_pause()
|
|
216
|
+
time.sleep(2)
|
|
217
|
+
|
|
218
|
+
# 8. 第二次connect
|
|
219
|
+
print("Second connect...")
|
|
220
|
+
sandbox = Sandbox.connect(sandbox_id)
|
|
221
|
+
time.sleep(2)
|
|
222
|
+
|
|
223
|
+
# 9. 验证第二次操作的结果
|
|
224
|
+
assert not sandbox.files.exists(
|
|
225
|
+
"/tmp/multi_test1.txt"
|
|
226
|
+
), "multi_test1.txt should be deleted"
|
|
227
|
+
assert sandbox.files.exists(
|
|
228
|
+
"/tmp/multi_test2.txt"
|
|
229
|
+
), "multi_test2.txt should exist"
|
|
230
|
+
assert sandbox.files.exists(
|
|
231
|
+
"/tmp/multi_test3.txt"
|
|
232
|
+
), "multi_test3.txt should exist"
|
|
233
|
+
content = sandbox.files.read("/tmp/multi_test3.txt", format="text")
|
|
234
|
+
assert "Second batch" in content
|
|
235
|
+
|
|
236
|
+
# 清理
|
|
237
|
+
sandbox.kill()
|
|
238
|
+
|
|
239
|
+
self.log_test_result(
|
|
240
|
+
"Multiple Connect and Pause Operations",
|
|
241
|
+
True,
|
|
242
|
+
"All verifications passed",
|
|
243
|
+
)
|
|
244
|
+
return True
|
|
245
|
+
|
|
246
|
+
except Exception as e:
|
|
247
|
+
self.log_test_result("Multiple Connect and Pause Operations", False, str(e))
|
|
248
|
+
print(f"Test failed with error: {e}")
|
|
249
|
+
import traceback
|
|
250
|
+
|
|
251
|
+
traceback.print_exc()
|
|
252
|
+
return False
|
|
253
|
+
|
|
254
|
+
def cleanup(self):
|
|
255
|
+
"""清理资源"""
|
|
256
|
+
if self.sandbox:
|
|
257
|
+
try:
|
|
258
|
+
self.sandbox.kill()
|
|
259
|
+
print("Sandbox cleaned up successfully")
|
|
260
|
+
except Exception as e:
|
|
261
|
+
print(f"Error cleaning up sandbox: {e}")
|
|
262
|
+
|
|
263
|
+
def print_summary(self):
|
|
264
|
+
"""打印测试摘要"""
|
|
265
|
+
total_tests = len(self.test_results)
|
|
266
|
+
passed_tests = sum(1 for r in self.test_results if r["success"])
|
|
267
|
+
failed_tests = total_tests - passed_tests
|
|
268
|
+
|
|
269
|
+
print("\n" + "=" * 60)
|
|
270
|
+
print("Connect and Pause Test Report (Sync)")
|
|
271
|
+
print("=" * 60)
|
|
272
|
+
print(f"总测试数: {total_tests}")
|
|
273
|
+
print(f"通过数: {passed_tests}")
|
|
274
|
+
print(f"失败数: {failed_tests}")
|
|
275
|
+
print(f"成功率: {(passed_tests/total_tests*100):.1f}%")
|
|
276
|
+
|
|
277
|
+
if failed_tests > 0:
|
|
278
|
+
print(f"\n失败的测试:")
|
|
279
|
+
for result in self.test_results:
|
|
280
|
+
if not result["success"]:
|
|
281
|
+
print(f" ❌ {result['test']}: {result['message']}")
|
|
282
|
+
|
|
283
|
+
print("=" * 60)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def main():
|
|
287
|
+
"""主函数"""
|
|
288
|
+
test_suite = ConnectPauseSyncTest()
|
|
289
|
+
|
|
290
|
+
try:
|
|
291
|
+
# 运行测试
|
|
292
|
+
test_suite.test_connect_pause_with_files()
|
|
293
|
+
# test_suite.test_connect_pause_multiple_operations()
|
|
294
|
+
finally:
|
|
295
|
+
test_suite.cleanup()
|
|
296
|
+
test_suite.print_summary()
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
if __name__ == "__main__":
|
|
300
|
+
main()
|
|
@@ -18,7 +18,9 @@ class CsxDesktopValidator:
|
|
|
18
18
|
self.success_count = 0
|
|
19
19
|
self.fail_count = 0
|
|
20
20
|
|
|
21
|
-
def log_test_result(
|
|
21
|
+
def log_test_result(
|
|
22
|
+
self, name: str, success: bool, error: Optional[Exception] = None
|
|
23
|
+
) -> None:
|
|
22
24
|
if success:
|
|
23
25
|
self.success_count += 1
|
|
24
26
|
print(f"✅ {name}")
|
|
@@ -126,5 +128,3 @@ if __name__ == "__main__":
|
|
|
126
128
|
finally:
|
|
127
129
|
validator.cleanup()
|
|
128
130
|
validator.print_summary()
|
|
129
|
-
|
|
130
|
-
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
测试用例:基于desktop创建sandbox,上传并执行test_sf.py
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
|
|
11
|
+
# 确保可以从项目根导入 scalebox
|
|
12
|
+
from scalebox.csx_desktop.main import Sandbox
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main():
|
|
16
|
+
"""主测试函数"""
|
|
17
|
+
print("=" * 60)
|
|
18
|
+
print("开始测试:基于desktop创建sandbox并执行test_sf.py")
|
|
19
|
+
print("=" * 60)
|
|
20
|
+
|
|
21
|
+
# 1. 基于desktop创建sandbox
|
|
22
|
+
print("\n[步骤 1] 正在创建desktop sandbox...")
|
|
23
|
+
sandbox = Sandbox.create(
|
|
24
|
+
template="browser-use",
|
|
25
|
+
timeout=3600, # 1小时超时
|
|
26
|
+
)
|
|
27
|
+
print(f"✓ Sandbox创建成功,ID: {sandbox.sandbox_id}")
|
|
28
|
+
|
|
29
|
+
# 2. 获取network_proxy
|
|
30
|
+
print("\n[步骤 2] 获取network_proxy...")
|
|
31
|
+
network_proxy = sandbox.network_proxy()
|
|
32
|
+
print(f"✓ Network Proxy: {network_proxy}")
|
|
33
|
+
|
|
34
|
+
# 3. 获取VNC URL(不启动,直接获取)
|
|
35
|
+
print("\n[步骤 3] 获取VNC URL...")
|
|
36
|
+
vnc_url = sandbox.stream.get_url(auto_connect=True)
|
|
37
|
+
print(f"✓ VNC URL: {vnc_url}")
|
|
38
|
+
|
|
39
|
+
# 4. 读取test_sf.py并修改username和password
|
|
40
|
+
print("\n[步骤 4] 读取并修改test_sf.py...")
|
|
41
|
+
test_sf_path = os.path.join(os.path.dirname(__file__), "test_sf.py")
|
|
42
|
+
|
|
43
|
+
with open(test_sf_path, "r", encoding="utf-8") as f:
|
|
44
|
+
test_sf_content = f.read()
|
|
45
|
+
|
|
46
|
+
# 从network_proxy中提取username和password
|
|
47
|
+
if network_proxy and isinstance(network_proxy, dict):
|
|
48
|
+
# network_proxy结构: {'proxy_configs': {'username': '...', 'password': '...', ...}, ...}
|
|
49
|
+
proxy_configs = network_proxy.get("proxy_configs", {})
|
|
50
|
+
if isinstance(proxy_configs, dict):
|
|
51
|
+
proxy_username = proxy_configs.get("username", "")
|
|
52
|
+
proxy_password = proxy_configs.get("password", "")
|
|
53
|
+
else:
|
|
54
|
+
# 兼容旧格式:直接在network_proxy中
|
|
55
|
+
proxy_username = network_proxy.get("username", "")
|
|
56
|
+
proxy_password = network_proxy.get("password", "")
|
|
57
|
+
|
|
58
|
+
if not proxy_username or not proxy_password:
|
|
59
|
+
print("⚠ 警告: network_proxy中缺少username或password字段")
|
|
60
|
+
print(f" network_proxy内容: {network_proxy}")
|
|
61
|
+
else:
|
|
62
|
+
# 替换test_sf.py中的username和password
|
|
63
|
+
# 匹配proxy字典中的username和password(处理可能的引号差异)
|
|
64
|
+
pattern_username = r'"username"\s*:\s*"[^"]*"'
|
|
65
|
+
pattern_password = r'"password"\s*:\s*"[^"]*"'
|
|
66
|
+
|
|
67
|
+
test_sf_content = re.sub(
|
|
68
|
+
pattern_username, f'"username": "{proxy_username}"', test_sf_content
|
|
69
|
+
)
|
|
70
|
+
test_sf_content = re.sub(
|
|
71
|
+
pattern_password, f'"password": "{proxy_password}"', test_sf_content
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
print(f"✓ 已更新username: {proxy_username}")
|
|
75
|
+
print(f"✓ 已更新password: {proxy_password[:20]}...")
|
|
76
|
+
else:
|
|
77
|
+
print("⚠ 警告: network_proxy为空或格式不正确,跳过修改")
|
|
78
|
+
print(f" network_proxy类型: {type(network_proxy)}, 值: {network_proxy}")
|
|
79
|
+
|
|
80
|
+
# 5. 上传test_sf.py到sandbox的/目录
|
|
81
|
+
print("\n[步骤 5] 上传test_sf.py到sandbox的/目录...")
|
|
82
|
+
result = sandbox.files.write("/test_sf.py", test_sf_content.encode("utf-8"))
|
|
83
|
+
print(f"✓ 文件上传成功: {result.path}")
|
|
84
|
+
|
|
85
|
+
# 6. 在sandbox中执行命令
|
|
86
|
+
print("\n[步骤 6] 在sandbox中执行: source /venv/bin/activate && python /test_sf.py")
|
|
87
|
+
try:
|
|
88
|
+
# 使用bash -c确保source命令和环境变量正确加载
|
|
89
|
+
result = sandbox.commands.run(
|
|
90
|
+
'bash -c "source /venv/bin/activate && python /test_sf.py"',
|
|
91
|
+
timeout=600, # 10分钟超时
|
|
92
|
+
)
|
|
93
|
+
print(f"✓ 命令执行完成")
|
|
94
|
+
print(f"退出码: {result.exit_code}")
|
|
95
|
+
print(f"标准输出:\n{result.stdout}")
|
|
96
|
+
if result.stderr:
|
|
97
|
+
print(f"标准错误:\n{result.stderr}")
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(f"✗ 命令执行失败: {e}")
|
|
100
|
+
raise
|
|
101
|
+
|
|
102
|
+
print("\n" + "=" * 60)
|
|
103
|
+
print("测试完成!")
|
|
104
|
+
print("=" * 60)
|
|
105
|
+
|
|
106
|
+
# 清理(可选,注释掉以保留sandbox)
|
|
107
|
+
# sandbox.kill()
|
|
108
|
+
# print("Sandbox已清理")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
main()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from scalebox.code_interpreter import Sandbox
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
# 1. 准备要上传的文件内容
|
|
5
|
+
print("正在准备文件内容...")
|
|
6
|
+
results_data = {
|
|
7
|
+
"experiment_id": "exp_001",
|
|
8
|
+
"status": "completed",
|
|
9
|
+
"metrics": {"accuracy": 0.952, "precision": 0.94, "recall": 0.96},
|
|
10
|
+
"timestamp": "2024-01-01T12:00:00Z",
|
|
11
|
+
"details": [
|
|
12
|
+
{"epoch": 1, "loss": 0.45},
|
|
13
|
+
{"epoch": 2, "loss": 0.32},
|
|
14
|
+
{"epoch": 3, "loss": 0.18},
|
|
15
|
+
],
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# 转换为 JSON 字符串
|
|
19
|
+
json_content = json.dumps(results_data, indent=2)
|
|
20
|
+
|
|
21
|
+
# 2. 创建沙箱并写入文件
|
|
22
|
+
print("\n正在创建沙箱并写入文件...")
|
|
23
|
+
sandbox = Sandbox.create(timeout=1800)
|
|
24
|
+
remote_path = "/home/user/results.json"
|
|
25
|
+
|
|
26
|
+
# 关键修改:使用 sandbox.write() 写入文件
|
|
27
|
+
sandbox.files.write(remote_path, json_content)
|
|
28
|
+
print(f"✅ 文件已写入沙箱: {remote_path}")
|
|
29
|
+
|
|
30
|
+
# 3. 获取预签名下载 URL
|
|
31
|
+
print("\n正在生成下载链接...")
|
|
32
|
+
download_url = sandbox.download_url(
|
|
33
|
+
path=remote_path, use_signature_expiration=180 # 180秒有效期
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
print(f"\n📥 下载 URL: {download_url}")
|
|
37
|
+
print(f"⏰ 链接将在 3 分钟后过期")
|
|
38
|
+
|
|
39
|
+
upload_url = sandbox.upload_url(path="/home/user", use_signature_expiration=360)
|
|
40
|
+
print(f"\n📥 上传 URL: {upload_url}")
|
|
41
|
+
print(f"⏰ 链接将在 6 分钟后过期")
|