devicebase 2026.4.1__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.
@@ -0,0 +1,16 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(pytest)",
5
+ "Bash(mypy src:*)",
6
+ "Bash(ruff check:*)",
7
+ "WebFetch(domain:localhost)",
8
+ "Bash(curl -s http://localhost:3410/openapi.json)",
9
+ "Bash(curl -s http://localhost:3410/docs)",
10
+ "Bash(pytest -v --tb=short)",
11
+ "Bash(ruff format:*)",
12
+ "Bash(pytest -v)",
13
+ "Bash(pytest --tb=short -q)"
14
+ ]
15
+ }
16
+ }
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ .Python
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .eggs/
10
+ .pytest_cache/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .coverage
14
+ .tox/
15
+ .venv/
16
+ venv/
17
+ *.egg
@@ -0,0 +1,100 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ This is the **DeviceBase Python SDK** — a client library for the TestClaw device automation API. It provides both HTTP and WebSocket interfaces for controlling Android devices.
8
+
9
+ ## Project Structure
10
+
11
+ ```
12
+ src/devicebase/
13
+ ├── __init__.py # Package exports
14
+ ├── client.py # Main DeviceBaseClient (high-level interface)
15
+ ├── http_client.py # DeviceBaseHttpClient (HTTP API)
16
+ ├── websocket_client.py # MinicapClient & MinitouchClient (WebSocket streams)
17
+ └── models.py # Data models (Point, Bounds, DeviceInfo, etc.)
18
+
19
+ tests/ # Test suite (pytest)
20
+ pyproject.toml # Project config (hatch + pytest + mypy + ruff)
21
+ ```
22
+
23
+ ## Common Commands
24
+
25
+ ```bash
26
+ # Install in editable mode with dev dependencies
27
+ pip install -e ".[dev]"
28
+
29
+ # Run tests
30
+ pytest
31
+
32
+ # Run type checking
33
+ mypy src
34
+
35
+ # Lint and format
36
+ ruff check src tests --fix
37
+ ruff format src tests
38
+ ```
39
+
40
+ ## Configuration
41
+
42
+ The SDK supports configuration via environment variables or constructor parameters:
43
+
44
+ - `DEVICEBASE_BASE_URL` / `base_url`: API base URL (default: https://api.devicebase.cn)
45
+ - `DEVICEBASE_API_KEY` / `api_key`: JWT API key for authentication
46
+
47
+ Both HTTP and HTTPS protocols are supported.
48
+
49
+ ## Architecture
50
+
51
+ ### Main Client (`DeviceBaseClient`)
52
+
53
+ High-level interface that combines HTTP and WebSocket operations:
54
+
55
+ ```python
56
+ from devicebase import DeviceBaseClient
57
+
58
+ client = DeviceBaseClient()
59
+
60
+ # HTTP operations
61
+ info = client.get_device_info("device123")
62
+ client.tap("device123", x=100, y=200)
63
+ screenshot = client.get_screenshot("device123")
64
+
65
+ # WebSocket clients
66
+ minicap = client.minicap_client("device123")
67
+ minitouch = client.minitouch_client("device123")
68
+ ```
69
+
70
+ ### HTTP Client (`DeviceBaseHttpClient`)
71
+
72
+ Handles all REST API calls with JWT authentication:
73
+ - Device info, touch operations, app control
74
+ - Screenshots (JPEG bytes)
75
+ - UI hierarchy dumping
76
+
77
+ ### WebSocket Clients
78
+
79
+ - `MinicapClient`: Real-time screen streaming (JPEG frames)
80
+ - `MinitouchClient`: Low-level touch event control
81
+
82
+ ### Models
83
+
84
+ Immutable dataclasses for type safety:
85
+ - `Point`, `Bounds`: Touch coordinates
86
+ - `DeviceInfo`, `AppInfo`, `HierarchyInfo`: API responses
87
+ - `OperationResult`: Command results
88
+
89
+ ## Error Handling
90
+
91
+ Custom exceptions:
92
+ - `AuthenticationError`: Missing/invalid API key
93
+ - `DeviceNotFoundError`: Device not connected (404)
94
+ - `ValidationError`: Invalid request parameters (422)
95
+ - `DeviceBaseError`: Base exception for all SDK errors
96
+
97
+ ## Dependencies
98
+
99
+ Runtime: `httpx`, `websockets`, `pydantic`
100
+ Dev: `pytest`, `pytest-asyncio`, `mypy`, `ruff`, `respx`
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 UUSENSE, Inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,224 @@
1
+ Metadata-Version: 2.4
2
+ Name: devicebase
3
+ Version: 2026.4.1
4
+ Summary: Devicebase Python SDK
5
+ Project-URL: Homepage, https://github.com/uusense/python-devicebase
6
+ Project-URL: Repository, https://github.com/uusense/python-devicebase
7
+ Author: Richie
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: httpx>=0.27.0
15
+ Requires-Dist: pydantic>=2.0
16
+ Requires-Dist: websockets>=12.0
17
+ Provides-Extra: dev
18
+ Requires-Dist: mypy>=1.0; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
20
+ Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
21
+ Requires-Dist: pytest>=8.0; extra == 'dev'
22
+ Requires-Dist: respx>=0.22.0; extra == 'dev'
23
+ Requires-Dist: ruff>=0.3.0; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Devicebase Python SDK
27
+
28
+ Python SDK for the Devicebase device automation API. Control Android/HarmonyOS/iOS devices programmatically via HTTP and WebSocket interfaces.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install devicebase
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ```python
39
+ from devicebase import DeviceBaseClient
40
+
41
+ # Initialize client (reads DEVICEBASE_BASE_URL and DEVICEBASE_API_KEY from env)
42
+ client = DeviceBaseClient()
43
+
44
+ # Get device info
45
+ info = client.get_device_info("device123")
46
+
47
+ # Control the device
48
+ client.tap("device123", x=100, y=200)
49
+ client.swipe("device123", x1=0, y1=500, x2=500, y2=500)
50
+ client.launch_app("device123", "com.example.app")
51
+
52
+ # Take a screenshot
53
+ screenshot_bytes = client.get_screenshot("device123")
54
+ with open("screenshot.jpg", "wb") as f:
55
+ f.write(screenshot_bytes)
56
+ ```
57
+
58
+ ## Configuration
59
+
60
+ Configure via environment variables or constructor parameters:
61
+
62
+ ```python
63
+ import os
64
+
65
+ # Option 1: Environment variables (optional, has default values)
66
+ os.environ["DEVICEBASE_API_KEY"] = "your-jwt-token"
67
+ # DEVICEBASE_BASE_URL defaults to https://api.devicebase.cn if not set
68
+ client = DeviceBaseClient()
69
+
70
+ # Option 2: Constructor parameters
71
+ client = DeviceBaseClient(
72
+ base_url="https://api.devicebase.cn", # or http://localhost:3410 for local server
73
+ api_key="your-jwt-token"
74
+ )
75
+ ```
76
+
77
+ Both HTTP and HTTPS protocols are supported.
78
+
79
+ ## Device Control
80
+
81
+ ### Touch Operations
82
+
83
+ ```python
84
+ # Single tap
85
+ client.tap("device123", x=100, y=200)
86
+
87
+ # Double tap
88
+ client.double_tap("device123", x=100, y=200)
89
+
90
+ # Long press
91
+ client.long_press("device123", x=100, y=200)
92
+
93
+ # Swipe
94
+ client.swipe("device123", x1=0, y1=500, x2=500, y2=500)
95
+ ```
96
+
97
+ ### Navigation
98
+
99
+ ```python
100
+ # Press back button
101
+ client.back("device123")
102
+
103
+ # Press home button
104
+ client.home("device123")
105
+ ```
106
+
107
+ ### App Operations
108
+
109
+ ```python
110
+ # Launch an app
111
+ client.launch_app("device123", "com.example.app")
112
+
113
+ # Get current foreground app
114
+ app_info = client.get_current_app("device123")
115
+ print(app_info.data["package"])
116
+ ```
117
+
118
+ ### Text Input
119
+
120
+ ```python
121
+ # Input text into focused field
122
+ client.input_text("device123", "Hello World")
123
+
124
+ # Clear text in focused field
125
+ client.clear_text("device123")
126
+ ```
127
+
128
+ ### UI Hierarchy
129
+
130
+ ```python
131
+ # Dump UI hierarchy (useful for automation)
132
+ hierarchy = client.dump_hierarchy("device123")
133
+ print(hierarchy.data)
134
+ ```
135
+
136
+ ## Screenshots
137
+
138
+ ```python
139
+ # Get screenshot as JPEG bytes
140
+ screenshot = client.get_screenshot("device123")
141
+
142
+ # Download screenshot as file attachment
143
+ download = client.download_screenshot("device123")
144
+ ```
145
+
146
+ ## WebSocket Streaming
147
+
148
+ ### Screen Streaming (Minicap)
149
+
150
+ ```python
151
+ import asyncio
152
+
153
+ async def stream_screen():
154
+ client = DeviceBaseClient()
155
+ minicap = client.minicap_client("device123")
156
+
157
+ async for frame in minicap.stream_frames():
158
+ # frame is JPEG bytes
159
+ with open("frame.jpg", "wb") as f:
160
+ f.write(frame)
161
+
162
+ asyncio.run(stream_screen())
163
+ ```
164
+
165
+ ### Touch Control (Minitouch)
166
+
167
+ ```python
168
+ import asyncio
169
+
170
+ async def control_touch():
171
+ client = DeviceBaseClient()
172
+ minitouch = client.minitouch_client("device123")
173
+
174
+ async with minitouch:
175
+ # Tap at coordinates
176
+ await minitouch.tap(100, 200)
177
+
178
+ # Swipe gesture
179
+ await minitouch.swipe(0, 500, 500, 500, duration_ms=300)
180
+
181
+ asyncio.run(control_touch())
182
+ ```
183
+
184
+ ## Error Handling
185
+
186
+ ```python
187
+ from devicebase import (
188
+ DeviceBaseClient,
189
+ AuthenticationError,
190
+ DeviceNotFoundError,
191
+ ValidationError,
192
+ )
193
+
194
+ try:
195
+ client = DeviceBaseClient()
196
+ info = client.get_device_info("device123")
197
+ except AuthenticationError:
198
+ print("Invalid or missing API key")
199
+ except DeviceNotFoundError:
200
+ print("Device not found or not connected")
201
+ except ValidationError as e:
202
+ print(f"Invalid request: {e}")
203
+ ```
204
+
205
+ ## Development
206
+
207
+ ```bash
208
+ # Install dependencies
209
+ pip install -e ".[dev]"
210
+
211
+ # Run tests
212
+ pytest
213
+
214
+ # Run type checking
215
+ mypy src
216
+
217
+ # Format and lint
218
+ ruff check src tests --fix
219
+ ruff format src tests
220
+ ```
221
+
222
+ ## License
223
+
224
+ MIT
@@ -0,0 +1,199 @@
1
+ # Devicebase Python SDK
2
+
3
+ Python SDK for the Devicebase device automation API. Control Android/HarmonyOS/iOS devices programmatically via HTTP and WebSocket interfaces.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install devicebase
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from devicebase import DeviceBaseClient
15
+
16
+ # Initialize client (reads DEVICEBASE_BASE_URL and DEVICEBASE_API_KEY from env)
17
+ client = DeviceBaseClient()
18
+
19
+ # Get device info
20
+ info = client.get_device_info("device123")
21
+
22
+ # Control the device
23
+ client.tap("device123", x=100, y=200)
24
+ client.swipe("device123", x1=0, y1=500, x2=500, y2=500)
25
+ client.launch_app("device123", "com.example.app")
26
+
27
+ # Take a screenshot
28
+ screenshot_bytes = client.get_screenshot("device123")
29
+ with open("screenshot.jpg", "wb") as f:
30
+ f.write(screenshot_bytes)
31
+ ```
32
+
33
+ ## Configuration
34
+
35
+ Configure via environment variables or constructor parameters:
36
+
37
+ ```python
38
+ import os
39
+
40
+ # Option 1: Environment variables (optional, has default values)
41
+ os.environ["DEVICEBASE_API_KEY"] = "your-jwt-token"
42
+ # DEVICEBASE_BASE_URL defaults to https://api.devicebase.cn if not set
43
+ client = DeviceBaseClient()
44
+
45
+ # Option 2: Constructor parameters
46
+ client = DeviceBaseClient(
47
+ base_url="https://api.devicebase.cn", # or http://localhost:3410 for local server
48
+ api_key="your-jwt-token"
49
+ )
50
+ ```
51
+
52
+ Both HTTP and HTTPS protocols are supported.
53
+
54
+ ## Device Control
55
+
56
+ ### Touch Operations
57
+
58
+ ```python
59
+ # Single tap
60
+ client.tap("device123", x=100, y=200)
61
+
62
+ # Double tap
63
+ client.double_tap("device123", x=100, y=200)
64
+
65
+ # Long press
66
+ client.long_press("device123", x=100, y=200)
67
+
68
+ # Swipe
69
+ client.swipe("device123", x1=0, y1=500, x2=500, y2=500)
70
+ ```
71
+
72
+ ### Navigation
73
+
74
+ ```python
75
+ # Press back button
76
+ client.back("device123")
77
+
78
+ # Press home button
79
+ client.home("device123")
80
+ ```
81
+
82
+ ### App Operations
83
+
84
+ ```python
85
+ # Launch an app
86
+ client.launch_app("device123", "com.example.app")
87
+
88
+ # Get current foreground app
89
+ app_info = client.get_current_app("device123")
90
+ print(app_info.data["package"])
91
+ ```
92
+
93
+ ### Text Input
94
+
95
+ ```python
96
+ # Input text into focused field
97
+ client.input_text("device123", "Hello World")
98
+
99
+ # Clear text in focused field
100
+ client.clear_text("device123")
101
+ ```
102
+
103
+ ### UI Hierarchy
104
+
105
+ ```python
106
+ # Dump UI hierarchy (useful for automation)
107
+ hierarchy = client.dump_hierarchy("device123")
108
+ print(hierarchy.data)
109
+ ```
110
+
111
+ ## Screenshots
112
+
113
+ ```python
114
+ # Get screenshot as JPEG bytes
115
+ screenshot = client.get_screenshot("device123")
116
+
117
+ # Download screenshot as file attachment
118
+ download = client.download_screenshot("device123")
119
+ ```
120
+
121
+ ## WebSocket Streaming
122
+
123
+ ### Screen Streaming (Minicap)
124
+
125
+ ```python
126
+ import asyncio
127
+
128
+ async def stream_screen():
129
+ client = DeviceBaseClient()
130
+ minicap = client.minicap_client("device123")
131
+
132
+ async for frame in minicap.stream_frames():
133
+ # frame is JPEG bytes
134
+ with open("frame.jpg", "wb") as f:
135
+ f.write(frame)
136
+
137
+ asyncio.run(stream_screen())
138
+ ```
139
+
140
+ ### Touch Control (Minitouch)
141
+
142
+ ```python
143
+ import asyncio
144
+
145
+ async def control_touch():
146
+ client = DeviceBaseClient()
147
+ minitouch = client.minitouch_client("device123")
148
+
149
+ async with minitouch:
150
+ # Tap at coordinates
151
+ await minitouch.tap(100, 200)
152
+
153
+ # Swipe gesture
154
+ await minitouch.swipe(0, 500, 500, 500, duration_ms=300)
155
+
156
+ asyncio.run(control_touch())
157
+ ```
158
+
159
+ ## Error Handling
160
+
161
+ ```python
162
+ from devicebase import (
163
+ DeviceBaseClient,
164
+ AuthenticationError,
165
+ DeviceNotFoundError,
166
+ ValidationError,
167
+ )
168
+
169
+ try:
170
+ client = DeviceBaseClient()
171
+ info = client.get_device_info("device123")
172
+ except AuthenticationError:
173
+ print("Invalid or missing API key")
174
+ except DeviceNotFoundError:
175
+ print("Device not found or not connected")
176
+ except ValidationError as e:
177
+ print(f"Invalid request: {e}")
178
+ ```
179
+
180
+ ## Development
181
+
182
+ ```bash
183
+ # Install dependencies
184
+ pip install -e ".[dev]"
185
+
186
+ # Run tests
187
+ pytest
188
+
189
+ # Run type checking
190
+ mypy src
191
+
192
+ # Format and lint
193
+ ruff check src tests --fix
194
+ ruff format src tests
195
+ ```
196
+
197
+ ## License
198
+
199
+ MIT
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "devicebase"
7
+ version = "2026.4.1"
8
+ description = "Devicebase Python SDK"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Richie" },
14
+ ]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent",
19
+ ]
20
+ dependencies = [
21
+ "httpx>=0.27.0",
22
+ "websockets>=12.0",
23
+ "pydantic>=2.0",
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+ dev = [
28
+ "pytest>=8.0",
29
+ "pytest-asyncio>=0.23.0",
30
+ "pytest-httpx>=0.30.0",
31
+ "mypy>=1.0",
32
+ "ruff>=0.3.0",
33
+ "respx>=0.22.0",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/uusense/python-devicebase"
38
+ Repository = "https://github.com/uusense/python-devicebase"
39
+
40
+ [tool.hatch.build.targets.wheel]
41
+ packages = ["src/devicebase"]
42
+
43
+ [tool.pytest.ini_options]
44
+ testpaths = ["tests"]
45
+ pythonpath = ["src"]
46
+ asyncio_mode = "auto"
47
+
48
+ [tool.mypy]
49
+ python_version = "3.10"
50
+ strict = true
51
+ warn_return_any = true
52
+ warn_unused_configs = true
53
+
54
+ [tool.ruff]
55
+ target-version = "py310"
56
+ line-length = 100
57
+
58
+ [tool.ruff.lint]
59
+ select = ["E", "F", "I", "N", "W", "UP", "B", "C4", "SIM"]
60
+ ignore = ["E501"]
61
+
62
+ [tool.ruff.lint.pydocstyle]
63
+ convention = "google"
@@ -0,0 +1,44 @@
1
+ """DeviceBase Python SDK for TestClaw device automation."""
2
+
3
+ from devicebase.client import DeviceBaseClient
4
+ from devicebase.http_client import (
5
+ AuthenticationError,
6
+ DeviceBaseError,
7
+ DeviceNotFoundError,
8
+ ValidationError,
9
+ )
10
+ from devicebase.models import (
11
+ AppInfo,
12
+ Bounds,
13
+ DeviceInfo,
14
+ HierarchyInfo,
15
+ InputTextRequest,
16
+ LaunchAppRequest,
17
+ OperationResult,
18
+ Point,
19
+ )
20
+ from devicebase.websocket_client import MinicapClient, MinitouchClient
21
+
22
+ __version__ = "2026.4.1"
23
+
24
+ __all__ = [
25
+ # Main client
26
+ "DeviceBaseClient",
27
+ # Exceptions
28
+ "AuthenticationError",
29
+ "DeviceBaseError",
30
+ "DeviceNotFoundError",
31
+ "ValidationError",
32
+ # Models
33
+ "AppInfo",
34
+ "Bounds",
35
+ "DeviceInfo",
36
+ "HierarchyInfo",
37
+ "InputTextRequest",
38
+ "LaunchAppRequest",
39
+ "OperationResult",
40
+ "Point",
41
+ # WebSocket clients
42
+ "MinicapClient",
43
+ "MinitouchClient",
44
+ ]