Skip to content

Commit 10835fb

Browse files
CopilotP4X-ng
andcommitted
Merge PR #24: Add high-level utility functions and classes
Co-authored-by: P4X-ng <223870169+P4X-ng@users.noreply.github.com>
1 parent 4530dfa commit 10835fb

8 files changed

Lines changed: 1586 additions & 0 deletions

File tree

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ I/O using [Trio](https://trio.readthedocs.io/). This library handles the
1313
WebSocket negotiation and session management, allowing you to transparently
1414
multiplex commands, responses, and events over a single connection.
1515

16+
## Features
17+
18+
- **Pure CDP**: Direct access to Chrome DevTools Protocol
19+
- **Async/Await**: Built on Trio for structured concurrency
20+
- **Type Safety**: Full type hints for better IDE support
21+
- **High-Level Utilities**: Puppeteer-inspired abstractions for common tasks
22+
- Keyboard and mouse simulation
23+
- Element interaction and querying
24+
- Wait for elements to appear
25+
- Pure CDP implementation (no JavaScript injection)
26+
27+
## Basic Example
28+
1629
The example below demonstrates the salient features of the library by navigating to a
1730
web page and extracting the document title.
1831

@@ -40,6 +53,30 @@ async with open_cdp(cdp_url) as conn:
4053
print(html)
4154
```
4255

56+
## High-Level Utilities Example
57+
58+
The library also provides high-level utilities for common automation tasks:
59+
60+
```python
61+
from trio_cdp import open_cdp, page, target
62+
from trio_cdp.util import query_selector, Keyboard
63+
64+
async with open_cdp(cdp_url) as conn:
65+
async with conn.open_session(target_id) as session:
66+
# Navigate to a page
67+
await page.enable()
68+
await page.navigate(url)
69+
70+
# Find an input field and type into it
71+
input_field = await query_selector(session, 'input[name="search"]')
72+
if input_field:
73+
await input_field.type('Hello, World!')
74+
75+
# Press Enter to submit
76+
keyboard = Keyboard(session)
77+
await keyboard.press('Enter')
78+
```
79+
4380
This example code is explained [in the documentation](https://trio-cdp.readthedocs.io)
4481
and more example code can be found in the `examples/` directory of this repository,
4582
including examples for taking screenshots and monitoring network events.

UTILITIES_IMPLEMENTATION.md

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Utilities Module Implementation Summary
2+
3+
## Overview
4+
5+
This implementation addresses the GitHub issue about extending `trio-chrome-devtools-protocol` with higher-level utility functions and classes for common browser automation tasks, inspired by Puppeteer/Pyppeteer.
6+
7+
## Decision: Integrated Approach
8+
9+
Rather than creating a separate `trio-puppeteer` package, the utilities are integrated directly into the main `trio_cdp` package as a `util` module. This approach was chosen because:
10+
11+
1. **Lightweight**: The utilities are thin wrappers around CDP commands
12+
2. **No External Dependencies**: Everything uses native CDP, no JavaScript injection
13+
3. **Tight Integration**: Direct access to session and connection objects
14+
4. **Simplicity**: Users don't need to install/manage a separate package
15+
16+
## Implementation
17+
18+
### New Module: `trio_cdp/util.py`
19+
20+
Contains three main classes and utility functions:
21+
22+
#### 1. Keyboard Class
23+
Provides keyboard input simulation:
24+
- `down(key, text=None)` - Press key down
25+
- `up(key)` - Release key
26+
- `press(key, delay=0)` - Complete key press (down + up)
27+
- `type(text, delay=0)` - Type a string character by character
28+
29+
**Example:**
30+
```python
31+
keyboard = Keyboard(session)
32+
await keyboard.type("Hello, World!")
33+
await keyboard.press("Enter")
34+
```
35+
36+
#### 2. Mouse Class
37+
Provides mouse action simulation:
38+
- `move(x, y, steps=1)` - Move mouse with optional smooth interpolation
39+
- `click(x, y, button='left', click_count=1, delay=0)` - Click at position
40+
- `down(button='left', click_count=1)` - Mouse button down
41+
- `up(button='left', click_count=1)` - Mouse button up
42+
43+
**Example:**
44+
```python
45+
mouse = Mouse(session)
46+
await mouse.move(100, 200, steps=10) # Smooth movement
47+
await mouse.click(100, 200)
48+
```
49+
50+
#### 3. ElementHandle Class
51+
Represents a handle to a DOM element with convenient interaction methods:
52+
- `click(button='left', click_count=1, delay=0)` - Click the element
53+
- `type(text, delay=0)` - Focus and type into element
54+
- `get_attribute(name)` - Get HTML attribute value
55+
- `get_property(name)` - Get JavaScript property value
56+
- `get_text_content()` - Extract text content
57+
58+
**Example:**
59+
```python
60+
input_field = await query_selector(session, 'input[name="email"]')
61+
if input_field:
62+
await input_field.type('user@example.com')
63+
```
64+
65+
#### Element Selection Functions
66+
- `query_selector(session, selector, node_id=None)` - Find first matching element
67+
- `query_selector_all(session, selector, node_id=None)` - Find all matching elements
68+
- `wait_for_selector(session, selector, timeout=30, visible=False)` - Wait for element
69+
70+
**Example:**
71+
```python
72+
# Find and interact with elements
73+
button = await query_selector(session, 'button.submit')
74+
if button:
75+
await button.click()
76+
77+
# Wait for dynamic content
78+
result = await wait_for_selector(session, '.result', timeout=10, visible=True)
79+
```
80+
81+
## Documentation
82+
83+
### Added Files
84+
1. **docs/utilities.rst** - Comprehensive documentation for all utilities
85+
2. **examples/form_interaction.py** - Example showing form interaction
86+
3. **examples/keyboard_mouse.py** - Example demonstrating keyboard/mouse usage
87+
4. **tests/test_util.py** - Unit tests for utility functions
88+
5. **validate_utilities.py** - Validation script to verify module structure
89+
90+
### Updated Files
91+
1. **README.md** - Added utilities section with examples
92+
2. **docs/index.rst** - Added utilities to documentation table of contents
93+
3. **trio_cdp/__init__.py** - Export util module
94+
95+
## Key Design Principles
96+
97+
1. **Pure CDP**: No JavaScript injection, all interactions use native CDP commands
98+
2. **Async-First**: Fully compatible with Trio's async/await patterns
99+
3. **Lightweight**: Minimal abstractions, close to underlying CDP
100+
4. **Type-Safe**: Complete type hints for IDE support
101+
5. **Composable**: Small, focused utilities that work well together
102+
6. **Optional**: Core CDP functionality remains available; utilities are opt-in
103+
104+
## Benefits
105+
106+
### For Users
107+
- **Intuitive API**: Familiar patterns for anyone coming from Puppeteer
108+
- **Less Boilerplate**: Common tasks simplified with high-level methods
109+
- **Type Safety**: Full IDE support with autocomplete and type checking
110+
- **Pure Python**: No JavaScript knowledge required
111+
112+
### For the Project
113+
- **Maintains Philosophy**: Stays true to lightweight, CDP-focused approach
114+
- **No Breaking Changes**: Completely additive, existing code unaffected
115+
- **Extensible**: Users can easily add custom utilities following same patterns
116+
- **Well-Documented**: Comprehensive docs and examples
117+
118+
## Technical Details
119+
120+
### Generator Fix
121+
Fixed `generator/generate.py` to handle `typing.Optional` type hints, which was preventing regeneration of CDP bindings with newer Python versions.
122+
123+
### CDP Bindings Regenerated
124+
Regenerated all CDP binding code to be compatible with `chrome-devtools-protocol==0.4.0`, resolving import errors with the generated code.
125+
126+
## Testing & Validation
127+
128+
1. **Unit Tests**: Comprehensive test suite in `tests/test_util.py`
129+
2. **Validation Script**: `validate_utilities.py` verifies all classes and methods exist
130+
3. **Code Quality**: Passed CodeQL security scan with 0 alerts
131+
4. **Examples**: Two working examples demonstrate real-world usage
132+
133+
## Usage Example
134+
135+
Here's a complete example showing the utilities in action:
136+
137+
```python
138+
import trio
139+
from trio_cdp import open_cdp, page, target
140+
from trio_cdp.util import query_selector, wait_for_selector, Keyboard
141+
142+
async def automate_form(cdp_url):
143+
async with open_cdp(cdp_url) as conn:
144+
# Get a target
145+
targets = await target.get_targets()
146+
target_id = targets[0].target_id
147+
148+
async with conn.open_session(target_id) as session:
149+
# Navigate
150+
await page.enable()
151+
await page.navigate('https://example.com/form')
152+
153+
# Wait for and fill form
154+
name_field = await wait_for_selector(session, 'input[name="name"]', timeout=10)
155+
if name_field:
156+
await name_field.type('John Doe')
157+
158+
# Use keyboard for submission
159+
keyboard = Keyboard(session)
160+
await keyboard.press('Enter')
161+
```
162+
163+
## Future Enhancements
164+
165+
Potential additions that maintain the same design philosophy:
166+
167+
1. **Page utilities**: Screenshot helpers, PDF generation utilities
168+
2. **Network utilities**: Request interception helpers, mock response utilities
169+
3. **Cookie utilities**: Easy cookie management
170+
4. **Dialog utilities**: Alert/prompt/confirm handlers
171+
5. **File upload**: File chooser utilities
172+
173+
Each would follow the same pattern: lightweight wrappers around CDP commands with convenient async interfaces.
174+
175+
## Conclusion
176+
177+
This implementation successfully extends `trio-chrome-devtools-protocol` with higher-level utilities while maintaining the library's core principles of being lightweight, pure-CDP, and Trio-native. The utilities provide a more intuitive interface for common automation tasks without sacrificing the power and flexibility of the underlying CDP protocol.

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ responses, and events over a single connection.
1515
installation
1616
getting_started
1717
api
18+
utilities
1819
changelog

0 commit comments

Comments
 (0)