Client and connections¶
TapClient finds the running server; TapConnection attaches devices and holds them. The
server's device list and info types, and starting the server from code. Guide:
The tap server, Python + pytest.
TapClient
¶
One gRPC channel to a host server. Cheap to create; share one per process.
:meth:create is the usual entry point: it resolves the endpoint (see
:func:resolve_endpoint) and, when discovering from daemon.json, checks that the
server answers Info. The constructor takes an already-resolved :class:Endpoint and
does no I/O. Use it as a context manager, or call :meth:close when done.
Methods:
| Name | Description |
|---|---|
create |
A client for |
info |
Daemon version and pid, protocol version, ADB executable, state dir, whether the |
devices |
Every device ADB lists, with its state ( |
connect |
Open a |
connections |
Every live client connection, held or observed, with the devices attached to it. |
resume |
The held connection named |
close |
Closes the channel. Close every |
create
¶
create(address: str | None = None, token: str | None = None) -> TapClient
A client for address (token: token or TAP_TOKEN), or for TAP_SERVER,
or for the live server daemon.json records. Raises TapError telling you to run
tap start when none is running. Never starts a server.
info
¶
info() -> ServerInfo
Daemon version and pid, protocol version, ADB executable, state dir, whether the
daemon carries a driver to install (driver_available) and its default timeouts.
devices
¶
devices() -> list[DeviceEntry]
Every device ADB lists, with its state (FREE, LEASED, QUARANTINED,
OFFLINE, UNAUTHORIZED); only FREE and LEASED devices can be attached.
connect
¶
connect(name: str, first_event_timeout: float = FIRST_EVENT_TIMEOUT, *, hold: float | None = None) -> TapConnection
Open a TapConnection named name.
By default the connection is observed: its liveness stream is established before this
returns (the server's first event, observing, is awaited for up to
first_event_timeout seconds, else TapError and the new id is disconnected), so
every later attach_device belongs to a live connection: if this process dies, the
server detaches every device the connection owns. A later closing event (the daemon
reaped the connection or is shutting down) makes it unusable with the daemon's reason.
With hold (seconds, 1 to 86400) the connection is held instead: it has no liveness
stream and outlives this process, so a later process can pick it up with :meth:resume.
Every call naming it restarts its idle clock; it ends after hold seconds without one,
on close from any process, or when the daemon stops. Its name must be unique among
held connections (else ServerError, reason DAEMON_PRECONDITION). Tests should
keep the default: a crashed test run would otherwise hold its devices until the timeout.
hold is experimental (the agent surface): it may change in any release.
Use the result as a context manager, or call close when done.
connections
¶
connections() -> list[ConnectionEntry]
Every live client connection, held or observed, with the devices attached to it.
resume
¶
resume(name: str) -> TapConnection
The held connection named name (see connect(..., hold=...)), for this process
to use; attached_devices() returns its devices. Raises TapError when no held
connection has that name (it was closed, or it expired).
Experimental: not covered by the compatibility promise; it may change in any release.
TapConnection
¶
An identity at the server that owns attached devices, returned by TapClient.connect.
An observed connection (the default) has its liveness stream already running on a
background thread. If this process dies, the server detaches every device owned by the
connection. If the stream ends unexpectedly (server restart, network loss) or the daemon
sends closing, the connection becomes unusable: attach_device and every call on its
devices raise TapError (broken holds the cause).
A held connection (hold is its idle timeout in seconds) has no stream: it lives in the
daemon until close, its idle timeout, or daemon shutdown, and other processes reach it
with TapClient.resume. Dropping the object without close leaves it for them.
Methods:
| Name | Description |
|---|---|
ensure_usable |
Raises |
available_serials |
Serials a test can use, from |
attach_device |
Attach |
attached_devices |
The devices attached to this connection now, as |
close |
Disconnects (the server detaches this connection's devices), then drops the liveness |
event_log |
The device calls this connection made, as the server logged them: every command |
hold
¶
hold: float | None
For a held connection, the idle timeout in seconds after which the server ends it;
None for an ordinary one that ends with this process (experimental).
broken
¶
broken: TapError | None
Why the liveness stream ended unexpectedly, or None while it is healthy.
usable
¶
usable: bool
True while the connection can attach devices: not closed and its stream is alive.
events
¶
events: list[str]
The most recent liveness-stream events (at most MAX_EVENTS), oldest first:
observing and closing: <reason>; heartbeats are not recorded.
ensure_usable
¶
ensure_usable(operation: str) -> None
Raises TapError when the connection is closed or its liveness stream ended.
available_serials
¶
available_serials() -> list[str]
Serials a test can use, from TapClient.devices: online and not quarantined, free
ones first, then ones another session holds (attach_device then waits for them when
wait_for_device is set). Exclusive use is enforced by the session itself, so there is
nothing to acquire beforehand.
attach_device
¶
attach_device(serial: str, *, timeouts: Timeouts | None = None, skip_driver_install: bool = False, wait_for_device: float = 0) -> Device
Attach serial: install and start the driver (unless skip_driver_install) and
take the device's session. timeouts are this device's defaults;
wait_for_device > 0 waits that many seconds for another session to release it.
Raises TapError without an RPC once the connection is closed or broken.
attached_devices
¶
The devices attached to this connection now, as Device objects — including ones
another process attached to a held connection. Nothing is re-attached: each keeps its
session and generation. timeouts are this process's defaults for them. Raises
TapError when the connection no longer exists at the server.
close
¶
close() -> None
Disconnects (the server detaches this connection's devices), then drops the liveness stream. For a held connection this ends it for every process. Idempotent: later calls do nothing.
event_log
¶
event_log(after_seq: int = 0) -> EventLog
The device calls this connection made, as the server logged them: every command
except the diagnostic device_info / dump_hierarchy, and the app calls that change
the device (install, uninstall, force-stop, clear-data, grant, launch, cold launch).
Only events with seq > after_seq. A selector appears as sent, so a snapshot ref shows
as the selector it named. The log is data, for turning a session into a test in any
language; nothing renders code from it. Typed text is recorded verbatim, passwords
included.
Experimental: not covered by the compatibility promise; it may change in any release.
Endpoint
¶
start_daemon
¶
start_daemon(binary: str | None = None, directory: Path | None = None, adb: str | None = None, timeout: float = 45.0) -> DaemonStartResult
tap start: starts the daemon in the background unless one is already running in the
state dir. The executable picks the port, detaches the process and waits for Info to
answer; nothing is parsed from the daemon process itself.
stop_daemon
¶
stop_daemon(binary: str | None = None, directory: Path | None = None, timeout: float = 30.0) -> None
tap stop: stops the daemon recorded in the state dir; a no-op when none is running.
DaemonStartResult
¶
DeviceEntry
¶
One device ADB lists (TapClient.devices()). client_connection_id is the holding
connection when this daemon holds the device; quarantine_reason says why it is
QUARANTINED.
DeviceState
¶
ServerInfo
¶
What the server reports about itself (TapClient.info()).
ServerDefaults
¶
ConnectionEntry
¶
A live client connection (TapClient.connections()). hold is the idle timeout in
seconds of a held connection, None for an observed one; idle is how long, in seconds,
no call has named it (0 while one is running).