tapium 0.1.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.
- tapium-0.1.0/LICENSE +21 -0
- tapium-0.1.0/PKG-INFO +168 -0
- tapium-0.1.0/README.md +147 -0
- tapium-0.1.0/pyproject.toml +35 -0
- tapium-0.1.0/setup.cfg +4 -0
- tapium-0.1.0/tapium.egg-info/PKG-INFO +168 -0
- tapium-0.1.0/tapium.egg-info/SOURCES.txt +13 -0
- tapium-0.1.0/tapium.egg-info/dependency_links.txt +1 -0
- tapium-0.1.0/tapium.egg-info/entry_points.txt +2 -0
- tapium-0.1.0/tapium.egg-info/requires.txt +1 -0
- tapium-0.1.0/tapium.egg-info/top_level.txt +1 -0
- tapium-0.1.0/tapium.py +1222 -0
- tapium-0.1.0/tests/test_actions.py +203 -0
- tapium-0.1.0/tests/test_cli.py +55 -0
- tapium-0.1.0/tests/test_pure_helpers.py +127 -0
tapium-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aleksandr
|
|
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.
|
tapium-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tapium
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Single-file, AI-agent-friendly controller for driving a real Android device over USB/ADB
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/alesav/tapium
|
|
7
|
+
Project-URL: Repository, https://github.com/alesav/tapium
|
|
8
|
+
Project-URL: Issues, https://github.com/alesav/tapium/issues
|
|
9
|
+
Keywords: android,adb,uiautomator2,automation,ai-agent,testing
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Software Development :: Testing
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: uiautomator2>=3.4.0
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Tapium
|
|
23
|
+
|
|
24
|
+
[](https://github.com/alesav/tapium/actions/workflows/ci.yml)
|
|
25
|
+
[](LICENSE)
|
|
26
|
+
|
|
27
|
+
A single-file, AI-agent-friendly controller for driving a real Android
|
|
28
|
+
device (or emulator) over USB/ADB — built for letting an LLM agent (or
|
|
29
|
+
any script) operate an app the way a human tester would: read the screen,
|
|
30
|
+
tap things, type things, wait for things to load.
|
|
31
|
+
|
|
32
|
+
Built on top of [`uiautomator2`](https://github.com/openatx/uiautomator2).
|
|
33
|
+
|
|
34
|
+
## Why
|
|
35
|
+
|
|
36
|
+
Most UI-automation tooling is built for deterministic test scripts: you
|
|
37
|
+
know in advance exactly which element you want, and you write a selector
|
|
38
|
+
for it. Driving a device from an LLM agent is different — the agent needs
|
|
39
|
+
to *see* the screen as structured data, decide what to do, act, and see
|
|
40
|
+
the result, in a tight loop, with minimal round-trips.
|
|
41
|
+
|
|
42
|
+
`tapium.py` is a thin JSON-in/JSON-out CLI wrapping `uiautomator2` with
|
|
43
|
+
that loop in mind:
|
|
44
|
+
|
|
45
|
+
- Every action returns a compact list of on-screen elements (text,
|
|
46
|
+
content-description, bounds, clickable/scrollable flags) — enough for
|
|
47
|
+
an agent to decide its next move without a screenshot.
|
|
48
|
+
- Every mutating action waits for the UI to settle before returning, so
|
|
49
|
+
the response already reflects the new screen — no extra "dump" call
|
|
50
|
+
needed in the common case.
|
|
51
|
+
- Actions are addressed by visible text/description first, with explicit
|
|
52
|
+
coordinate and structured-selector fallbacks for elements that don't
|
|
53
|
+
expose text (SVGs, canvases, custom views).
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install tapium
|
|
59
|
+
tapium setup
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`tapium setup` checks Python, `adb`, and a connected device, tells you
|
|
63
|
+
exactly how to install anything missing (no Android Studio — just the
|
|
64
|
+
~10MB platform-tools binary), and installs the on-device automation agent.
|
|
65
|
+
Run `tapium doctor` any time afterward to re-check the environment without
|
|
66
|
+
reinstalling anything.
|
|
67
|
+
|
|
68
|
+
Full first-run walkthrough, including enabling USB debugging on the phone:
|
|
69
|
+
see [AGENTS.md](AGENTS.md).
|
|
70
|
+
|
|
71
|
+
Requires:
|
|
72
|
+
- A device with USB debugging enabled, connected and authorized (`adb devices` should list it)
|
|
73
|
+
- Python 3.8+
|
|
74
|
+
|
|
75
|
+
Installing from this repo instead of PyPI: `pip install -e .`, or the
|
|
76
|
+
older `pip install -r requirements.txt` + running `tapium.py` directly
|
|
77
|
+
still works identically.
|
|
78
|
+
|
|
79
|
+
## Usage
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
tapium '{"action":"dump_ui"}'
|
|
83
|
+
tapium '{"action":"tap","text":"Sign in"}'
|
|
84
|
+
tapium '{"action":"input_text","field":"Email","text":"hello@example.com"}'
|
|
85
|
+
tapium '{"action":"swipe","direction":"up"}'
|
|
86
|
+
tapium '{"action":"wait_for","text":"Welcome back","timeout":15}'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
(Running from source instead of the installed command: swap `tapium` for
|
|
90
|
+
`python tapium.py` in the examples above.)
|
|
91
|
+
|
|
92
|
+
Every call prints one JSON object to stdout and exits `0` on success
|
|
93
|
+
(`"ok": true`) or `1` on failure (`"ok": false, "error": "..."`).
|
|
94
|
+
|
|
95
|
+
See the module docstring in `tapium.py` for the full action reference,
|
|
96
|
+
and `examples/` for a worked example of wiring this into an agent loop.
|
|
97
|
+
|
|
98
|
+
## Pairing with a backend API
|
|
99
|
+
|
|
100
|
+
`api.py` shows the intended pattern for combining `tapium.py` with a
|
|
101
|
+
backend API client in agent-driven testing — using the API for setup/
|
|
102
|
+
verification that's slow or flaky to reach purely through the UI (seed an
|
|
103
|
+
account, check a record landed, tear down test data), while
|
|
104
|
+
`tapium.py` drives the app itself.
|
|
105
|
+
|
|
106
|
+
**Every request in `api.py` is mocked** — there's no real backend wired
|
|
107
|
+
up, just an in-memory store and canned responses, so you can run it
|
|
108
|
+
out of the box and see the shape of the integration:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
python3 api.py '{"command":"get_user","id":"user_123","env":"staging"}'
|
|
112
|
+
python3 api.py '{"command":"create_user","email":"demo@example.com","env":"staging"}'
|
|
113
|
+
python3 api.py '{"command":"list_orders","user_id":"user_123","env":"staging"}'
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
To point this at a real API: replace `_mock_request()` with actual HTTP
|
|
117
|
+
calls (e.g. via `requests`) against `env["base_url"]`, authenticated with
|
|
118
|
+
`env["token"]`. Copy `environments.example.json` to `environments.json`
|
|
119
|
+
and fill in real tokens — that file is gitignored so secrets never get
|
|
120
|
+
committed.
|
|
121
|
+
|
|
122
|
+
## Design notes
|
|
123
|
+
|
|
124
|
+
- **No app-specific defaults.** Package names, landmark screen text, and
|
|
125
|
+
APK paths are always passed in by the caller — this tool knows nothing
|
|
126
|
+
about any particular app.
|
|
127
|
+
- **Text/description first, coordinates as fallback.** Tapping by visible
|
|
128
|
+
label is far more robust to minor layout shifts than fixed coordinates,
|
|
129
|
+
but `tap` and `input_sequence` both support coordinate fallbacks for the
|
|
130
|
+
cases where an element genuinely has no usable label.
|
|
131
|
+
- **`tap_selector` for non-text elements.** SVG/canvas/custom-rendered UI
|
|
132
|
+
often has no `text` or `content-desc` at all — `tap_selector` exposes
|
|
133
|
+
the underlying uiautomator2 `Selector` kwargs (`className`, `instance`,
|
|
134
|
+
`resourceId`, etc.) for those cases.
|
|
135
|
+
- **`set_location` is necessarily a bit app-specific.** Mock-location apps
|
|
136
|
+
all have different UIs, so this action drives a fairly common
|
|
137
|
+
"menu → search → lat/lon fields → OK → Start" shape and exposes the
|
|
138
|
+
parts likely to need adjusting (`menu_coords`, package names) as
|
|
139
|
+
arguments rather than hardcoding them. You may need to adapt the field
|
|
140
|
+
labels for whichever mock-location app you use — see the docstring.
|
|
141
|
+
|
|
142
|
+
## What this is not
|
|
143
|
+
|
|
144
|
+
This isn't a full test framework — there's no assertion library, test
|
|
145
|
+
runner, or reporting built in. It's the device-control layer you'd build
|
|
146
|
+
one on top of. If you're looking for that, this plays well alongside
|
|
147
|
+
`pytest` (treat each action's `"ok"` field and `"screen"` contents as your
|
|
148
|
+
assertions) or an agent framework that can shell out and parse JSON.
|
|
149
|
+
|
|
150
|
+
## Testing
|
|
151
|
+
|
|
152
|
+
The test suite runs against a fake in-memory device — **no real Android
|
|
153
|
+
device or emulator required**:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pip install -r requirements-dev.txt
|
|
157
|
+
pytest tests/ -v
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development workflow.
|
|
161
|
+
|
|
162
|
+
## Contributing
|
|
163
|
+
|
|
164
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT — see [LICENSE](LICENSE).
|
tapium-0.1.0/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Tapium
|
|
2
|
+
|
|
3
|
+
[](https://github.com/alesav/tapium/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
A single-file, AI-agent-friendly controller for driving a real Android
|
|
7
|
+
device (or emulator) over USB/ADB — built for letting an LLM agent (or
|
|
8
|
+
any script) operate an app the way a human tester would: read the screen,
|
|
9
|
+
tap things, type things, wait for things to load.
|
|
10
|
+
|
|
11
|
+
Built on top of [`uiautomator2`](https://github.com/openatx/uiautomator2).
|
|
12
|
+
|
|
13
|
+
## Why
|
|
14
|
+
|
|
15
|
+
Most UI-automation tooling is built for deterministic test scripts: you
|
|
16
|
+
know in advance exactly which element you want, and you write a selector
|
|
17
|
+
for it. Driving a device from an LLM agent is different — the agent needs
|
|
18
|
+
to *see* the screen as structured data, decide what to do, act, and see
|
|
19
|
+
the result, in a tight loop, with minimal round-trips.
|
|
20
|
+
|
|
21
|
+
`tapium.py` is a thin JSON-in/JSON-out CLI wrapping `uiautomator2` with
|
|
22
|
+
that loop in mind:
|
|
23
|
+
|
|
24
|
+
- Every action returns a compact list of on-screen elements (text,
|
|
25
|
+
content-description, bounds, clickable/scrollable flags) — enough for
|
|
26
|
+
an agent to decide its next move without a screenshot.
|
|
27
|
+
- Every mutating action waits for the UI to settle before returning, so
|
|
28
|
+
the response already reflects the new screen — no extra "dump" call
|
|
29
|
+
needed in the common case.
|
|
30
|
+
- Actions are addressed by visible text/description first, with explicit
|
|
31
|
+
coordinate and structured-selector fallbacks for elements that don't
|
|
32
|
+
expose text (SVGs, canvases, custom views).
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install tapium
|
|
38
|
+
tapium setup
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`tapium setup` checks Python, `adb`, and a connected device, tells you
|
|
42
|
+
exactly how to install anything missing (no Android Studio — just the
|
|
43
|
+
~10MB platform-tools binary), and installs the on-device automation agent.
|
|
44
|
+
Run `tapium doctor` any time afterward to re-check the environment without
|
|
45
|
+
reinstalling anything.
|
|
46
|
+
|
|
47
|
+
Full first-run walkthrough, including enabling USB debugging on the phone:
|
|
48
|
+
see [AGENTS.md](AGENTS.md).
|
|
49
|
+
|
|
50
|
+
Requires:
|
|
51
|
+
- A device with USB debugging enabled, connected and authorized (`adb devices` should list it)
|
|
52
|
+
- Python 3.8+
|
|
53
|
+
|
|
54
|
+
Installing from this repo instead of PyPI: `pip install -e .`, or the
|
|
55
|
+
older `pip install -r requirements.txt` + running `tapium.py` directly
|
|
56
|
+
still works identically.
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
tapium '{"action":"dump_ui"}'
|
|
62
|
+
tapium '{"action":"tap","text":"Sign in"}'
|
|
63
|
+
tapium '{"action":"input_text","field":"Email","text":"hello@example.com"}'
|
|
64
|
+
tapium '{"action":"swipe","direction":"up"}'
|
|
65
|
+
tapium '{"action":"wait_for","text":"Welcome back","timeout":15}'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
(Running from source instead of the installed command: swap `tapium` for
|
|
69
|
+
`python tapium.py` in the examples above.)
|
|
70
|
+
|
|
71
|
+
Every call prints one JSON object to stdout and exits `0` on success
|
|
72
|
+
(`"ok": true`) or `1` on failure (`"ok": false, "error": "..."`).
|
|
73
|
+
|
|
74
|
+
See the module docstring in `tapium.py` for the full action reference,
|
|
75
|
+
and `examples/` for a worked example of wiring this into an agent loop.
|
|
76
|
+
|
|
77
|
+
## Pairing with a backend API
|
|
78
|
+
|
|
79
|
+
`api.py` shows the intended pattern for combining `tapium.py` with a
|
|
80
|
+
backend API client in agent-driven testing — using the API for setup/
|
|
81
|
+
verification that's slow or flaky to reach purely through the UI (seed an
|
|
82
|
+
account, check a record landed, tear down test data), while
|
|
83
|
+
`tapium.py` drives the app itself.
|
|
84
|
+
|
|
85
|
+
**Every request in `api.py` is mocked** — there's no real backend wired
|
|
86
|
+
up, just an in-memory store and canned responses, so you can run it
|
|
87
|
+
out of the box and see the shape of the integration:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
python3 api.py '{"command":"get_user","id":"user_123","env":"staging"}'
|
|
91
|
+
python3 api.py '{"command":"create_user","email":"demo@example.com","env":"staging"}'
|
|
92
|
+
python3 api.py '{"command":"list_orders","user_id":"user_123","env":"staging"}'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
To point this at a real API: replace `_mock_request()` with actual HTTP
|
|
96
|
+
calls (e.g. via `requests`) against `env["base_url"]`, authenticated with
|
|
97
|
+
`env["token"]`. Copy `environments.example.json` to `environments.json`
|
|
98
|
+
and fill in real tokens — that file is gitignored so secrets never get
|
|
99
|
+
committed.
|
|
100
|
+
|
|
101
|
+
## Design notes
|
|
102
|
+
|
|
103
|
+
- **No app-specific defaults.** Package names, landmark screen text, and
|
|
104
|
+
APK paths are always passed in by the caller — this tool knows nothing
|
|
105
|
+
about any particular app.
|
|
106
|
+
- **Text/description first, coordinates as fallback.** Tapping by visible
|
|
107
|
+
label is far more robust to minor layout shifts than fixed coordinates,
|
|
108
|
+
but `tap` and `input_sequence` both support coordinate fallbacks for the
|
|
109
|
+
cases where an element genuinely has no usable label.
|
|
110
|
+
- **`tap_selector` for non-text elements.** SVG/canvas/custom-rendered UI
|
|
111
|
+
often has no `text` or `content-desc` at all — `tap_selector` exposes
|
|
112
|
+
the underlying uiautomator2 `Selector` kwargs (`className`, `instance`,
|
|
113
|
+
`resourceId`, etc.) for those cases.
|
|
114
|
+
- **`set_location` is necessarily a bit app-specific.** Mock-location apps
|
|
115
|
+
all have different UIs, so this action drives a fairly common
|
|
116
|
+
"menu → search → lat/lon fields → OK → Start" shape and exposes the
|
|
117
|
+
parts likely to need adjusting (`menu_coords`, package names) as
|
|
118
|
+
arguments rather than hardcoding them. You may need to adapt the field
|
|
119
|
+
labels for whichever mock-location app you use — see the docstring.
|
|
120
|
+
|
|
121
|
+
## What this is not
|
|
122
|
+
|
|
123
|
+
This isn't a full test framework — there's no assertion library, test
|
|
124
|
+
runner, or reporting built in. It's the device-control layer you'd build
|
|
125
|
+
one on top of. If you're looking for that, this plays well alongside
|
|
126
|
+
`pytest` (treat each action's `"ok"` field and `"screen"` contents as your
|
|
127
|
+
assertions) or an agent framework that can shell out and parse JSON.
|
|
128
|
+
|
|
129
|
+
## Testing
|
|
130
|
+
|
|
131
|
+
The test suite runs against a fake in-memory device — **no real Android
|
|
132
|
+
device or emulator required**:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
pip install -r requirements-dev.txt
|
|
136
|
+
pytest tests/ -v
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development workflow.
|
|
140
|
+
|
|
141
|
+
## Contributing
|
|
142
|
+
|
|
143
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
144
|
+
|
|
145
|
+
## License
|
|
146
|
+
|
|
147
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tapium"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Single-file, AI-agent-friendly controller for driving a real Android device over USB/ADB"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
keywords = ["android", "adb", "uiautomator2", "automation", "ai-agent", "testing"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Software Development :: Testing",
|
|
20
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"uiautomator2>=3.4.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/alesav/tapium"
|
|
28
|
+
Repository = "https://github.com/alesav/tapium"
|
|
29
|
+
Issues = "https://github.com/alesav/tapium/issues"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
tapium = "tapium:main"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools]
|
|
35
|
+
py-modules = ["tapium"]
|
tapium-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tapium
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Single-file, AI-agent-friendly controller for driving a real Android device over USB/ADB
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/alesav/tapium
|
|
7
|
+
Project-URL: Repository, https://github.com/alesav/tapium
|
|
8
|
+
Project-URL: Issues, https://github.com/alesav/tapium/issues
|
|
9
|
+
Keywords: android,adb,uiautomator2,automation,ai-agent,testing
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Software Development :: Testing
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: uiautomator2>=3.4.0
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Tapium
|
|
23
|
+
|
|
24
|
+
[](https://github.com/alesav/tapium/actions/workflows/ci.yml)
|
|
25
|
+
[](LICENSE)
|
|
26
|
+
|
|
27
|
+
A single-file, AI-agent-friendly controller for driving a real Android
|
|
28
|
+
device (or emulator) over USB/ADB — built for letting an LLM agent (or
|
|
29
|
+
any script) operate an app the way a human tester would: read the screen,
|
|
30
|
+
tap things, type things, wait for things to load.
|
|
31
|
+
|
|
32
|
+
Built on top of [`uiautomator2`](https://github.com/openatx/uiautomator2).
|
|
33
|
+
|
|
34
|
+
## Why
|
|
35
|
+
|
|
36
|
+
Most UI-automation tooling is built for deterministic test scripts: you
|
|
37
|
+
know in advance exactly which element you want, and you write a selector
|
|
38
|
+
for it. Driving a device from an LLM agent is different — the agent needs
|
|
39
|
+
to *see* the screen as structured data, decide what to do, act, and see
|
|
40
|
+
the result, in a tight loop, with minimal round-trips.
|
|
41
|
+
|
|
42
|
+
`tapium.py` is a thin JSON-in/JSON-out CLI wrapping `uiautomator2` with
|
|
43
|
+
that loop in mind:
|
|
44
|
+
|
|
45
|
+
- Every action returns a compact list of on-screen elements (text,
|
|
46
|
+
content-description, bounds, clickable/scrollable flags) — enough for
|
|
47
|
+
an agent to decide its next move without a screenshot.
|
|
48
|
+
- Every mutating action waits for the UI to settle before returning, so
|
|
49
|
+
the response already reflects the new screen — no extra "dump" call
|
|
50
|
+
needed in the common case.
|
|
51
|
+
- Actions are addressed by visible text/description first, with explicit
|
|
52
|
+
coordinate and structured-selector fallbacks for elements that don't
|
|
53
|
+
expose text (SVGs, canvases, custom views).
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install tapium
|
|
59
|
+
tapium setup
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`tapium setup` checks Python, `adb`, and a connected device, tells you
|
|
63
|
+
exactly how to install anything missing (no Android Studio — just the
|
|
64
|
+
~10MB platform-tools binary), and installs the on-device automation agent.
|
|
65
|
+
Run `tapium doctor` any time afterward to re-check the environment without
|
|
66
|
+
reinstalling anything.
|
|
67
|
+
|
|
68
|
+
Full first-run walkthrough, including enabling USB debugging on the phone:
|
|
69
|
+
see [AGENTS.md](AGENTS.md).
|
|
70
|
+
|
|
71
|
+
Requires:
|
|
72
|
+
- A device with USB debugging enabled, connected and authorized (`adb devices` should list it)
|
|
73
|
+
- Python 3.8+
|
|
74
|
+
|
|
75
|
+
Installing from this repo instead of PyPI: `pip install -e .`, or the
|
|
76
|
+
older `pip install -r requirements.txt` + running `tapium.py` directly
|
|
77
|
+
still works identically.
|
|
78
|
+
|
|
79
|
+
## Usage
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
tapium '{"action":"dump_ui"}'
|
|
83
|
+
tapium '{"action":"tap","text":"Sign in"}'
|
|
84
|
+
tapium '{"action":"input_text","field":"Email","text":"hello@example.com"}'
|
|
85
|
+
tapium '{"action":"swipe","direction":"up"}'
|
|
86
|
+
tapium '{"action":"wait_for","text":"Welcome back","timeout":15}'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
(Running from source instead of the installed command: swap `tapium` for
|
|
90
|
+
`python tapium.py` in the examples above.)
|
|
91
|
+
|
|
92
|
+
Every call prints one JSON object to stdout and exits `0` on success
|
|
93
|
+
(`"ok": true`) or `1` on failure (`"ok": false, "error": "..."`).
|
|
94
|
+
|
|
95
|
+
See the module docstring in `tapium.py` for the full action reference,
|
|
96
|
+
and `examples/` for a worked example of wiring this into an agent loop.
|
|
97
|
+
|
|
98
|
+
## Pairing with a backend API
|
|
99
|
+
|
|
100
|
+
`api.py` shows the intended pattern for combining `tapium.py` with a
|
|
101
|
+
backend API client in agent-driven testing — using the API for setup/
|
|
102
|
+
verification that's slow or flaky to reach purely through the UI (seed an
|
|
103
|
+
account, check a record landed, tear down test data), while
|
|
104
|
+
`tapium.py` drives the app itself.
|
|
105
|
+
|
|
106
|
+
**Every request in `api.py` is mocked** — there's no real backend wired
|
|
107
|
+
up, just an in-memory store and canned responses, so you can run it
|
|
108
|
+
out of the box and see the shape of the integration:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
python3 api.py '{"command":"get_user","id":"user_123","env":"staging"}'
|
|
112
|
+
python3 api.py '{"command":"create_user","email":"demo@example.com","env":"staging"}'
|
|
113
|
+
python3 api.py '{"command":"list_orders","user_id":"user_123","env":"staging"}'
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
To point this at a real API: replace `_mock_request()` with actual HTTP
|
|
117
|
+
calls (e.g. via `requests`) against `env["base_url"]`, authenticated with
|
|
118
|
+
`env["token"]`. Copy `environments.example.json` to `environments.json`
|
|
119
|
+
and fill in real tokens — that file is gitignored so secrets never get
|
|
120
|
+
committed.
|
|
121
|
+
|
|
122
|
+
## Design notes
|
|
123
|
+
|
|
124
|
+
- **No app-specific defaults.** Package names, landmark screen text, and
|
|
125
|
+
APK paths are always passed in by the caller — this tool knows nothing
|
|
126
|
+
about any particular app.
|
|
127
|
+
- **Text/description first, coordinates as fallback.** Tapping by visible
|
|
128
|
+
label is far more robust to minor layout shifts than fixed coordinates,
|
|
129
|
+
but `tap` and `input_sequence` both support coordinate fallbacks for the
|
|
130
|
+
cases where an element genuinely has no usable label.
|
|
131
|
+
- **`tap_selector` for non-text elements.** SVG/canvas/custom-rendered UI
|
|
132
|
+
often has no `text` or `content-desc` at all — `tap_selector` exposes
|
|
133
|
+
the underlying uiautomator2 `Selector` kwargs (`className`, `instance`,
|
|
134
|
+
`resourceId`, etc.) for those cases.
|
|
135
|
+
- **`set_location` is necessarily a bit app-specific.** Mock-location apps
|
|
136
|
+
all have different UIs, so this action drives a fairly common
|
|
137
|
+
"menu → search → lat/lon fields → OK → Start" shape and exposes the
|
|
138
|
+
parts likely to need adjusting (`menu_coords`, package names) as
|
|
139
|
+
arguments rather than hardcoding them. You may need to adapt the field
|
|
140
|
+
labels for whichever mock-location app you use — see the docstring.
|
|
141
|
+
|
|
142
|
+
## What this is not
|
|
143
|
+
|
|
144
|
+
This isn't a full test framework — there's no assertion library, test
|
|
145
|
+
runner, or reporting built in. It's the device-control layer you'd build
|
|
146
|
+
one on top of. If you're looking for that, this plays well alongside
|
|
147
|
+
`pytest` (treat each action's `"ok"` field and `"screen"` contents as your
|
|
148
|
+
assertions) or an agent framework that can shell out and parse JSON.
|
|
149
|
+
|
|
150
|
+
## Testing
|
|
151
|
+
|
|
152
|
+
The test suite runs against a fake in-memory device — **no real Android
|
|
153
|
+
device or emulator required**:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pip install -r requirements-dev.txt
|
|
157
|
+
pytest tests/ -v
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development workflow.
|
|
161
|
+
|
|
162
|
+
## Contributing
|
|
163
|
+
|
|
164
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
tapium.py
|
|
5
|
+
tapium.egg-info/PKG-INFO
|
|
6
|
+
tapium.egg-info/SOURCES.txt
|
|
7
|
+
tapium.egg-info/dependency_links.txt
|
|
8
|
+
tapium.egg-info/entry_points.txt
|
|
9
|
+
tapium.egg-info/requires.txt
|
|
10
|
+
tapium.egg-info/top_level.txt
|
|
11
|
+
tests/test_actions.py
|
|
12
|
+
tests/test_cli.py
|
|
13
|
+
tests/test_pure_helpers.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
uiautomator2>=3.4.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tapium
|