grasp-sdk 0.2.0b2__tar.gz → 0.2.0b3__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.

Potentially problematic release.


This version of grasp-sdk might be problematic. Click here for more details.

Files changed (45) hide show
  1. {grasp_sdk-0.2.0b2/grasp_sdk.egg-info → grasp_sdk-0.2.0b3}/PKG-INFO +1 -1
  2. grasp_sdk-0.2.0b3/examples/grasp-mouse-usage-2.py +151 -0
  3. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/test_terminal_updates.py +2 -2
  4. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/__init__.py +1 -2
  5. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/grasp/server.py +2 -0
  6. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/models/__init__.py +2 -2
  7. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/services/browser.py +1 -1
  8. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/services/sandbox.py +6 -6
  9. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3/grasp_sdk.egg-info}/PKG-INFO +1 -1
  10. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk.egg-info/SOURCES.txt +2 -0
  11. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk.egg-info/top_level.txt +1 -0
  12. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/pyproject.toml +1 -1
  13. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/MANIFEST.in +0 -0
  14. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/README.md +0 -0
  15. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/build_and_publish.py +0 -0
  16. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/example_async_context.py +0 -0
  17. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/example_binary_file_support.py +0 -0
  18. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/example_grasp_usage.py +0 -0
  19. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/example_readfile_usage.py +0 -0
  20. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/grasp_terminal.py +0 -0
  21. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/grasp_usage.py +0 -0
  22. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/test_async_context.py +0 -0
  23. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/test_grasp_classes.py +0 -0
  24. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/test_python_script.py +0 -0
  25. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/examples/test_removed_methods.py +0 -0
  26. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/grasp/__init__.py +0 -0
  27. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/grasp/browser.py +0 -0
  28. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/grasp/index.py +0 -0
  29. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/grasp/session.py +0 -0
  30. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/grasp/utils.py +0 -0
  31. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/services/__init__.py +0 -0
  32. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/services/filesystem.py +0 -0
  33. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/services/terminal.py +0 -0
  34. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/utils/__init__.py +0 -0
  35. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/utils/auth.py +0 -0
  36. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/utils/config.py +0 -0
  37. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk/utils/logger.py +0 -0
  38. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk.egg-info/dependency_links.txt +0 -0
  39. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk.egg-info/entry_points.txt +0 -0
  40. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk.egg-info/not-zip-safe +0 -0
  41. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/grasp_sdk.egg-info/requires.txt +0 -0
  42. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/py.typed +0 -0
  43. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/requirements.txt +0 -0
  44. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/setup.cfg +0 -0
  45. {grasp_sdk-0.2.0b2 → grasp_sdk-0.2.0b3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grasp_sdk
3
- Version: 0.2.0b2
3
+ Version: 0.2.0b3
4
4
  Summary: Python SDK for Grasp E2B - Browser automation and sandbox management
5
5
  Home-page: https://github.com/grasp-team/grasp-e2b
6
6
  Author: Grasp Team
@@ -0,0 +1,151 @@
1
+ import asyncio
2
+ import subprocess
3
+
4
+ import sys
5
+ from pathlib import Path
6
+ from dotenv import load_dotenv
7
+
8
+ # 添加父目录到 Python 路径,以便导入 grasp_sdk
9
+ sys.path.insert(0, str(Path(__file__).parent.parent))
10
+
11
+ from grasp_sdk import Grasp
12
+ from playwright.async_api import async_playwright
13
+ import math
14
+
15
+ # 加载环境变量
16
+ load_dotenv("../.env.grasp")
17
+
18
+ async def main():
19
+ grasp = Grasp()
20
+
21
+ session = await grasp.launch({
22
+ "browser": {
23
+ # "type": "chrome-stable",
24
+ "headless": False,
25
+ # "args": [
26
+ # "--enable-webgl",
27
+ # "--ignore-gpu-blacklist",
28
+ # "--use-gl=swiftshader",
29
+ # "--headless=false",
30
+ # ],
31
+ # "adblock": True,
32
+ "liveview": True,
33
+ },
34
+ "debug": True,
35
+ "keepAliveMS": 10000,
36
+ "timeout": 3600000,
37
+ })
38
+
39
+ terminal = session.terminal
40
+ # response = await terminal.run_command(
41
+ # # "node -e \"console.log(process.env)\""
42
+ # "Xvfb :1 -screen 0 1024x768x24 & export DISPLAY=:1 && glxinfo | grep \"OpenGL renderer\""
43
+ # )
44
+ # response.stdout.pipe(process.stdout)
45
+ # response.stderr.pipe(process.stderr)
46
+ # print(await response.json())
47
+
48
+ # await session.files.download_file(
49
+ # "/home/user/.env.json",
50
+ # "./output/.env.json"
51
+ # )
52
+
53
+ ws_url = session.browser.get_endpoint()
54
+ print(ws_url)
55
+
56
+ async with async_playwright() as p:
57
+ browser = await p.chromium.connect_over_cdp(ws_url, timeout=150000)
58
+
59
+ url = await session.browser.get_liveview_page_url()
60
+ if url:
61
+ # 使用 subprocess 打开 URL(替代 Node.js 的 open 包)
62
+ subprocess.run(["open", url]) # macOS
63
+ # subprocess.run(["xdg-open", url]) # Linux
64
+ # subprocess.run(["start", url], shell=True) # Windows
65
+
66
+ page = await browser.new_page()
67
+
68
+ # 打开一个可以玩拖拽的网页
69
+ await page.goto("https://the-internet.herokuapp.com/drag_and_drop")
70
+
71
+ box_a = page.locator("#column-a")
72
+ box_b = page.locator("#column-b")
73
+
74
+ box_a_box = await box_a.bounding_box()
75
+ box_b_box = await box_b.bounding_box()
76
+
77
+ if not box_a_box or not box_b_box:
78
+ raise Exception("Could not get bounding boxes for elements")
79
+
80
+ mouse = page.mouse
81
+
82
+ # 🎯 Step 1: 炫技滑动到 Box A
83
+ await mouse.move(0, 0, steps=20)
84
+ await mouse.move(box_a_box["x"] + 30, box_a_box["y"] + 30, steps=40)
85
+
86
+ # ⚡ Step 2: 快速点击一次
87
+ await mouse.click(box_a_box["x"] + 30, box_a_box["y"] + 30)
88
+
89
+ # 🧲 Step 3: 拖拽 Box A 到 Box B
90
+ await mouse.move(box_a_box["x"] + 30, box_a_box["y"] + 30)
91
+ await mouse.down()
92
+ await mouse.move(box_b_box["x"] + 30, box_b_box["y"] + 30, steps=50)
93
+ await mouse.up()
94
+
95
+ # 🎡 Step 4: 鼠标绕 Box B 旋转一圈
96
+ center_x = box_b_box["x"] + box_b_box["width"] / 2
97
+ center_y = box_b_box["y"] + box_b_box["height"] / 2
98
+ radius = 40
99
+ for angle in range(0, 361, 10):
100
+ rad = (angle * math.pi) / 180
101
+ x = center_x + radius * math.cos(rad)
102
+ y = center_y + radius * math.sin(rad)
103
+ await mouse.move(x, y)
104
+
105
+ # 👋 Step 5: 优雅滑出屏幕
106
+ await mouse.move(center_x + 100, center_y + 500, steps=30)
107
+
108
+ # 下载liveview 截屏
109
+ # screenshots_dir = await session.browser.get_replay_screenshots()
110
+ # print(screenshots_dir)
111
+
112
+ command = await terminal.run_command(
113
+ "cd /home/user/downloads/grasp-screenshots && ls -1 | grep -v '^filelist.txt$' | sort | awk '{print \"file '\\''\" $0 \"'\\''\"}' > filelist.txt"
114
+ )
115
+ await command.end()
116
+
117
+ command2 = await terminal.run_command(
118
+ "cd /home/user/downloads/grasp-screenshots && ffmpeg -r 25 -f concat -safe 0 -i filelist.txt -vsync vfr -pix_fmt yuv420p output.mp4"
119
+ )
120
+
121
+ # Python 中处理流输出的方式
122
+ def handle_stdout(data):
123
+ print(data, end="")
124
+
125
+ def handle_stderr(data):
126
+ print(data, end="")
127
+
128
+ # 注册事件处理器
129
+ command2.on('stdout', handle_stdout)
130
+ command2.on('stderr', handle_stderr)
131
+
132
+ await command2.end()
133
+
134
+ # 创建 ./output 目录
135
+ Path("./output").mkdir(parents=True, exist_ok=True)
136
+
137
+ await asyncio.gather(
138
+ session.files.download_file(
139
+ "/home/user/downloads/grasp-screenshots/filelist.txt",
140
+ "./output/filelist.txt"
141
+ ),
142
+ session.files.download_file(
143
+ "/home/user/downloads/grasp-screenshots/output.mp4",
144
+ "./output/output.mp4"
145
+ ),
146
+ )
147
+
148
+ await session.close()
149
+
150
+ if __name__ == "__main__":
151
+ asyncio.run(main())
@@ -111,7 +111,7 @@ async def test_terminal_service():
111
111
  mock_sandbox.run_command.return_value = mock_emitter
112
112
 
113
113
  # Test run_command
114
- result = await terminal.run_command('echo "Hello World"', {'timeout_ms': 5000})
114
+ result = await terminal.run_command('echo "Hello World"', {'timeoutMs': 5000})
115
115
  print("✓ run_command executed successfully")
116
116
 
117
117
  # Verify the command was called with correct options
@@ -152,7 +152,7 @@ async def test_command_options_compatibility():
152
152
  # Test that ICommandOptions supports 'inBackground' parameter
153
153
  options: ICommandOptions = {
154
154
  'inBackground': True,
155
- 'timeout_ms': 5000,
155
+ 'timeoutMs': 5000,
156
156
  'cwd': '/tmp',
157
157
  'nohup': False
158
158
  }
@@ -25,7 +25,7 @@ from .grasp import (
25
25
  # Import CDPConnection for type annotation
26
26
  from .services.browser import CDPConnection
27
27
 
28
- __version__ = "0.2.0b2"
28
+ __version__ = "0.2.0b3"
29
29
  __author__ = "Grasp Team"
30
30
  __email__ = "team@grasp.dev"
31
31
 
@@ -165,7 +165,6 @@ __all__ = [
165
165
  'Grasp',
166
166
  'GraspSession',
167
167
  'GraspBrowser',
168
- 'GraspTerminal',
169
168
  'launch_browser',
170
169
  'shutdown',
171
170
  ]
@@ -30,6 +30,7 @@ class GraspServer:
30
30
  browser_type = sandbox_config.pop('type', 'chromium')
31
31
  headless = sandbox_config.pop('headless', True)
32
32
  adblock = sandbox_config.pop('adblock', False)
33
+ liveview = sandbox_config.pop('liveview', False)
33
34
  logLevel = sandbox_config.pop('logLevel', '')
34
35
  keepAliveMS = sandbox_config.pop('keepAliveMS', 0)
35
36
 
@@ -45,6 +46,7 @@ class GraspServer:
45
46
  'envs': {
46
47
  'ADBLOCK': 'true' if adblock else 'false',
47
48
  'KEEP_ALIVE_MS': str(keepAliveMS),
49
+ 'ENABLE_LIVEVIEW': 'true' if liveview else 'false',
48
50
  }
49
51
  }
50
52
 
@@ -37,7 +37,7 @@ class IBrowserConfig(TypedDict):
37
37
  class ICommandOptions(TypedDict):
38
38
  """Command execution options interface."""
39
39
  inBackground: NotRequired[bool] # Whether to run command in background (corresponds to 'background' in TypeScript)
40
- timeout_ms: NotRequired[int] # Timeout in milliseconds (corresponds to 'timeoutMs' in TypeScript)
40
+ timeoutMs: NotRequired[int] # Timeout in milliseconds (corresponds to 'timeoutMs' in TypeScript)
41
41
  cwd: NotRequired[str] # Working directory
42
42
  user: NotRequired[str] # User to run the command as (default: 'user')
43
43
  envs: NotRequired[Dict[str, str]] # Environment variables for the command
@@ -49,7 +49,7 @@ class IScriptOptions(TypedDict):
49
49
  """Script execution options interface."""
50
50
  type: str # Required: Script type: 'cjs' for CommonJS, 'esm' for ES Modules, 'py' for Python
51
51
  cwd: NotRequired[str] # Working directory
52
- timeout_ms: NotRequired[int] # Timeout in milliseconds
52
+ timeoutMs: NotRequired[int] # Timeout in milliseconds
53
53
  background: NotRequired[bool] # Run in background
54
54
  user: NotRequired[str] # User to run the script as (default: 'user')
55
55
  nohup: NotRequired[bool] # Use nohup for background execution (Grasp-specific extension)
@@ -186,7 +186,7 @@ class BrowserService:
186
186
  'type': 'esm',
187
187
  'background': True,
188
188
  'nohup': not self.sandbox_service.is_debug,
189
- 'timeout_ms': 0,
189
+ 'timeoutMs': 0,
190
190
  'preCommand': ''
191
191
  }
192
192
 
@@ -286,7 +286,7 @@ class SandboxService:
286
286
  options = {}
287
287
 
288
288
  cwd = options.get('cwd', self.DEFAULT_WORKING_DIRECTORY)
289
- timeout_ms = options.get('timeout_ms', 0)
289
+ timeoutMs = options.get('timeoutMs', 0)
290
290
  use_nohup = options.get('nohup', False)
291
291
  in_background = options.get('inBackground', False)
292
292
  envs = options.get('envs', {})
@@ -299,7 +299,7 @@ class SandboxService:
299
299
  self.logger.debug('Running command in sandbox', {
300
300
  'command': command,
301
301
  'cwd': cwd,
302
- 'timeout': timeout_ms,
302
+ 'timeout': timeoutMs,
303
303
  'nohup': use_nohup,
304
304
  'background': in_background
305
305
  })
@@ -319,7 +319,7 @@ class SandboxService:
319
319
  result = await self.sandbox.commands.run(
320
320
  final_command,
321
321
  cwd=cwd,
322
- timeout=timeout_ms // 1000,
322
+ timeout=timeoutMs // 1000,
323
323
  envs=envs,
324
324
  background=in_background,
325
325
  user=user,
@@ -345,7 +345,7 @@ class SandboxService:
345
345
  await self.sandbox.commands.run(
346
346
  nohup_command,
347
347
  cwd=cwd,
348
- timeout=timeout_ms // 1000,
348
+ timeout=timeoutMs // 1000,
349
349
  envs=envs,
350
350
  background=in_background,
351
351
  user=user,
@@ -365,7 +365,7 @@ class SandboxService:
365
365
  handle = await commands_attr.run(
366
366
  command,
367
367
  cwd=cwd,
368
- timeout=timeout_ms // 1000,
368
+ timeout=timeoutMs // 1000,
369
369
  background=True,
370
370
  envs=envs,
371
371
  user=user,
@@ -473,7 +473,7 @@ class SandboxService:
473
473
  # Prepare command options
474
474
  cmd_options: Optional[Any] = {
475
475
  'cwd': options.get('cwd'),
476
- 'timeout_ms': options.get('timeout_ms', 0),
476
+ 'timeoutMs': options.get('timeoutMs', 0),
477
477
  'inBackground': options.get('background', False),
478
478
  'nohup': options.get('nohup', False),
479
479
  'envs': envs,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grasp_sdk
3
- Version: 0.2.0b2
3
+ Version: 0.2.0b3
4
4
  Summary: Python SDK for Grasp E2B - Browser automation and sandbox management
5
5
  Home-page: https://github.com/grasp-team/grasp-e2b
6
6
  Author: Grasp Team
@@ -12,6 +12,7 @@ setup.py
12
12
  ./examples/example_binary_file_support.py
13
13
  ./examples/example_grasp_usage.py
14
14
  ./examples/example_readfile_usage.py
15
+ ./examples/grasp-mouse-usage-2.py
15
16
  ./examples/grasp_terminal.py
16
17
  ./examples/grasp_usage.py
17
18
  ./examples/test_async_context.py
@@ -40,6 +41,7 @@ examples/example_async_context.py
40
41
  examples/example_binary_file_support.py
41
42
  examples/example_grasp_usage.py
42
43
  examples/example_readfile_usage.py
44
+ examples/grasp-mouse-usage-2.py
43
45
  examples/grasp_terminal.py
44
46
  examples/grasp_usage.py
45
47
  examples/test_async_context.py
@@ -1,3 +1,4 @@
1
1
  dist
2
2
  examples
3
3
  grasp_sdk
4
+ output
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "grasp_sdk"
7
- version = "0.2.0b2"
7
+ version = "0.2.0b3"
8
8
  authors = [
9
9
  {name = "Grasp Team", email = "team@grasp.com"},
10
10
  ]
File without changes
File without changes
File without changes
File without changes
File without changes