handsets — Python bindings
A small, Pythonic wrapper around the Handsets
CLI (hs). Drives Android devices from Python without reimplementing the
subprocess + JSON-parse + exit-code boilerplate every caller used to write
by hand.
Install
pip install handsets
You also need the hs binary on $PATH. See the project
install instructions.
Usage
from handsets import Session
with Session() as d: # `hs use` on enter, `hs drop` on exit
for node in d.ui():
print(node.cls, node.text, node.coords)
d.tap("Continue") # text lookup
d.tap(540, 860) # raw coords
d.fill("EditText", "you@x.com") # atomic ACTION_SET_TEXT against the selector
d.type("hello") # keystrokes to the focused field
d.submit()
d.wait(text="Welcome", timeout="15s")
Errors map to typed exceptions:
from handsets import Session, NotFound, Timeout, Ambiguous
try:
d.tap("Submit", unique=True, timeout="5s")
except NotFound:
... # exit code 2 — selector matched nothing
except Timeout:
... # exit code 3 — wait budget exhausted
except Ambiguous:
... # exit code 4 — --unique saw multiple matches
Everything else (daemon errors, bad arguments, secure-window blocks)
raises a generic HandsetsError whose .code attribute carries the
structured ErrCode enum value from the CLI's JSON output.
Batching
For tight loops, Session.batch() opens a warm-socket context that
keeps one hs run - subprocess alive across calls. Per-call process
startup (~5–10 ms each) collapses into one startup for the whole batch:
with Session() as d:
with d.batch(timeout="5s", retries=2) as b:
for label in labels_to_press:
b.tap(label, visible=True)
b.wait(text="Done")
batch() covers the action verbs (tap, type, fill, submit,
paste, wait, go, swipe). Query verbs (find, ui) still spawn
per-call — they emit multiple JSON lines which would desync the batch
read loop.
Talking to a specific device
Session(serial="PIXEL6_SERIAL")
Multiple sessions can run side-by-side; each one shells out independently.
Why a thin wrapper?
The CLI already does the hard work: warm daemon, push-mirrored state,
millisecond round-trips. The Python layer's job is to make that ergonomic
— context managers, typed exceptions, no manual subprocess.run. Future
versions may keep an hs run subprocess warm and stream commands over its
stdin to amortise per-call process overhead.
Metadata
Release files for handsets 0.1.38
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| handsets-0.1.38.tar.gz | 9.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| handsets-0.1.38-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.4 kB
Release files / handsets-0.1.38.tar.gz
| Download URL | handsets-0.1.38.tar.gz |
|---|---|
| Size | 9.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e2fc9e1f00bbb0421278e702e37f68ca482336b7cd49f14d07e80f3e700c47fd
|
|
BLAKE2b-256 checksum How to use checksums |
681c6303dce3c61aae5af57b48156088d56a4e5f9a02e9ae351ac8abd6fd0462
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.9
|
Release files / handsets-0.1.38-py3-none-any.whl
| Download URL | handsets-0.1.38-py3-none-any.whl |
|---|---|
| Size | 9.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9412d3bb24122a3269420bc6d91022941014f3d076313a95853dc15cc9879f47
|
|
BLAKE2b-256 checksum How to use checksums |
553e98cb502c67a9e2fd2dc43e657e751258b77c5f9848474ede4d57b2fa7392
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.9
|
Security for handsets 0.1.38
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.