grasp-sdk 0.1.8__py3-none-any.whl → 0.2.0a1__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.
Potentially problematic release.
This version of grasp-sdk might be problematic. Click here for more details.
- examples/example_async_context.py +122 -0
- examples/example_binary_file_support.py +127 -0
- examples/example_grasp_usage.py +82 -0
- examples/example_readfile_usage.py +136 -0
- examples/grasp_terminal.py +110 -0
- examples/grasp_usage.py +111 -0
- examples/test_async_context.py +64 -0
- examples/test_get_replay_screenshots.py +90 -0
- examples/test_grasp_classes.py +80 -0
- examples/test_python_script.py +160 -0
- examples/test_removed_methods.py +80 -0
- examples/test_shutdown_deprecation.py +62 -0
- examples/test_terminal_updates.py +196 -0
- grasp_sdk/__init__.py +131 -239
- grasp_sdk/grasp/__init__.py +26 -0
- grasp_sdk/grasp/browser.py +69 -0
- grasp_sdk/grasp/index.py +122 -0
- grasp_sdk/grasp/server.py +250 -0
- grasp_sdk/grasp/session.py +108 -0
- grasp_sdk/grasp/terminal.py +32 -0
- grasp_sdk/grasp/utils.py +90 -0
- grasp_sdk/models/__init__.py +1 -1
- grasp_sdk/services/__init__.py +8 -1
- grasp_sdk/services/browser.py +92 -63
- grasp_sdk/services/filesystem.py +94 -0
- grasp_sdk/services/sandbox.py +391 -20
- grasp_sdk/services/terminal.py +177 -0
- grasp_sdk/utils/auth.py +6 -8
- {grasp_sdk-0.1.8.dist-info → grasp_sdk-0.2.0a1.dist-info}/METADATA +2 -3
- grasp_sdk-0.2.0a1.dist-info/RECORD +36 -0
- {grasp_sdk-0.1.8.dist-info → grasp_sdk-0.2.0a1.dist-info}/top_level.txt +1 -0
- grasp_sdk/sandbox/bootstrap-chrome-stable.mjs +0 -69
- grasp_sdk/sandbox/chrome-stable.mjs +0 -424
- grasp_sdk/sandbox/chromium.mjs +0 -395
- grasp_sdk/sandbox/http-proxy.mjs +0 -324
- grasp_sdk-0.1.8.dist-info/RECORD +0 -18
- {grasp_sdk-0.1.8.dist-info → grasp_sdk-0.2.0a1.dist-info}/WHEEL +0 -0
- {grasp_sdk-0.1.8.dist-info → grasp_sdk-0.2.0a1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""测试 Grasp 异步上下文管理器功能"""
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import os
|
|
6
|
+
from grasp_sdk import Grasp
|
|
7
|
+
|
|
8
|
+
async def test_async_context_manager():
|
|
9
|
+
"""测试异步上下文管理器功能"""
|
|
10
|
+
print("测试 Grasp 异步上下文管理器...")
|
|
11
|
+
|
|
12
|
+
# 初始化 Grasp SDK
|
|
13
|
+
grasp = Grasp({'apiKey': 'test-key'})
|
|
14
|
+
|
|
15
|
+
# 测试 launch_context 方法
|
|
16
|
+
print("\n1. 测试 launch_context 方法:")
|
|
17
|
+
context_manager = grasp.launch_context({
|
|
18
|
+
'browser': {
|
|
19
|
+
'type': 'chromium',
|
|
20
|
+
'headless': True,
|
|
21
|
+
'timeout': 30000
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
print(f" ✓ launch_context 返回类型: {type(context_manager).__name__}")
|
|
25
|
+
print(f" ✓ 是否为同一实例: {context_manager is grasp}")
|
|
26
|
+
|
|
27
|
+
# 测试异步上下文管理器方法存在性
|
|
28
|
+
print("\n2. 测试异步上下文管理器方法:")
|
|
29
|
+
print(f" ✓ 具有 __aenter__ 方法: {hasattr(grasp, '__aenter__')}")
|
|
30
|
+
print(f" ✓ 具有 __aexit__ 方法: {hasattr(grasp, '__aexit__')}")
|
|
31
|
+
|
|
32
|
+
# 测试错误情况
|
|
33
|
+
print("\n3. 测试错误处理:")
|
|
34
|
+
try:
|
|
35
|
+
# 尝试在没有设置 launch_options 的情况下使用上下文管理器
|
|
36
|
+
fresh_grasp = Grasp({'apiKey': 'test-key'})
|
|
37
|
+
async with fresh_grasp as session:
|
|
38
|
+
pass
|
|
39
|
+
except RuntimeError as e:
|
|
40
|
+
print(f" ✓ 正确捕获错误: {e}")
|
|
41
|
+
|
|
42
|
+
# 模拟使用异步上下文管理器的语法(不实际连接)
|
|
43
|
+
print("\n4. 异步上下文管理器语法示例:")
|
|
44
|
+
print(" 代码示例:")
|
|
45
|
+
print(" async with grasp.launch_context({")
|
|
46
|
+
print(" 'browser': {")
|
|
47
|
+
print(" 'type': 'chromium',")
|
|
48
|
+
print(" 'headless': True,")
|
|
49
|
+
print(" 'timeout': 30000")
|
|
50
|
+
print(" }")
|
|
51
|
+
print(" }) as session:")
|
|
52
|
+
print(" # 使用 session 进行操作")
|
|
53
|
+
print(" browser = session.browser")
|
|
54
|
+
print(" terminal = session.terminal")
|
|
55
|
+
print(" files = session.files")
|
|
56
|
+
|
|
57
|
+
print("\n✅ 异步上下文管理器功能测试完成!")
|
|
58
|
+
print("\n📝 使用说明:")
|
|
59
|
+
print(" - 使用 grasp.launch_context(options) 设置启动选项")
|
|
60
|
+
print(" - 然后使用 async with 语法自动管理会话生命周期")
|
|
61
|
+
print(" - 会话将在退出上下文时自动关闭")
|
|
62
|
+
|
|
63
|
+
if __name__ == '__main__':
|
|
64
|
+
asyncio.run(test_async_context_manager())
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""测试 get_replay_screenshots 功能的示例脚本
|
|
3
|
+
|
|
4
|
+
这个脚本演示如何使用 get_replay_screenshots 函数获取截图目录路径。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import os
|
|
9
|
+
from grasp_sdk import launch_browser, get_replay_screenshots
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def test_get_replay_screenshots():
|
|
13
|
+
"""测试 get_replay_screenshots 功能"""
|
|
14
|
+
print("🚀 启动浏览器服务...")
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
# 启动浏览器并获取连接信息
|
|
18
|
+
connection = await launch_browser({
|
|
19
|
+
'headless': True,
|
|
20
|
+
'type': 'chromium'
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
print(f"✅ 浏览器启动成功!")
|
|
24
|
+
print(f"连接 ID: {connection.id}")
|
|
25
|
+
print(f"WebSocket URL: {connection.ws_url or connection.ws_url}")
|
|
26
|
+
print(f"HTTP URL: {connection.http_url}")
|
|
27
|
+
|
|
28
|
+
# 获取截图目录路径
|
|
29
|
+
print("\n📸 获取截图目录路径...")
|
|
30
|
+
screenshots_dir = await get_replay_screenshots(connection)
|
|
31
|
+
|
|
32
|
+
print(f"✅ 截图目录路径: {screenshots_dir}")
|
|
33
|
+
|
|
34
|
+
# 检查目录是否存在
|
|
35
|
+
if os.path.exists(screenshots_dir):
|
|
36
|
+
print(f"📁 目录已存在")
|
|
37
|
+
|
|
38
|
+
# 列出目录中的文件
|
|
39
|
+
files = os.listdir(screenshots_dir)
|
|
40
|
+
if files:
|
|
41
|
+
print(f"📋 目录中有 {len(files)} 个文件:")
|
|
42
|
+
for file in files[:5]: # 只显示前5个文件
|
|
43
|
+
print(f" - {file}")
|
|
44
|
+
if len(files) > 5:
|
|
45
|
+
print(f" ... 还有 {len(files) - 5} 个文件")
|
|
46
|
+
else:
|
|
47
|
+
print("📂 目录为空")
|
|
48
|
+
else:
|
|
49
|
+
print(f"⚠️ 目录不存在,将在首次使用时创建")
|
|
50
|
+
|
|
51
|
+
# 测试错误处理
|
|
52
|
+
print("\n🧪 测试错误处理...")
|
|
53
|
+
|
|
54
|
+
# 测试缺少 id 字段的情况
|
|
55
|
+
try:
|
|
56
|
+
invalid_connection = {
|
|
57
|
+
'ws_url': connection.ws_url,
|
|
58
|
+
'http_url': connection.http_url
|
|
59
|
+
# 缺少 'id' 字段
|
|
60
|
+
}
|
|
61
|
+
await get_replay_screenshots(invalid_connection)
|
|
62
|
+
except ValueError as e:
|
|
63
|
+
print(f"✅ 正确捕获 ValueError: {e}")
|
|
64
|
+
|
|
65
|
+
# 测试无效 ID 的情况
|
|
66
|
+
try:
|
|
67
|
+
invalid_connection = {
|
|
68
|
+
'id': 'invalid-id-123',
|
|
69
|
+
'ws_url': connection.ws_url,
|
|
70
|
+
'http_url': connection.http_url
|
|
71
|
+
}
|
|
72
|
+
await get_replay_screenshots(invalid_connection)
|
|
73
|
+
except KeyError as e:
|
|
74
|
+
print(f"✅ 正确捕获 KeyError: {e}")
|
|
75
|
+
|
|
76
|
+
print("\n🎉 所有测试完成!")
|
|
77
|
+
|
|
78
|
+
except Exception as e:
|
|
79
|
+
print(f"❌ 测试失败: {e}")
|
|
80
|
+
raise
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__":
|
|
84
|
+
# 检查环境变量
|
|
85
|
+
if not os.getenv('GRASP_KEY'):
|
|
86
|
+
print("⚠️ 警告: 未设置 GRASP_KEY 环境变量")
|
|
87
|
+
print("请设置: export GRASP_KEY=your_api_key")
|
|
88
|
+
|
|
89
|
+
# 运行测试
|
|
90
|
+
asyncio.run(test_get_replay_screenshots())
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""测试 Grasp 类的功能"""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from grasp_sdk import Grasp, GraspSession, GraspBrowser, GraspTerminal
|
|
6
|
+
|
|
7
|
+
def test_grasp_classes():
|
|
8
|
+
"""测试所有 Grasp 类的基本功能"""
|
|
9
|
+
print("🧪 测试 Grasp 类功能...")
|
|
10
|
+
|
|
11
|
+
# 测试 Grasp 类初始化
|
|
12
|
+
print("\n1. 测试 Grasp 类初始化:")
|
|
13
|
+
|
|
14
|
+
# 通过字典设置 apiKey
|
|
15
|
+
grasp1 = Grasp({'apiKey': 'test-key-from-dict'})
|
|
16
|
+
print(f" ✓ 通过字典初始化: {grasp1.key == 'test-key-from-dict'}")
|
|
17
|
+
|
|
18
|
+
# 通过环境变量设置 apiKey
|
|
19
|
+
os.environ['GRASP_KEY'] = 'test-key-from-env'
|
|
20
|
+
grasp2 = Grasp()
|
|
21
|
+
print(f" ✓ 通过环境变量初始化: {grasp2.key == 'test-key-from-env'}")
|
|
22
|
+
|
|
23
|
+
# 测试类的导入
|
|
24
|
+
print("\n2. 测试类的导入:")
|
|
25
|
+
print(f" ✓ Grasp 类可用: {Grasp is not None}")
|
|
26
|
+
print(f" ✓ GraspSession 类可用: {GraspSession is not None}")
|
|
27
|
+
print(f" ✓ GraspBrowser 类可用: {GraspBrowser is not None}")
|
|
28
|
+
print(f" ✓ GraspTerminal 类可用: {GraspTerminal is not None}")
|
|
29
|
+
|
|
30
|
+
# 测试方法可用性
|
|
31
|
+
print("\n3. 测试方法可用性:")
|
|
32
|
+
grasp = Grasp({'apiKey': 'test-key'})
|
|
33
|
+
|
|
34
|
+
# 测试 Grasp 类方法
|
|
35
|
+
print(f" ✓ Grasp.launch 方法可用: {hasattr(grasp, 'launch')}")
|
|
36
|
+
print(f" ✓ Grasp.connect 方法可用: {hasattr(grasp, 'connect')}")
|
|
37
|
+
print(f" ✓ Grasp.launch_browser 静态方法可用: {hasattr(Grasp, 'launch_browser')}")
|
|
38
|
+
|
|
39
|
+
# 测试异步上下文管理器功能
|
|
40
|
+
print("\n4. 测试异步上下文管理器功能:")
|
|
41
|
+
try:
|
|
42
|
+
# 测试 launch_context 方法
|
|
43
|
+
context_manager = grasp.launch_context({
|
|
44
|
+
'browser': {
|
|
45
|
+
'type': 'chromium',
|
|
46
|
+
'headless': True,
|
|
47
|
+
'timeout': 30000
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
print(f" ✓ launch_context 方法可用: {hasattr(grasp, 'launch_context')}")
|
|
51
|
+
print(f" ✓ 返回自身实例: {context_manager is grasp}")
|
|
52
|
+
|
|
53
|
+
# 测试异步上下文管理器方法
|
|
54
|
+
print(f" ✓ __aenter__ 方法可用: {hasattr(grasp, '__aenter__')}")
|
|
55
|
+
print(f" ✓ __aexit__ 方法可用: {hasattr(grasp, '__aexit__')}")
|
|
56
|
+
|
|
57
|
+
except Exception as e:
|
|
58
|
+
print(f" ❌ 异步上下文管理器测试失败: {e}")
|
|
59
|
+
|
|
60
|
+
print("\n✅ 所有测试通过!")
|
|
61
|
+
print("\n📋 已实现的方法:")
|
|
62
|
+
print(" - Grasp.launch()")
|
|
63
|
+
print(" - Grasp.connect()")
|
|
64
|
+
print(" - Grasp.launch_browser()")
|
|
65
|
+
print(" - Grasp.launch_context() [新增]")
|
|
66
|
+
print(" - Grasp.__aenter__() [新增]")
|
|
67
|
+
print(" - Grasp.__aexit__() [新增]")
|
|
68
|
+
print(" - GraspSession.close()")
|
|
69
|
+
print(" - GraspBrowser.get_endpoint()")
|
|
70
|
+
print(" - GraspTerminal.create()")
|
|
71
|
+
print("\n⏭️ 已跳过的方法 (已废弃):")
|
|
72
|
+
print(" - Grasp.shutdown()")
|
|
73
|
+
print(" - Grasp.createRunner()")
|
|
74
|
+
print("\n🎯 新功能:")
|
|
75
|
+
print(" - 支持 async with grasp.launch_context(options) as session 语法")
|
|
76
|
+
print(" - 自动管理会话生命周期")
|
|
77
|
+
print(" - 会话在退出上下文时自动关闭")
|
|
78
|
+
|
|
79
|
+
if __name__ == '__main__':
|
|
80
|
+
test_grasp_classes()
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Example demonstrating Python script execution support in Grasp SDK.
|
|
2
|
+
|
|
3
|
+
This example shows how to use the enhanced run_script method to execute
|
|
4
|
+
Python scripts alongside JavaScript in the E2B sandbox environment.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from grasp_sdk.services.sandbox import SandboxService
|
|
9
|
+
from grasp_sdk.models import ISandboxConfig
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def main():
|
|
13
|
+
"""Main example function demonstrating Python script support."""
|
|
14
|
+
|
|
15
|
+
# Configure sandbox service
|
|
16
|
+
config: ISandboxConfig = {
|
|
17
|
+
'key': 'your-api-key-here', # Replace with your actual API key
|
|
18
|
+
'timeout': 30000,
|
|
19
|
+
'workspace': 'your-workspace-id', # Replace with your workspace ID
|
|
20
|
+
'debug': True
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Create sandbox service
|
|
24
|
+
sandbox = SandboxService(config)
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
# Create and start sandbox
|
|
28
|
+
await sandbox.create_sandbox('base')
|
|
29
|
+
print("✅ Sandbox created successfully")
|
|
30
|
+
|
|
31
|
+
# Example 1: Basic Python script execution
|
|
32
|
+
print("\n🐍 Example 1: Basic Python script")
|
|
33
|
+
python_code = """
|
|
34
|
+
print("Hello from Python in E2B sandbox!")
|
|
35
|
+
print(f"Python version: {__import__('sys').version}")
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
result = await sandbox.run_script(python_code, {'type': 'py'})
|
|
39
|
+
print(f"Output: {getattr(result, 'stdout', str(result))}")
|
|
40
|
+
|
|
41
|
+
# Example 2: Python script with mathematical operations
|
|
42
|
+
print("\n🧮 Example 2: Python mathematical operations")
|
|
43
|
+
math_code = """
|
|
44
|
+
import math
|
|
45
|
+
|
|
46
|
+
# Calculate some mathematical operations
|
|
47
|
+
numbers = [1, 2, 3, 4, 5]
|
|
48
|
+
print(f"Numbers: {numbers}")
|
|
49
|
+
print(f"Sum: {sum(numbers)}")
|
|
50
|
+
print(f"Square root of 16: {math.sqrt(16)}")
|
|
51
|
+
print(f"Pi: {math.pi:.4f}")
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
result = await sandbox.run_script(math_code, {'type': 'py'})
|
|
55
|
+
print(f"Output: {getattr(result, 'stdout', str(result))}")
|
|
56
|
+
|
|
57
|
+
# Example 3: Python script with environment variables
|
|
58
|
+
print("\n🌍 Example 3: Python script with environment variables")
|
|
59
|
+
env_code = """
|
|
60
|
+
import os
|
|
61
|
+
|
|
62
|
+
print(f"Custom variable: {os.environ.get('MY_CUSTOM_VAR', 'Not set')}")
|
|
63
|
+
print(f"Python path: {os.environ.get('PYTHONPATH', 'Default')}")
|
|
64
|
+
print(f"Current working directory: {os.getcwd()}")
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
result = await sandbox.run_script(env_code, {
|
|
68
|
+
'type': 'py',
|
|
69
|
+
'envs': {
|
|
70
|
+
'MY_CUSTOM_VAR': 'Hello from environment!',
|
|
71
|
+
'PYTHONPATH': '/custom/python/path'
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
print(f"Output: {getattr(result, 'stdout', str(result))}")
|
|
75
|
+
|
|
76
|
+
# Example 4: Python script with package installation
|
|
77
|
+
print("\n📦 Example 4: Python script with package installation")
|
|
78
|
+
package_code = """
|
|
79
|
+
import requests
|
|
80
|
+
import json
|
|
81
|
+
|
|
82
|
+
# Make a simple HTTP request
|
|
83
|
+
response = requests.get('https://httpbin.org/json')
|
|
84
|
+
data = response.json()
|
|
85
|
+
print(f"HTTP Status: {response.status_code}")
|
|
86
|
+
print(f"Response data: {json.dumps(data, indent=2)}")
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
result = await sandbox.run_script(package_code, {
|
|
90
|
+
'type': 'py',
|
|
91
|
+
'preCommand': 'pip install requests && '
|
|
92
|
+
})
|
|
93
|
+
print(f"Output: {getattr(result, 'stdout', str(result))}")
|
|
94
|
+
|
|
95
|
+
# Example 5: Python script with custom working directory
|
|
96
|
+
print("\n📁 Example 5: Python script with custom working directory")
|
|
97
|
+
file_code = """
|
|
98
|
+
import os
|
|
99
|
+
|
|
100
|
+
# Create a test file
|
|
101
|
+
with open('test_file.txt', 'w') as f:
|
|
102
|
+
f.write('Hello from Python file operation!')
|
|
103
|
+
|
|
104
|
+
# Read the file back
|
|
105
|
+
with open('test_file.txt', 'r') as f:
|
|
106
|
+
content = f.read()
|
|
107
|
+
print(f"File content: {content}")
|
|
108
|
+
|
|
109
|
+
print(f"Current directory: {os.getcwd()}")
|
|
110
|
+
print(f"Files in directory: {os.listdir('.')}")
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
result = await sandbox.run_script(file_code, {
|
|
114
|
+
'type': 'py',
|
|
115
|
+
'cwd': '/home/user/python_workspace'
|
|
116
|
+
})
|
|
117
|
+
print(f"Output: {getattr(result, 'stdout', str(result))}")
|
|
118
|
+
|
|
119
|
+
# Example 6: Compare with JavaScript execution
|
|
120
|
+
print("\n🔄 Example 6: JavaScript vs Python comparison")
|
|
121
|
+
|
|
122
|
+
# JavaScript version
|
|
123
|
+
js_code = """
|
|
124
|
+
const numbers = [1, 2, 3, 4, 5];
|
|
125
|
+
const sum = numbers.reduce((a, b) => a + b, 0);
|
|
126
|
+
console.log(`JavaScript - Numbers: ${numbers}`);
|
|
127
|
+
console.log(`JavaScript - Sum: ${sum}`);
|
|
128
|
+
console.log(`JavaScript - Node version: ${process.version}`);
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
js_result = await sandbox.run_script(js_code, {'type': 'cjs'})
|
|
132
|
+
print(f"JavaScript Output: {getattr(js_result, 'stdout', str(js_result))}")
|
|
133
|
+
|
|
134
|
+
# Python version
|
|
135
|
+
py_code = """
|
|
136
|
+
numbers = [1, 2, 3, 4, 5]
|
|
137
|
+
total = sum(numbers)
|
|
138
|
+
print(f"Python - Numbers: {numbers}")
|
|
139
|
+
print(f"Python - Sum: {total}")
|
|
140
|
+
print(f"Python - Version: {__import__('sys').version.split()[0]}")
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
py_result = await sandbox.run_script(py_code, {'type': 'py'})
|
|
144
|
+
print(f"Python Output: {getattr(py_result, 'stdout', str(py_result))}")
|
|
145
|
+
|
|
146
|
+
print("\n✅ All examples completed successfully!")
|
|
147
|
+
|
|
148
|
+
except Exception as error:
|
|
149
|
+
print(f"❌ Error: {error}")
|
|
150
|
+
|
|
151
|
+
finally:
|
|
152
|
+
# Clean up sandbox
|
|
153
|
+
await sandbox.destroy()
|
|
154
|
+
print("\n🧹 Sandbox destroyed")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
# Run the example
|
|
159
|
+
print("🚀 Starting Python script execution examples...")
|
|
160
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
测试已删除方法的验证脚本
|
|
4
|
+
|
|
5
|
+
验证 create_terminal 和 create_filesystem 方法已被正确移除。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
# 添加父目录到路径
|
|
12
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
13
|
+
|
|
14
|
+
def test_removed_methods():
|
|
15
|
+
"""测试已删除的方法不再可用"""
|
|
16
|
+
print("🧪 测试已删除方法的验证")
|
|
17
|
+
print("=" * 30)
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from grasp_sdk import Grasp, GraspSession, GraspBrowser, GraspTerminal
|
|
21
|
+
print("✅ 核心类导入成功")
|
|
22
|
+
except ImportError as e:
|
|
23
|
+
print(f"❌ 核心类导入失败: {e}")
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
# 测试 create_terminal 方法不存在(预期 ImportError)
|
|
27
|
+
try:
|
|
28
|
+
# 这行代码预期会失败,因为方法已被删除
|
|
29
|
+
from grasp_sdk import create_terminal # type: ignore
|
|
30
|
+
print("❌ create_terminal 方法仍然存在(应该已被删除)")
|
|
31
|
+
return False
|
|
32
|
+
except ImportError:
|
|
33
|
+
print("✅ create_terminal 方法已成功删除")
|
|
34
|
+
|
|
35
|
+
# 测试 create_filesystem 方法不存在(预期 ImportError)
|
|
36
|
+
try:
|
|
37
|
+
# 这行代码预期会失败,因为方法已被删除
|
|
38
|
+
from grasp_sdk import create_filesystem # type: ignore
|
|
39
|
+
print("❌ create_filesystem 方法仍然存在(应该已被删除)")
|
|
40
|
+
return False
|
|
41
|
+
except ImportError:
|
|
42
|
+
print("✅ create_filesystem 方法已成功删除")
|
|
43
|
+
|
|
44
|
+
# 验证 GraspSession 仍然提供 terminal 和 files 属性
|
|
45
|
+
print("\n📋 验证 GraspSession 的替代功能:")
|
|
46
|
+
print(" - session.terminal (替代 create_terminal)")
|
|
47
|
+
print(" - session.files (替代 create_filesystem)")
|
|
48
|
+
|
|
49
|
+
# 检查 __all__ 列表
|
|
50
|
+
try:
|
|
51
|
+
import grasp_sdk
|
|
52
|
+
all_exports = grasp_sdk.__all__
|
|
53
|
+
|
|
54
|
+
if 'create_terminal' in all_exports:
|
|
55
|
+
print("❌ create_terminal 仍在 __all__ 列表中")
|
|
56
|
+
return False
|
|
57
|
+
else:
|
|
58
|
+
print("✅ create_terminal 已从 __all__ 列表中移除")
|
|
59
|
+
|
|
60
|
+
if 'create_filesystem' in all_exports:
|
|
61
|
+
print("❌ create_filesystem 仍在 __all__ 列表中")
|
|
62
|
+
return False
|
|
63
|
+
else:
|
|
64
|
+
print("✅ create_filesystem 已从 __all__ 列表中移除")
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print(f"⚠️ 检查 __all__ 列表时出错: {e}")
|
|
68
|
+
|
|
69
|
+
print("\n🎉 所有验证通过!create_terminal 和 create_filesystem 方法已成功移除")
|
|
70
|
+
print("\n💡 使用建议:")
|
|
71
|
+
print(" - 使用 session.terminal 替代 create_terminal(connection)")
|
|
72
|
+
print(" - 使用 session.files 替代 create_filesystem(connection)")
|
|
73
|
+
|
|
74
|
+
return True
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
success = test_removed_methods()
|
|
78
|
+
if not success:
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
print("\n✅ 测试完成")
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
测试 shutdown 方法的废弃警告
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import warnings
|
|
7
|
+
import sys
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
# 添加项目路径
|
|
11
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
12
|
+
|
|
13
|
+
from grasp_sdk import shutdown
|
|
14
|
+
|
|
15
|
+
def test_shutdown_deprecation():
|
|
16
|
+
"""测试 shutdown 方法是否正确发出废弃警告"""
|
|
17
|
+
print("🧪 测试 shutdown 方法的废弃警告...")
|
|
18
|
+
|
|
19
|
+
# 设置警告过滤器显示所有警告
|
|
20
|
+
warnings.filterwarnings("always")
|
|
21
|
+
|
|
22
|
+
# 捕获警告
|
|
23
|
+
with warnings.catch_warnings(record=True) as w:
|
|
24
|
+
warnings.simplefilter("always")
|
|
25
|
+
|
|
26
|
+
print("📞 调用 shutdown(None)...")
|
|
27
|
+
|
|
28
|
+
# 调用废弃的 shutdown 方法
|
|
29
|
+
try:
|
|
30
|
+
shutdown(None)
|
|
31
|
+
print("✅ shutdown 方法调用完成")
|
|
32
|
+
except SystemExit:
|
|
33
|
+
print("⚠️ shutdown 方法触发了系统退出")
|
|
34
|
+
except Exception as e:
|
|
35
|
+
print(f"⚠️ shutdown 方法调用出现异常: {e}")
|
|
36
|
+
|
|
37
|
+
# 检查是否有废弃警告
|
|
38
|
+
print(f"\n📊 捕获到 {len(w)} 个警告")
|
|
39
|
+
deprecation_warnings = [warning for warning in w if issubclass(warning.category, DeprecationWarning)]
|
|
40
|
+
|
|
41
|
+
if deprecation_warnings:
|
|
42
|
+
print(f"✅ 检测到 {len(deprecation_warnings)} 个废弃警告:")
|
|
43
|
+
for warning in deprecation_warnings:
|
|
44
|
+
print(f" - {warning.message}")
|
|
45
|
+
print(f" 文件: {warning.filename}:{warning.lineno}")
|
|
46
|
+
else:
|
|
47
|
+
print("❌ 未检测到废弃警告")
|
|
48
|
+
if w:
|
|
49
|
+
print("其他警告:")
|
|
50
|
+
for warning in w:
|
|
51
|
+
print(f" - {warning.category.__name__}: {warning.message}")
|
|
52
|
+
|
|
53
|
+
print("\n📋 废弃方法迁移指南:")
|
|
54
|
+
print(" 旧方式: shutdown(connection)")
|
|
55
|
+
print(" 新方式: await session.close()")
|
|
56
|
+
print("\n💡 建议:")
|
|
57
|
+
print(" - 使用 grasp.launch() 获取 session")
|
|
58
|
+
print(" - 使用 await session.close() 关闭会话")
|
|
59
|
+
print(" - 避免直接使用 shutdown() 方法")
|
|
60
|
+
|
|
61
|
+
if __name__ == '__main__':
|
|
62
|
+
test_shutdown_deprecation()
|