grasp-sdk 0.1.4__tar.gz → 0.2.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.

Potentially problematic release.


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

Files changed (60) hide show
  1. grasp_sdk-0.2.0/PKG-INFO +291 -0
  2. grasp_sdk-0.2.0/README.md +246 -0
  3. grasp_sdk-0.2.0/RELEASE.md +109 -0
  4. grasp_sdk-0.2.0/TESTING.md +55 -0
  5. grasp_sdk-0.2.0/debug_test.py +67 -0
  6. grasp_sdk-0.2.0/examples/async_usage.py +69 -0
  7. grasp_sdk-0.2.0/examples/basic_usage.py +57 -0
  8. grasp_sdk-0.2.0/examples/playwright_integration.py +86 -0
  9. grasp_sdk-0.2.0/package.json +29 -0
  10. grasp_sdk-0.2.0/publish.sh +91 -0
  11. grasp_sdk-0.2.0/pyproject.toml +127 -0
  12. grasp_sdk-0.2.0/run_tests.sh +58 -0
  13. grasp_sdk-0.2.0/src/grasp/__init__.py +80 -0
  14. grasp_sdk-0.2.0/src/grasp/_async_client.py +141 -0
  15. grasp_sdk-0.2.0/src/grasp/_browser.py +38 -0
  16. grasp_sdk-0.2.0/src/grasp/_client.py +135 -0
  17. grasp_sdk-0.2.0/src/grasp/_container.py +222 -0
  18. grasp_sdk-0.2.0/src/grasp/_exceptions.py +156 -0
  19. grasp_sdk-0.2.0/src/grasp/_http.py +195 -0
  20. grasp_sdk-0.2.0/src/grasp/_models.py +47 -0
  21. grasp_sdk-0.2.0/src/grasp/_types.py +26 -0
  22. grasp_sdk-0.2.0/src/grasp/_version.py +3 -0
  23. grasp_sdk-0.2.0/src/grasp/py.typed +0 -0
  24. grasp_sdk-0.2.0/src/grasp_sdk.egg-info/PKG-INFO +291 -0
  25. grasp_sdk-0.2.0/src/grasp_sdk.egg-info/SOURCES.txt +31 -0
  26. grasp_sdk-0.2.0/src/grasp_sdk.egg-info/requires.txt +23 -0
  27. grasp_sdk-0.2.0/src/grasp_sdk.egg-info/top_level.txt +1 -0
  28. grasp_sdk-0.2.0/test_cleanup.py +56 -0
  29. grasp_sdk-0.2.0/tests/conftest.py +83 -0
  30. grasp_sdk-0.2.0/tests/test_async_client.py +308 -0
  31. grasp_sdk-0.2.0/tests/test_client.py +286 -0
  32. grasp_sdk-0.1.4/MANIFEST.in +0 -30
  33. grasp_sdk-0.1.4/PKG-INFO +0 -307
  34. grasp_sdk-0.1.4/README.md +0 -260
  35. grasp_sdk-0.1.4/build_and_publish.py +0 -135
  36. grasp_sdk-0.1.4/example_usage.py +0 -101
  37. grasp_sdk-0.1.4/grasp_sdk/__init__.py +0 -296
  38. grasp_sdk-0.1.4/grasp_sdk/models/__init__.py +0 -78
  39. grasp_sdk-0.1.4/grasp_sdk/sandbox/chrome-stable.mjs +0 -394
  40. grasp_sdk-0.1.4/grasp_sdk/sandbox/chromium.mjs +0 -389
  41. grasp_sdk-0.1.4/grasp_sdk/services/__init__.py +0 -8
  42. grasp_sdk-0.1.4/grasp_sdk/services/browser.py +0 -405
  43. grasp_sdk-0.1.4/grasp_sdk/services/sandbox.py +0 -586
  44. grasp_sdk-0.1.4/grasp_sdk/utils/__init__.py +0 -31
  45. grasp_sdk-0.1.4/grasp_sdk/utils/auth.py +0 -227
  46. grasp_sdk-0.1.4/grasp_sdk/utils/config.py +0 -150
  47. grasp_sdk-0.1.4/grasp_sdk/utils/logger.py +0 -233
  48. grasp_sdk-0.1.4/grasp_sdk.egg-info/PKG-INFO +0 -307
  49. grasp_sdk-0.1.4/grasp_sdk.egg-info/SOURCES.txt +0 -41
  50. grasp_sdk-0.1.4/grasp_sdk.egg-info/entry_points.txt +0 -2
  51. grasp_sdk-0.1.4/grasp_sdk.egg-info/not-zip-safe +0 -1
  52. grasp_sdk-0.1.4/grasp_sdk.egg-info/requires.txt +0 -21
  53. grasp_sdk-0.1.4/grasp_sdk.egg-info/top_level.txt +0 -2
  54. grasp_sdk-0.1.4/py.typed +0 -2
  55. grasp_sdk-0.1.4/pyproject.toml +0 -127
  56. grasp_sdk-0.1.4/requirements.txt +0 -15
  57. grasp_sdk-0.1.4/setup.py +0 -79
  58. grasp_sdk-0.1.4/test_install.py +0 -87
  59. {grasp_sdk-0.1.4 → grasp_sdk-0.2.0}/setup.cfg +0 -0
  60. {grasp_sdk-0.1.4 → grasp_sdk-0.2.0/src}/grasp_sdk.egg-info/dependency_links.txt +0 -0
@@ -0,0 +1,291 @@
1
+ Metadata-Version: 2.4
2
+ Name: grasp-sdk
3
+ Version: 0.2.0
4
+ Summary: Official Python SDK for the Grasp browser automation platform
5
+ Author-email: Grasp Team <dev@getgrasp.ai>
6
+ License: MIT
7
+ Project-URL: Homepage, https://getgrasp.ai
8
+ Project-URL: Documentation, https://docs.getgrasp.ai
9
+ Project-URL: Repository, https://github.com/getgrasp-ai/grasp
10
+ Project-URL: Issues, https://github.com/getgrasp-ai/grasp/issues
11
+ Keywords: browser,automation,chrome,devtools,cdp,playwright,puppeteer
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Intended Audience :: Developers
20
+ Classifier: License :: OSI Approved :: MIT License
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: httpx>=0.24.0
26
+ Requires-Dist: pydantic>=2.0
27
+ Requires-Dist: pydantic-core>=2.0
28
+ Requires-Dist: python-dateutil>=2.8
29
+ Requires-Dist: typing-extensions>=4.0; python_version < "3.10"
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7.0; extra == "dev"
32
+ Requires-Dist: pytest-asyncio>=0.20; extra == "dev"
33
+ Requires-Dist: pytest-httpx>=0.22; extra == "dev"
34
+ Requires-Dist: pytest-sugar>=0.9.7; extra == "dev"
35
+ Requires-Dist: pytest-watch>=4.2.0; extra == "dev"
36
+ Requires-Dist: pytest-xdist>=3.0; extra == "dev"
37
+ Requires-Dist: rich>=13.0; extra == "dev"
38
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
39
+ Requires-Dist: playwright>=1.40; extra == "dev"
40
+ Requires-Dist: black>=23.0; extra == "dev"
41
+ Requires-Dist: mypy>=1.0; extra == "dev"
42
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
43
+ Requires-Dist: build>=0.10; extra == "dev"
44
+ Requires-Dist: twine>=4.0; extra == "dev"
45
+
46
+ # Grasp Python SDK
47
+
48
+ Official Python SDK for the Grasp browser automation platform.
49
+
50
+ ## Features
51
+
52
+ - **Dual Client Architecture**: Both synchronous and asynchronous clients
53
+ - **Type Safety**: Full type hints and Pydantic models for validation
54
+ - **Browser Automation**: Seamless integration with Playwright and Puppeteer
55
+ - **Proxy Support**: Built-in proxy configuration for different use cases
56
+ - **Error Handling**: Comprehensive exception hierarchy
57
+ - **Auto-retry**: Automatic retry with exponential backoff
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ pip install grasp-sdk
63
+ ```
64
+
65
+ ## Quick Start
66
+
67
+ ### Synchronous Usage
68
+
69
+ ```python
70
+ from grasp import Grasp
71
+
72
+ # Initialize client
73
+ client = Grasp(api_key="your-api-key") # or set GRASP_API_KEY env var
74
+
75
+ # Create a container
76
+ container = client.create(
77
+ idle_timeout=30000, # 30 seconds
78
+ proxy={
79
+ "enabled": True,
80
+ "type": "residential",
81
+ "country": "US"
82
+ }
83
+ )
84
+
85
+ # Access browser information
86
+ print(f"Container ID: {container.id}")
87
+ print(f"CDP WebSocket: {container.browser.ws_endpoint}")
88
+ print(f"Live View: {container.browser.live_url}")
89
+
90
+ # Shutdown when done
91
+ container.shutdown()
92
+ ```
93
+
94
+ ### Asynchronous Usage
95
+
96
+ ```python
97
+ import asyncio
98
+ from grasp import AsyncGrasp
99
+
100
+ async def main():
101
+ # Use context manager for automatic cleanup
102
+ async with AsyncGrasp(api_key="your-api-key") as client:
103
+ # Create container
104
+ container = await client.create(idle_timeout=30000)
105
+
106
+ # Use the container
107
+ print(f"Container ID: {container.id}")
108
+
109
+ # Shutdown
110
+ await container.shutdown()
111
+
112
+ asyncio.run(main())
113
+ ```
114
+
115
+ ### Playwright Integration
116
+
117
+ ```python
118
+ from grasp import Grasp
119
+ from playwright.sync_api import sync_playwright
120
+
121
+ # Create Grasp container
122
+ grasp = Grasp()
123
+ container = grasp.create()
124
+
125
+ # Connect Playwright
126
+ with sync_playwright() as p:
127
+ browser = p.chromium.connect_over_cdp(container.browser.ws_endpoint)
128
+ page = browser.new_page()
129
+ page.goto("https://example.com")
130
+
131
+ # Your automation code here
132
+ title = page.title()
133
+ print(f"Page title: {title}")
134
+
135
+ browser.close()
136
+
137
+ # Cleanup
138
+ container.shutdown()
139
+ ```
140
+
141
+ ## Configuration
142
+
143
+ ### Environment Variables
144
+
145
+ - `GRASP_API_KEY`: Your API key (alternative to passing in code)
146
+ - `GRASP_BASE_URL`: API base URL (defaults to `https://api.getgrasp.ai`)
147
+
148
+ ### Client Options
149
+
150
+ ```python
151
+ client = Grasp(
152
+ api_key="your-api-key",
153
+ base_url="https://api.getgrasp.ai", # optional
154
+ timeout=60.0, # request timeout in seconds
155
+ max_retries=2 # maximum retry attempts
156
+ )
157
+ ```
158
+
159
+ ### Container Options
160
+
161
+ ```python
162
+ container = client.create(
163
+ idle_timeout=30000, # milliseconds before container sleeps
164
+ proxy={
165
+ "enabled": True,
166
+ "type": "residential", # mobile, residential, isp, datacenter, custom
167
+ "country": "US", # optional: country code
168
+ "state": "CA", # optional: state code
169
+ "city": "LA" # optional: city name
170
+ }
171
+ )
172
+ ```
173
+
174
+ ## API Reference
175
+
176
+ ### Main Classes
177
+
178
+ #### `Grasp` / `AsyncGrasp`
179
+ Main client classes for interacting with the API.
180
+
181
+ **Methods:**
182
+ - `create(**options)`: Create a new container
183
+ - `connect(container_id)`: Connect to existing container
184
+
185
+ #### `GraspContainer` / `AsyncGraspContainer`
186
+ Represents a browser automation container.
187
+
188
+ **Properties:**
189
+ - `id`: Container identifier
190
+ - `status`: Current status (running, stopped, sleeping)
191
+ - `created_at`: Creation timestamp
192
+ - `browser`: Browser session information
193
+
194
+ **Methods:**
195
+ - `shutdown()`: Shut down the container
196
+
197
+ #### `BrowserSession`
198
+ Browser session information.
199
+
200
+ **Properties:**
201
+ - `ws_endpoint`: Chrome DevTools Protocol WebSocket endpoint
202
+ - `live_url`: Live view URL for observing the browser
203
+
204
+ ### Exception Handling
205
+
206
+ ```python
207
+ from grasp import (
208
+ GraspError,
209
+ AuthenticationError,
210
+ NotFoundError,
211
+ RateLimitError
212
+ )
213
+
214
+ try:
215
+ container = client.create()
216
+ except AuthenticationError:
217
+ print("Invalid API key")
218
+ except RateLimitError as e:
219
+ print(f"Rate limited. Retry after: {e.retry_after}")
220
+ except GraspError as e:
221
+ print(f"API error: {e}")
222
+ ```
223
+
224
+ ### Exception Hierarchy
225
+
226
+ - `GraspError`: Base exception
227
+ - `APIError`: API-related errors
228
+ - `APIStatusError`: HTTP status errors
229
+ - `AuthenticationError`: 401 Unauthorized
230
+ - `NotFoundError`: 404 Not Found
231
+ - `RateLimitError`: 429 Rate Limited
232
+ - `InternalServerError`: 500 Server Error
233
+ - `APIConnectionError`: Network issues
234
+ - `APITimeoutError`: Request timeout
235
+
236
+ ## Examples
237
+
238
+ See the [examples](examples/) directory for more detailed examples:
239
+
240
+ - [basic_usage.py](examples/basic_usage.py): Simple synchronous usage
241
+ - [async_usage.py](examples/async_usage.py): Async with multiple containers
242
+ - [playwright_integration.py](examples/playwright_integration.py): Full Playwright integration
243
+
244
+ ## Development
245
+
246
+ ### Setup Development Environment
247
+
248
+ ```bash
249
+ # Clone the repository
250
+ git clone https://github.com/getgrasp-ai/grasp.git
251
+ cd grasp/packages/python-sdk
252
+
253
+ # Install dependencies
254
+ pip install -e ".[dev]"
255
+ ```
256
+
257
+ ### Run Tests
258
+
259
+ ```bash
260
+ # Run all tests
261
+ pytest
262
+
263
+ # Run with coverage
264
+ pytest --cov=grasp
265
+
266
+ # Run specific test file
267
+ pytest tests/test_client.py
268
+ ```
269
+
270
+ ### Code Quality
271
+
272
+ ```bash
273
+ # Format code
274
+ black src/ tests/
275
+
276
+ # Lint
277
+ ruff check src/ tests/
278
+
279
+ # Type check
280
+ mypy src/
281
+ ```
282
+
283
+ ## Requirements
284
+
285
+ - Python 3.8+
286
+ - httpx >= 0.24.0
287
+ - pydantic >= 2.0
288
+
289
+ ## License
290
+
291
+ MIT
@@ -0,0 +1,246 @@
1
+ # Grasp Python SDK
2
+
3
+ Official Python SDK for the Grasp browser automation platform.
4
+
5
+ ## Features
6
+
7
+ - **Dual Client Architecture**: Both synchronous and asynchronous clients
8
+ - **Type Safety**: Full type hints and Pydantic models for validation
9
+ - **Browser Automation**: Seamless integration with Playwright and Puppeteer
10
+ - **Proxy Support**: Built-in proxy configuration for different use cases
11
+ - **Error Handling**: Comprehensive exception hierarchy
12
+ - **Auto-retry**: Automatic retry with exponential backoff
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install grasp-sdk
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### Synchronous Usage
23
+
24
+ ```python
25
+ from grasp import Grasp
26
+
27
+ # Initialize client
28
+ client = Grasp(api_key="your-api-key") # or set GRASP_API_KEY env var
29
+
30
+ # Create a container
31
+ container = client.create(
32
+ idle_timeout=30000, # 30 seconds
33
+ proxy={
34
+ "enabled": True,
35
+ "type": "residential",
36
+ "country": "US"
37
+ }
38
+ )
39
+
40
+ # Access browser information
41
+ print(f"Container ID: {container.id}")
42
+ print(f"CDP WebSocket: {container.browser.ws_endpoint}")
43
+ print(f"Live View: {container.browser.live_url}")
44
+
45
+ # Shutdown when done
46
+ container.shutdown()
47
+ ```
48
+
49
+ ### Asynchronous Usage
50
+
51
+ ```python
52
+ import asyncio
53
+ from grasp import AsyncGrasp
54
+
55
+ async def main():
56
+ # Use context manager for automatic cleanup
57
+ async with AsyncGrasp(api_key="your-api-key") as client:
58
+ # Create container
59
+ container = await client.create(idle_timeout=30000)
60
+
61
+ # Use the container
62
+ print(f"Container ID: {container.id}")
63
+
64
+ # Shutdown
65
+ await container.shutdown()
66
+
67
+ asyncio.run(main())
68
+ ```
69
+
70
+ ### Playwright Integration
71
+
72
+ ```python
73
+ from grasp import Grasp
74
+ from playwright.sync_api import sync_playwright
75
+
76
+ # Create Grasp container
77
+ grasp = Grasp()
78
+ container = grasp.create()
79
+
80
+ # Connect Playwright
81
+ with sync_playwright() as p:
82
+ browser = p.chromium.connect_over_cdp(container.browser.ws_endpoint)
83
+ page = browser.new_page()
84
+ page.goto("https://example.com")
85
+
86
+ # Your automation code here
87
+ title = page.title()
88
+ print(f"Page title: {title}")
89
+
90
+ browser.close()
91
+
92
+ # Cleanup
93
+ container.shutdown()
94
+ ```
95
+
96
+ ## Configuration
97
+
98
+ ### Environment Variables
99
+
100
+ - `GRASP_API_KEY`: Your API key (alternative to passing in code)
101
+ - `GRASP_BASE_URL`: API base URL (defaults to `https://api.getgrasp.ai`)
102
+
103
+ ### Client Options
104
+
105
+ ```python
106
+ client = Grasp(
107
+ api_key="your-api-key",
108
+ base_url="https://api.getgrasp.ai", # optional
109
+ timeout=60.0, # request timeout in seconds
110
+ max_retries=2 # maximum retry attempts
111
+ )
112
+ ```
113
+
114
+ ### Container Options
115
+
116
+ ```python
117
+ container = client.create(
118
+ idle_timeout=30000, # milliseconds before container sleeps
119
+ proxy={
120
+ "enabled": True,
121
+ "type": "residential", # mobile, residential, isp, datacenter, custom
122
+ "country": "US", # optional: country code
123
+ "state": "CA", # optional: state code
124
+ "city": "LA" # optional: city name
125
+ }
126
+ )
127
+ ```
128
+
129
+ ## API Reference
130
+
131
+ ### Main Classes
132
+
133
+ #### `Grasp` / `AsyncGrasp`
134
+ Main client classes for interacting with the API.
135
+
136
+ **Methods:**
137
+ - `create(**options)`: Create a new container
138
+ - `connect(container_id)`: Connect to existing container
139
+
140
+ #### `GraspContainer` / `AsyncGraspContainer`
141
+ Represents a browser automation container.
142
+
143
+ **Properties:**
144
+ - `id`: Container identifier
145
+ - `status`: Current status (running, stopped, sleeping)
146
+ - `created_at`: Creation timestamp
147
+ - `browser`: Browser session information
148
+
149
+ **Methods:**
150
+ - `shutdown()`: Shut down the container
151
+
152
+ #### `BrowserSession`
153
+ Browser session information.
154
+
155
+ **Properties:**
156
+ - `ws_endpoint`: Chrome DevTools Protocol WebSocket endpoint
157
+ - `live_url`: Live view URL for observing the browser
158
+
159
+ ### Exception Handling
160
+
161
+ ```python
162
+ from grasp import (
163
+ GraspError,
164
+ AuthenticationError,
165
+ NotFoundError,
166
+ RateLimitError
167
+ )
168
+
169
+ try:
170
+ container = client.create()
171
+ except AuthenticationError:
172
+ print("Invalid API key")
173
+ except RateLimitError as e:
174
+ print(f"Rate limited. Retry after: {e.retry_after}")
175
+ except GraspError as e:
176
+ print(f"API error: {e}")
177
+ ```
178
+
179
+ ### Exception Hierarchy
180
+
181
+ - `GraspError`: Base exception
182
+ - `APIError`: API-related errors
183
+ - `APIStatusError`: HTTP status errors
184
+ - `AuthenticationError`: 401 Unauthorized
185
+ - `NotFoundError`: 404 Not Found
186
+ - `RateLimitError`: 429 Rate Limited
187
+ - `InternalServerError`: 500 Server Error
188
+ - `APIConnectionError`: Network issues
189
+ - `APITimeoutError`: Request timeout
190
+
191
+ ## Examples
192
+
193
+ See the [examples](examples/) directory for more detailed examples:
194
+
195
+ - [basic_usage.py](examples/basic_usage.py): Simple synchronous usage
196
+ - [async_usage.py](examples/async_usage.py): Async with multiple containers
197
+ - [playwright_integration.py](examples/playwright_integration.py): Full Playwright integration
198
+
199
+ ## Development
200
+
201
+ ### Setup Development Environment
202
+
203
+ ```bash
204
+ # Clone the repository
205
+ git clone https://github.com/getgrasp-ai/grasp.git
206
+ cd grasp/packages/python-sdk
207
+
208
+ # Install dependencies
209
+ pip install -e ".[dev]"
210
+ ```
211
+
212
+ ### Run Tests
213
+
214
+ ```bash
215
+ # Run all tests
216
+ pytest
217
+
218
+ # Run with coverage
219
+ pytest --cov=grasp
220
+
221
+ # Run specific test file
222
+ pytest tests/test_client.py
223
+ ```
224
+
225
+ ### Code Quality
226
+
227
+ ```bash
228
+ # Format code
229
+ black src/ tests/
230
+
231
+ # Lint
232
+ ruff check src/ tests/
233
+
234
+ # Type check
235
+ mypy src/
236
+ ```
237
+
238
+ ## Requirements
239
+
240
+ - Python 3.8+
241
+ - httpx >= 0.24.0
242
+ - pydantic >= 2.0
243
+
244
+ ## License
245
+
246
+ MIT
@@ -0,0 +1,109 @@
1
+ # Release Guide for Grasp Python SDK
2
+
3
+ ## Pre-release Checklist
4
+
5
+ - [ ] All tests pass locally
6
+ - [ ] Version number updated in `pyproject.toml`
7
+ - [ ] README.md is up to date
8
+ - [ ] CHANGELOG updated (if exists)
9
+ - [ ] Examples work correctly
10
+
11
+ ## Current Release Info
12
+
13
+ - **Package Name**: grasp-sdk (on PyPI)
14
+ - **Import Name**: grasp (in Python code)
15
+ - **Previous Version**: 0.1.11 (from previous maintainer)
16
+ - **New Version**: 0.2.0 (complete rewrite)
17
+
18
+ ## Publishing Steps
19
+
20
+ ### 1. Clean previous builds
21
+ ```bash
22
+ rm -rf dist/ build/ *.egg-info/
23
+ ```
24
+
25
+ ### 2. Install build tools
26
+ ```bash
27
+ pip install --upgrade build twine
28
+ ```
29
+
30
+ ### 3. Build the package
31
+ ```bash
32
+ python -m build
33
+ ```
34
+
35
+ ### 4. Check the distribution
36
+ ```bash
37
+ # Check if package is correctly structured
38
+ twine check dist/*
39
+
40
+ # Test installation locally
41
+ pip install dist/grasp_sdk-0.2.0-py3-none-any.whl
42
+
43
+ # Verify it works
44
+ python -c "from grasp import Grasp; print('Import successful!')"
45
+ ```
46
+
47
+ ### 5. Upload to Test PyPI (optional but recommended)
48
+ ```bash
49
+ # Upload to test.pypi.org first
50
+ twine upload --repository testpypi dist/*
51
+
52
+ # Test install from Test PyPI
53
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ grasp-sdk==0.2.0
54
+ ```
55
+
56
+ ### 6. Upload to PyPI
57
+ ```bash
58
+ # You'll need PyPI credentials or token
59
+ twine upload dist/*
60
+ ```
61
+
62
+ ## Authentication
63
+
64
+ You'll need PyPI credentials. There are two options:
65
+
66
+ ### Option 1: Using Token (Recommended)
67
+ 1. Go to https://pypi.org/manage/account/token/
68
+ 2. Create a token for `grasp-sdk` project
69
+ 3. Use `__token__` as username and the token as password
70
+
71
+ ### Option 2: Using .pypirc file
72
+ Create `~/.pypirc`:
73
+ ```ini
74
+ [distutils]
75
+ index-servers =
76
+ pypi
77
+ testpypi
78
+
79
+ [pypi]
80
+ username = __token__
81
+ password = pypi-YOUR-TOKEN-HERE
82
+
83
+ [testpypi]
84
+ repository = https://test.pypi.org/legacy/
85
+ username = __token__
86
+ password = pypi-YOUR-TEST-TOKEN-HERE
87
+ ```
88
+
89
+ ## Post-release
90
+
91
+ After successful release:
92
+ 1. Create a git tag: `git tag v0.2.0`
93
+ 2. Push tag: `git push origin v0.2.0`
94
+ 3. Create GitHub release with changelog
95
+ 4. Update documentation if needed
96
+
97
+ ## Breaking Changes from 0.1.11
98
+
99
+ Since this is a complete rewrite, users upgrading from 0.1.11 should be aware:
100
+ - Completely new API design
101
+ - Both sync and async clients available
102
+ - Different import structure
103
+ - New error handling system
104
+ - Better container lifecycle management
105
+
106
+ ## Version History
107
+
108
+ - **0.1.11** - Last version from previous maintainer
109
+ - **0.2.0** - Complete rewrite with new architecture
@@ -0,0 +1,55 @@
1
+ # Testing the Grasp Python SDK
2
+
3
+ ## Prerequisites
4
+
5
+ 1. **API Server Running**: Ensure the Grasp API server is running locally on `http://localhost:3000`
6
+ ```bash
7
+ # From the root directory
8
+ pnpm --filter api-server dev
9
+ ```
10
+
11
+ 2. **Python Environment**: Python 3.8+ installed
12
+
13
+ ## Running Tests
14
+
15
+ ```bash
16
+ cd packages/python-sdk
17
+ ./run_tests.sh
18
+ ```
19
+
20
+ The test script will automatically:
21
+ - Set environment variables (`GRASP_API_KEY="api-server-test"`, `GRASP_BASE_URL="http://localhost:3000"`)
22
+ - Install the SDK in development mode
23
+ - Install test dependencies (pytest, pytest-asyncio)
24
+ - Install Playwright for browser automation tests
25
+ - Run all tests including Playwright integration tests
26
+ - Show clear pass/fail status with troubleshooting tips
27
+
28
+ ## Test Structure
29
+
30
+ - `tests/test_client.py` - Tests for synchronous client
31
+ - `tests/test_async_client.py` - Tests for asynchronous client
32
+
33
+ Each test file covers:
34
+ - Client initialization
35
+ - Container creation and management
36
+ - Browser endpoint validation
37
+ - Error handling
38
+ - Serialization
39
+ - **Playwright Integration** (optional):
40
+ - Browser connection via CDP
41
+ - Page navigation and content scraping
42
+
43
+ ## Troubleshooting
44
+
45
+ ### Connection Errors
46
+ If you see connection errors, ensure:
47
+ 1. API server is running on port 3000
48
+ 2. Environment variables are set correctly
49
+ 3. No firewall blocking localhost connections
50
+
51
+ ### API Key Errors
52
+ The test API key `api-server-test` is hardcoded for local testing. Make sure the API server recognizes this key.
53
+
54
+ ### Cleanup
55
+ Tests automatically clean up containers after completion. If tests fail, some containers might remain active. Check the API server logs for orphaned containers.