Python API Reference
The xa11y Python package provides bindings to the xa11y Rust library via PyO3.
Install from PyPI:
pip install xa11yQuick start:
import xa11y
safari = xa11y.App.by_name("Safari")
for button in safari.locator("button").elements(): print(button.name)
safari.locator("button[name='OK']").press()Module Functions
Section titled “Module Functions”xa11y.locator() → Locator
Section titled “xa11y.locator() → Locator”Create a top-level Locator searching from the system root.
| Parameter | Type | Default |
|---|---|---|
selector |
str |
xa11y.set_default_timeout() → None
Section titled “xa11y.set_default_timeout() → None”Set the process-wide default timeout, in seconds.
Becomes the default for every auto-waiting action method, wait_*
call, and app lookup (App.by_name / App.by_pid / App.find)
that doesn’t pass an explicit timeout=. An explicit per-call
timeout= always wins. Takes precedence over the
XA11Y_DEFAULT_TIMEOUT environment variable (seconds, read once at
import).
Pass 0 for “single attempt, no polling” semantics. Raises
ValueError for negative or non-finite values.
| Parameter | Type | Default |
|---|---|---|
timeout |
float |
xa11y.get_default_timeout() → float
Section titled “xa11y.get_default_timeout() → float”Get the effective process-wide default timeout, in seconds.
Resolution order: the set_default_timeout value, else the
XA11Y_DEFAULT_TIMEOUT environment variable, else the built-in 5.0.
xa11y.capabilities() → Capabilities
Section titled “xa11y.capabilities() → Capabilities”What a platform’s backend can report: one answer per feature, read from a static table without connecting to any app.
With no arguments, describes the running platform and OS version. Pass
platform to describe another one, and os_version to narrow it to
an OS release.
| Parameter | Type | Default |
|---|---|---|
platform |
PlatformName | None |
None |
os_version |
str | None |
None |
backend |
str | None |
None |
xa11y.input_sim() → InputSim
Section titled “xa11y.input_sim() → InputSim”Construct an InputSim backed by the platform’s native input path.
xa11y.screenshot() → Screenshot
Section titled “xa11y.screenshot() → Screenshot”Capture pixels from the screen.
With no arguments, captures the full primary display. Pass element
to capture the pixels under an element’s current bounds, or region
as (x, y, width, height) to capture an explicit rectangle in logical
screen coordinates. Passing both raises ValueError.
annotate draws a numbered box over every element each locator
matches, and fills in Screenshot.legend,
Screenshot.omitted and Screenshot.truncated. Each entry
is one group, with its own colour and tag letter, and must be scoped to
an application: app.locator("button"). An entry that is neither a
Locator nor a str raises TypeError.
A rootless group raises InvalidSelectorError — a bare str, or
locator, searches every application, and each entry’s
<selector>:nth(n) would then count within one application while the
legend counts across all of them. The two agree only for a single
application, so the selector on an entry would name a different element
than the box it labels.
Cropping and annotating are independent: annotations outside the
captured area land in omitted rather than being clamped to an edge.
shot = xa11y.screenshot( element=app.locator(“window”).element(), annotate=[app.locator(“button”), app.locator(“text_field”)], )
| Parameter | Type | Default |
|---|---|---|
element |
Element | None |
None |
region |
tuple[int, int, int, int] | None |
None |
annotate |
list[Locator | str] | None |
None |
Classes
Section titled “Classes”Locator
Section titled “Locator”A resilient element reference that re-queries on each interaction.
Locators never hold a live reference to a UI element. Instead, they store
a selector and resolve it on demand, making them immune to staleness.
Action methods auto-wait for the element to appear before acting, using
the process-wide default timeout (5 seconds unless overridden via
set_default_timeout or the XA11Y_DEFAULT_TIMEOUT environment
variable). wait_* methods use the same default when no explicit
timeout= is passed.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
selector |
str |
The CSS-like selector string for this locator. |
Navigation
Section titled “Navigation”| Method | Returns | Description |
|---|---|---|
nth(n: int) |
Locator |
Return a new Locator that selects the n-th match (1-based). |
first() |
Locator |
Return a new Locator that selects the first match. |
child(selector: str) |
Locator |
Return a new Locator scoped to direct children matching selector. |
descendant(selector: str) |
Locator |
Return a new Locator scoped to descendants matching selector. |
Inspection
Section titled “Inspection”| Method | Returns | Description |
|---|---|---|
exists() |
bool |
Check if a matching element exists. |
count() |
int |
Count matching elements. |
element() |
Element |
Get a single Element handle for the matched element. |
elements() |
list[Element] |
Get all matching elements. |
Actions
Section titled “Actions”| Method | Returns | Description |
|---|---|---|
capture(*, max_depth: int | None = None, max_nodes: int = 2000, max_text_bytes: int = 65536, detail: Iterable[CaptureDetailName] | None = None, timeout: float | None = None, max_runs: int = 4096, cancel: CancelToken | None = None) |
Capture |
Read the subtree into a bounded Capture: every node read, |
tree(max_depth: int | None = None) |
dict |
Capture the subtree rooted at the matched element as a recursive dict. |
dump(max_depth: int | None = None) |
str |
Render the subtree rooted at the matched element as an indented string. |
press() |
Click / invoke the matched element. | |
focus() |
Set keyboard focus on the matched element. | |
blur() |
Remove keyboard focus from the matched element. | |
toggle() |
Toggle the matched element (checkbox, switch). | |
expand() |
Expand the matched element. | |
collapse() |
Collapse the matched element. | |
select() |
Select the matched element (list item, tab, etc.). | |
show_menu() |
Show the context menu for the matched element. | |
scroll_into_view() |
Scroll the matched element into the visible area. | |
increment() |
Increment the matched element (slider, spinner). | |
decrement() |
Decrement the matched element (slider, spinner). | |
set_value(value: str) |
Set the text value of the matched element. | |
set_numeric_value(value: float) |
Set the numeric value of the matched element (slider, spinner). | |
type_text(text: str) |
Type text at the current cursor position on the matched element. | |
select_text(start: int | RangeLike, end: int | None = None) |
Select a text range within the matched element: (start, end) or a |
|
text() |
Text |
The matched element’s text, read by range. Re-resolves the locator on |
perform_action(action: str) |
Perform an action by snake_case name. | |
activate() |
Activate the matched window: bring it to the foreground and give it focus. | |
minimize() |
Minimize the matched window. | |
maximize() |
Maximize the matched window. | |
enter_fullscreen() |
Put the matched window in native fullscreen. | |
restore() |
Restore the matched window to its normal state (from minimized, | |
close() |
Close the matched window. | |
move_to(x: int, y: int) |
Move the matched window to the given logical screen coordinates (top-left origin). | |
resize_to(width: int, height: int) |
Resize the matched window to the given logical dimensions. |
Waiting
Section titled “Waiting”| Method | Returns | Description |
|---|---|---|
wait_visible(timeout: float | None = None) |
Element |
Wait until the element is visible, polling the provider. |
wait_attached(timeout: float | None = None) |
Element |
Wait until the element exists in the tree. |
wait_detached(timeout: float | None = None) |
Wait until the element is removed from the tree. | |
wait_enabled(timeout: float | None = None) |
Element |
Wait until the element is enabled. |
wait_hidden(timeout: float | None = None) |
Wait until the element is hidden or removed. | |
wait_disabled(timeout: float | None = None) |
Element |
Wait until the element is disabled. |
wait_focused(timeout: float | None = None) |
Element |
Wait until the element has keyboard focus. |
wait_unfocused(timeout: float | None = None) |
Element |
Wait until the element does not have keyboard focus. |
wait_stable(timeout: float | None = None) |
Element |
Wait until visible bounds are observed unchanged for at least 750 ms |
wait_until(predicate: Callable[[Element | None], bool], timeout: float | None = None) |
Wait until an arbitrary predicate is satisfied. |
ElementStaleError
Section titled “ElementStaleError”The element no longer names a live node, so nothing was done to it.
A subclass of SelectorNotMatchedError, so existing handlers keep
catching it. xa11y never re-matches a stale element by name: re-resolve
with a locator to act on whatever is there now.
Attributes
Section titled “Attributes”| Attribute | Type | Description |
|---|---|---|
reason |
Literal['removed', 'process_exited', 'process_restarted', 'identity_changed', 'evicted'] |
Why: "removed" (the node is gone), "process_exited", |
element |
str |
What was captured: role "name", or the handle when that is all |
selector |
str | None |
The same description as element. A stale element was never found |
InvalidTextRangeError
Section titled “InvalidTextRangeError”A text range is out of bounds, reversed, or splits a surrogate pair.
Offsets are UTF-16 code units. length is the text’s current length when
the check knew it, so a range made stale by an edit says how long the text
is now.
Attributes
Section titled “Attributes”| Attribute | Type | Description |
|---|---|---|
start |
int |
Start of the refused range (UTF-16 code units). |
end |
int |
End of the refused range (UTF-16 code units). |
length |
int | None |
The text’s length when the check knew it, else None. |
TableInfo
Section titled “TableInfo”Size of a table, grid or tree grid. Each count is None when not
reported.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
row_count |
CountValue | None |
Number of rows: int, "unknown", or None. |
column_count |
CountValue | None |
Number of columns: int, "unknown", or None. |
CellInfo
Section titled “CellInfo”Row, column and spans of a table cell. Every index is 0-based; a field
the platform did not report is None.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
row |
int | None |
0-based row index. |
column |
int | None |
0-based column index. |
row_span |
int | None |
Rows the cell covers (at least 1), or None when not reported. |
column_span |
int | None |
Columns the cell covers (at least 1), or None when not reported. |
kind |
Literal['data', 'column_header', 'row_header'] | None |
"data", "column_header" or "row_header", or None when |
header |
Literal['column', 'row'] | None |
"column" or "row" for a header cell, else None (a data cell, |
RowInfo
Section titled “RowInfo”Row index of a table or tree-grid row (0-based).
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
index |
int | None |
0-based row index in the table, or None when not reported. |
CollectionInfo
Section titled “CollectionInfo”Position of an item in a list, tree, tab list or radio group.
index and depth are 0-based: the first item is 0, a top-level
tree item has depth 0. To show “3 of 10”, add 1 to index.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
index |
int | None |
0-based position in the set. |
size |
CountValue | None |
Number of items in the set: int, "unknown", or None. |
depth |
int | None |
0-based nesting depth. |
LiveRegionInfo
Section titled “LiveRegionInfo”Live-region settings of an element. Every field is None when the
platform did not report it.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
politeness |
PolitenessName | None |
"off", "polite" or "assertive". |
atomic |
bool | None |
Whether the whole region is announced when part of it changes. |
relevant |
str | None |
Which changes are announced, as the platform spells it |
Relation
Section titled “Relation”One kind of relation and the elements it points at, as
Element.relations returns it.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
kind |
Literal['labelled_by', 'label_for', 'described_by', 'description_for', 'details', 'details_for', 'controls', 'controlled_by', 'flows_to', 'flows_from', 'error_message', 'error_for', 'owns', 'member_of', 'linked'] |
The relation kind, in snake_case ("labelled_by", "controls"). |
elements |
list[Element] |
The related elements, in platform order; [] for a kind the |
CancelToken
Section titled “CancelToken”Stops a capture in progress. Pass it as capture(cancel=token) and
call cancel from any thread: the walk checks it between nodes.
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
cancel() |
Ask every capture holding this token to stop. Idempotent. | |
is_cancelled() |
bool |
Whether cancel has been called. |
CaptureStats
Section titled “CaptureStats”How many platform reads a capture made, by kind. A structure-only capture makes only children and identity reads.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
children_reads |
int |
Child-list reads, one per node whose children were read. |
identity_reads |
int |
Identity reads, one per node. |
text_reads |
int |
Text reads ("text" detail). |
formatting_reads |
int |
Attribute runs read ("formatting" detail). |
relation_reads |
int |
Relation reads ("relations" detail). |
text_bytes |
int |
Bytes of text read. |
Truncation
Section titled “Truncation”Which limits dropped something. A limit that was reached without dropping anything is not reported.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
by_depth |
bool |
Children below max_depth were left out. |
by_nodes |
bool |
Nodes past max_nodes were left out. |
by_text |
bool |
Text past max_text_bytes was left out. |
by_time |
bool |
The time budget ran out before the walk finished. |
by_formatting |
bool |
Attribute runs past max_runs were left out. |
by_cancel |
bool |
The cancel token was cancelled before the walk finished. |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
any() |
bool |
Whether any limit dropped something. |
CapturedText
Section titled “CapturedText”An element’s text, as far as the capture’s text budget reached.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
content |
str |
The text read, from offset 0. |
length |
int |
The element’s full text length, in UTF-16 code units. |
truncated |
bool |
Whether content stops short of length. |
runs |
list[TextRun] | None |
With detail={"formatting"}: the attribute runs over |
runs_truncated |
bool |
Whether runs past max_runs were left out of runs. |
CaptureError
Section titled “CaptureError”A read of one node that failed. The capture continued past it.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
step |
Literal['children', 'identity', 'text', 'formatting', 'relations', 'cycle'] |
What was being read: "children", "identity", "text", |
error |
XA11yError |
The exception the read raised, as an xa11y exception instance. |
CapturedRelation
Section titled “CapturedRelation”One kind of relation on a CapturedNode and its targets.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
kind |
Literal['labelled_by', 'label_for', 'described_by', 'description_for', 'details', 'details_for', 'controls', 'controlled_by', 'flows_to', 'flows_from', 'error_message', 'error_for', 'owns', 'member_of', 'linked'] |
The relation kind, in snake_case ("labelled_by", "controls"). |
targets |
list[int | Element] |
The targets, in platform order: an int index into |
CapturedNode
Section titled “CapturedNode”One node of a Capture.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
index |
int |
Index in Capture.nodes, which is pre-order. 0-based. |
parent |
int | None |
The parent’s index; None on the root. |
depth |
int |
Depth below the root, which is 0. |
element |
Element |
The element, which names exactly this node: actions on it reach it or |
children |
list[int] |
Indices of the children in the capture, in platform order. |
children_count |
int | None |
How many children the node has, including ones the capture left out. |
children_truncated |
bool |
Whether children of this node are missing from the capture. |
errors |
list[CaptureError] |
Reads of this node that failed. |
text |
CapturedText | None |
The node’s text, with detail={"text"}, when it has a text |
relations |
list[CapturedRelation] |
With detail={"relations"}: one CapturedRelation per kind |
role |
str |
Shortcut for element.role. |
name |
str | None |
Shortcut for element.name. |
Capture
Section titled “Capture”A bounded read of a subtree: every node read, pre-order, and which limits
cut it. See Element.capture.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
nodes |
list[CapturedNode] |
Every node read, pre-order. The root is index 0. |
truncated |
Truncation |
Which limits dropped something. |
vanished |
int |
Nodes that disappeared while the capture read them, and were dropped. |
started |
float |
When the walk began, in seconds since the epoch. |
finished |
float |
When the walk ended, in seconds since the epoch. |
backend |
str | None |
Which platform API read the nodes: "atspi", "ax", |
stats |
CaptureStats |
How many platform reads the capture made, by kind. |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
root() |
CapturedNode |
The root node. |
subtree(index: int) |
list[CapturedNode] |
The nodes of index’s subtree, itself first, in pre-order. Empty |
TextRange
Section titled “TextRange”A half-open range [start, end) of UTF-16 code units.
Anywhere a range is accepted, a (start, end) tuple works too.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
start |
int |
0-based offset of the first unit. |
end |
int |
0-based offset one past the last unit. |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
len() |
int |
Number of UTF-16 code units covered. |
is_empty() |
bool |
Whether the range covers nothing (a caret position). |
TextAttributes
Section titled “TextAttributes”Formatting of a run of text. Every attribute is None when the
platform did not report it; nothing is defaulted.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
font_family |
str | None |
Font family name. |
font_size |
float | None |
Font size in points. |
font_weight |
int | None |
Font weight on the CSS scale: 400 normal, 700 bold. |
italic |
bool | None |
Italic or oblique. |
underline |
bool | None |
Underlined. |
strikethrough |
bool | None |
Struck through. |
foreground |
str | None |
Text colour as "#rrggbb" or "#rrggbbaa". |
background |
str | None |
Background colour as "#rrggbb" or "#rrggbbaa". |
script |
Literal['baseline', 'superscript', 'subscript'] | None |
"baseline", "superscript" or "subscript". |
spelling_error |
bool | None |
Marked as a spelling error. |
TextRun
Section titled “TextRun”A run of text sharing one set of attributes.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
range |
TextRange |
The text the run covers. |
attributes |
TextAttributes |
Its formatting. |
TextLines
Section titled “TextLines”One page of rendered lines from Text.lines.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
lines |
list[TextRange] |
The lines, each clipped to the requested range. |
truncated |
bool |
Whether the limit stopped the walk before the end of the range. |
next_start |
int | None |
Where to start the next page; set exactly when truncated. |
TextRuns
Section titled “TextRuns”One page of formatting runs from Text.runs.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
runs |
list[TextRun] |
The runs, each clipped to the requested range. |
truncated |
bool |
Whether the limit stopped the walk before the end of the range. |
next_start |
int | None |
Where to start the next page; set exactly when truncated. |
TextChange
Section titled “TextChange”What a text_changed event inserted or deleted (Event.text_change).
Each field is what the platform supplied: range is None when it
counts offsets in a unit other than UTF-16 (on Linux, every toolkit but
Qt), and text is None when it does not send the text.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
kind |
Literal['inserted', 'deleted'] |
"inserted" or "deleted". |
range |
TextRange | None |
Where, in UTF-16 code units: for an insertion the range the new text |
text |
str | None |
The inserted or deleted text, or None when not supplied. |
An element’s text, read by range. Every method is a live platform
read; offsets are UTF-16 code units, so use read rather than slicing
Element.value when the text may contain emoji.
From Element.text() it stays bound to that element. From
Locator.text() it re-resolves the locator on every read.
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
length() |
int |
Length in UTF-16 code units, without reading the text where the |
caret() |
int | None |
The caret offset. None when the element is not focused. While a |
selections() |
list[TextRange] |
The selected ranges in document order; empty when nothing is selected. |
read(range: TextRange | tuple[int, int]) |
str |
The text in range (a TextRange or (start, end)), exactly |
read_all() |
str |
The whole text. |
find(needle: str, *, occurrence: int = 0, within: RangeLike | None = None) |
TextRange | None |
The occurrence-th (0-based) exact match of needle, searching |
object_at(offset: int) |
Element | None |
Live embedded object at a UTF-16 offset; unsupported on default backends. |
range_at(offset: int, unit: Literal['character', 'word', 'line', 'paragraph']) |
TextRange |
The unit ("character", "word", "line", |
lines(range: TextRange | tuple[int, int], limit: int = 200) |
TextLines |
Rendered lines covering range, at most limit per page. |
bounds(range: TextRange | tuple[int, int]) |
list[Rect] |
Screen rectangles of range, one per rendered line fragment, in the |
runs(range: TextRange | tuple[int, int], limit: int = 200) |
TextRuns |
Formatting runs covering range, at most limit per page. |
EventType
Section titled “EventType”Accessibility event type constants.
Each constant’s value is the string carried in Event.event_type,
so handlers can compare against the constant or the literal string
interchangeably.
Constants
Section titled “Constants”| Constant | Value | Description |
|---|---|---|
FOCUS_CHANGED |
'focus_changed' |
|
VALUE_CHANGED |
'value_changed' |
|
NAME_CHANGED |
'name_changed' |
|
STATE_CHANGED |
'state_changed' |
|
STRUCTURE_CHANGED |
'structure_changed' |
|
WINDOW_OPENED |
'window_opened' |
|
WINDOW_CLOSED |
'window_closed' |
|
WINDOW_ACTIVATED |
'window_activated' |
|
WINDOW_DEACTIVATED |
'window_deactivated' |
|
SELECTION_CHANGED |
'selection_changed' |
|
MENU_OPENED |
'menu_opened' |
|
MENU_CLOSED |
'menu_closed' |
|
TEXT_CHANGED |
'text_changed' |
|
TEXT_SELECTION_CHANGED |
'text_selection_changed' |
|
ANNOUNCEMENT |
'announcement' |
An accessibility event delivered to subscribers.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
event_type |
str |
|
app_name |
str |
|
app_pid |
int |
|
target |
Element | None |
|
state_flag |
str | None |
For state_changed events: the flag that changed (e.g. 'checked'). |
state_value |
bool | None |
For state_changed events: the new boolean value of the flag. |
text_change |
TextChange | None |
For text_changed events: what was inserted or deleted, when the |
sequence |
int |
Position in this subscription’s stream, from 0. A gap means events |
announcement |
AnnouncementInfo | None |
For announcement events: the origin and, where sent, the text. |
time |
float |
When the event was received, in seconds since the epoch. |
AnnouncementInfo
Section titled “AnnouncementInfo”What an announcement event carries (Event.announcement).
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
origin |
Literal['request', 'live_region', 'alert'] |
"request" (an app asked for text to be spoken), "live_region" |
text |
str | None |
The text to announce, for a request where the platform sends it. |
politeness |
PolitenessName | None |
"polite" or "assertive", normalised across platforms. |
platform_priority |
str | None |
The platform’s own priority, as it spells it. |
activity_id |
str | None |
UIA’s activityId (Windows only). |
Subscription
Section titled “Subscription”A live event subscription.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
dropped |
int |
How many events the buffer has dropped, in total, because it was full. |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
try_recv() |
Event | None |
|
recv(timeout: float = 5.0) |
Event |
|
wait_for(predicate: Callable[[Event], bool], timeout: float = 5.0) |
Event |
|
close() |
||
__iter__() |
Iterator[Event] |
A running application — the entry point for accessibility queries.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
name |
str |
|
pid |
int | None |
|
is_foreground |
bool |
Whether this application is the foreground application. |
focused |
bool |
Deprecated alias for is_foreground. |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
by_name(name: str, *, timeout: float | None = None, backend: str | None = None) |
App |
Find an application by exact name. |
by_pid(pid: int, *, timeout: float | None = None, backend: str | None = None) |
App |
Find an application by process ID. |
find(predicate: Callable[[App], bool], *, timeout: float | None = None, backend: str | None = None) |
App |
Find an application matching predicate. |
foreground(*, timeout: float | None = None, backend: str | None = None) |
App |
Resolve the application that currently holds the system foreground. |
list(*, backend: str | None = None) |
list[App] |
List all running applications. |
locator(selector: str) |
Locator |
Create a Locator scoped to this application’s accessibility tree. |
subscribe(*, kinds: Iterable[str] | None = None, buffer: int | None = None) |
Subscription |
Subscribe to accessibility events from this application. |
children() |
list[Element] |
Get direct children (typically windows) of this application. |
windows() |
list[Element] |
List the top-level windows of this application. |
enable_web_accessibility(*, timeout: float | None = None) |
Turn on the accessibility tree for the app’s web content, then wait | |
as_element() |
Element |
Get an Element handle for the application root. |
capture(*, max_depth: int | None = None, max_nodes: int = 2000, max_text_bytes: int = 65536, detail: Iterable[CaptureDetailName] | None = None, timeout: float | None = None, max_runs: int = 4096, cancel: CancelToken | None = None) |
Capture |
Read the subtree into a bounded Capture: every node read, |
tree(max_depth: int | None = None) |
dict |
Capture this application’s accessibility tree as a recursive dict. |
dump(max_depth: int | None = None) |
str |
Render this application’s accessibility tree as an indented string. |
ShellSurface
Section titled “ShellSurface”One OS-owned shell surface — the taskbar, a desktop panel, the dock, the menu bar, a process’s status items, the desktop, or an open flyout.
ShellSurface is not an Element. It represents the surface
as a whole and provides a locator() to search its accessibility tree,
exactly as App does for an application.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
kind |
Literal['menu_bar', 'status_items', 'taskbar', 'panel', 'dock', 'desktop', 'flyout', 'unknown'] |
What this surface is, as a snake_case string ("taskbar", |
name |
str |
The owning app for per-app surfaces ("Safari" menu bar), the |
pid |
int | None |
Owning process where the platform reports one honestly. On Windows |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
list() |
list[ShellSurface] |
List the OS shell surfaces currently on screen. |
by_kind(kind: Literal['menu_bar', 'status_items', 'taskbar', 'panel', 'dock', 'desktop', 'flyout', 'unknown'], *, timeout: float | None = None) |
ShellSurface |
Wait for exactly one shell surface of kind. |
locator(selector: str) |
Locator |
Create a Locator scoped to this surface’s accessibility tree. |
children() |
list[Element] |
Get direct children of the surface root. |
as_element() |
Element |
Get an Element handle for the surface root. |
capture(*, max_depth: int | None = None, max_nodes: int = 2000, max_text_bytes: int = 65536, detail: Iterable[CaptureDetailName] | None = None, timeout: float | None = None, max_runs: int = 4096, cancel: CancelToken | None = None) |
Capture |
Read the subtree into a bounded Capture: every node read, |
tree(max_depth: int | None = None) |
dict |
Capture this surface’s accessibility tree as a recursive dict. |
dump(max_depth: int | None = None) |
str |
Render this surface’s accessibility tree as an indented string. |
Element
Section titled “Element”A live element with lazy navigation.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
role |
str |
|
name |
str | None |
|
value |
str | None |
|
description |
str | None |
|
numeric_value |
float | None |
|
min_value |
float | None |
|
max_value |
float | None |
|
stable_id |
str | None |
|
pid |
int | None |
|
actions |
list[str] |
|
bounds |
Rect | None |
|
raw |
dict[str, object] |
Platform-specific raw data attached to this element. |
enabled |
bool |
|
visible |
bool |
|
hidden_reason |
HiddenReasonName | None |
Why the element is not visible, or None when it is. |
focused |
bool |
|
active |
bool |
Whether this element is the active (foreground) window. |
checked |
str | None |
Tri-state toggle value: 'on', 'off', 'mixed', or None. |
selected |
bool |
|
expanded |
bool | None |
|
editable |
bool |
|
focusable |
bool |
|
modal |
bool |
|
required |
bool |
|
busy |
bool |
|
password |
bool |
Whether this is a password (secure text) field. |
minimized |
bool | None |
Whether the window is minimized. |
maximized |
bool | None |
Whether the window is maximized. None = unknown / not a window. |
fullscreen |
bool | None |
Whether the window is fullscreen. None = unknown / not a window. |
table |
TableInfo | None |
Size of a table, grid or tree grid; None when not a table or not |
cell |
CellInfo | None |
Row, column and spans of a table cell (0-based); None otherwise. |
table_row |
RowInfo | None |
Row index of a table row (0-based); None otherwise. |
collection |
CollectionInfo | None |
Position in a list, tree, tab list or radio group (0-based index and |
heading_level |
int | None |
A heading’s level, 1 for a top-level heading (a level, not an |
landmark_type |
LandmarkName | None |
Which landmark a landmark element is, as its ARIA role; |
web_role |
str | None |
The ARIA role web content declares, verbatim; None outside web |
link_url |
str | None |
A link’s target URL; None on a non-link or when not reported. |
live_region |
LiveRegionInfo | None |
Live-region settings; None when the element has none. |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
same_as(other: Element) |
bool |
Whether other names the same platform node, checked live with |
check_alive() |
Prove this element still names the node it was found as. Raises | |
children() |
list[Element] |
Get direct children (lazy — each call queries the provider). |
parent() |
Element | None |
Get parent element (lazy — each call queries the provider). |
capture(*, max_depth: int | None = None, max_nodes: int = 2000, max_text_bytes: int = 65536, detail: Iterable[CaptureDetailName] | None = None, timeout: float | None = None, max_runs: int = 4096, cancel: CancelToken | None = None) |
Capture |
Read the subtree into a bounded Capture: every node read, |
tree(max_depth: int | None = None) |
dict |
Capture the subtree rooted at this element as a recursive dict snapshot. |
dump(max_depth: int | None = None) |
str |
Render the subtree rooted at this element as an indented string. |
subscribe(*, kinds: Iterable[str] | None = None, buffer: int | None = None) |
Subscription |
Subscribe to accessibility events for this element (typically an app). |
press() |
Click / invoke this element. | |
focus() |
Move keyboard focus to this element. | |
blur() |
Remove keyboard focus from this element. | |
toggle() |
Toggle this element’s checked state. | |
expand() |
Expand this element (e.g. tree node, combo box). | |
collapse() |
Collapse this element. | |
select() |
Select this element (e.g. list item, tab). | |
show_menu() |
Show this element’s context menu. | |
scroll_into_view() |
Scroll this element into view. | |
increment() |
Increment this element’s value (e.g. slider, spinner). | |
decrement() |
Decrement this element’s value. | |
set_value(value: str) |
Replace this element’s text value. | |
set_numeric_value(value: float) |
Set this element’s numeric value. | |
type_text(text: str) |
Insert text at the current cursor position. | |
select_text(start: int | RangeLike, end: int | None = None) |
Select a text range: select_text(start, end), or |
|
relations(kinds: list[RelationKindName] | None = None) |
list[Relation] |
The elements this one is related to, as a list of Relation |
text() |
Text |
This element’s text, read by range (UTF-16 offsets). Reads nothing |
cell_at(row: int, column: int) |
Element | None |
On a table: the cell at 0-based row / column (a merged cell |
column_headers() |
list[Element] |
On a table: its column header cells. |
row_headers() |
list[Element] |
On a table: its row header cells. |
column_header_cells() |
list[Element] |
On a cell: the column header cells that head it. |
row_header_cells() |
list[Element] |
On a cell: the row header cells that head it. |
selected_items() |
list[Element] |
On a list, tree, table or tab list: the selected items. |
perform_action(action: str) |
Perform an action by snake_case name. |
|
activate() |
Activate this window: bring it to the foreground and give it focus. | |
minimize() |
Minimize this window. | |
maximize() |
Maximize this window. | |
enter_fullscreen() |
Put this window in native fullscreen (macOS AXFullScreen). |
|
restore() |
Restore this window to its normal state (from minimized/maximized/fullscreen). | |
close() |
Close this window. | |
move_to(x: int, y: int) |
Move this window to the given logical screen coordinates (top-left origin). | |
resize_to(width: int, height: int) |
Resize this window to the given logical width and height. |
InputSim
Section titled “InputSim”Input-simulation façade for synthesised pointer and keyboard events.
Targets are either a (x, y) tuple in logical screen coordinates (same
space as Element.bounds), or an Element (uses its bounds centre);
each backend converts to physical device pixels at the OS boundary. Key
values are strings: printable characters
are literal ("a", "7", ";"); named keys use their Pascal name
("Enter", "ArrowUp", "F5"); modifiers are "Shift",
"Ctrl", "Alt", "Meta".
Input simulation is distinct from the accessibility action layer — prefer
Locator.press() / Locator.type_text() when the target exposes the
semantic action. Use InputSim for gestures with no a11y equivalent
(drag-and-drop, scroll wheels, global shortcuts).
Built-in backends reject pointer targets outside every active display
before sending input, with InvalidActionDataError. On Wayland,
raw points are checked against the compositor’s logical output layout, or
the XA11Y_SCREEN_WIDTH / XA11Y_SCREEN_HEIGHT override. This checks
screen membership, not visibility or hit testing. The error’s
pointer_target carries the requested point, checked coordinate space,
displays, and any element bounds and anchor.
Both drag endpoints are checked before the gesture. Captured moves while
this simulator holds a mouse button, and button releases, remain possible;
explicit clicks and scrolls still require an on-display target.
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
click(target: tuple[int, int] | Element, *, button: Literal['left', 'right', 'middle'] = 'left', count: int = 1, held: list[str] | None = None, anchor: AnchorName | tuple[int, int] | None = None) |
Click at target. |
|
double_click(target: tuple[int, int] | Element) |
Left double-click at target. |
|
right_click(target: tuple[int, int] | Element) |
Right-click at target. |
|
move_to(target: tuple[int, int] | Element) |
Move the pointer to target without pressing any button. |
|
mouse_down(button: Literal['left', 'right', 'middle'] = 'left') |
Press a mouse button at the current pointer location, without | |
mouse_up(button: Literal['left', 'right', 'middle'] = 'left') |
Release a mouse button at the current pointer location. | |
drag(start: tuple[int, int] | Element, end: tuple[int, int] | Element, *, button: Literal['left', 'right', 'middle'] = 'left', held: list[str] | None = None, duration: float = 0.15) |
Drag from start to end. |
|
scroll(target: tuple[int, int] | Element, dx: int = 0, dy: int = 0) |
Scroll at target, in wheel ticks. Positive dy scrolls down, toward |
|
press(key: str) |
Tap a key (press + release). | |
chord(key: str, held: list[str] = ...) |
Tap key while the keys in held are held down. |
|
key_down(key: str) |
Press key without releasing it. Pair with key_up. |
|
key_up(key: str) |
Release a key previously pressed with key_down. |
|
type_text(text: str) |
Type literal text into the currently focused control. |
LegendEntry
Section titled “LegendEntry”One drawn annotation box: the tag in the image, and the element it came from.
A model reads a tag off the PNG; selector is what acts on the element
that tag labels:
entry = next(e for e in shot.legend if e.tag == “B1”)
app.locator(entry.selector).set_value(“42”)
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
tag |
str |
What is drawn in the box — "B7". A group letter and a 1-based |
group |
int |
1-based, matching the position of this element’s locator in |
index |
int |
1-based, and exactly the :nth(n) argument in selector. |
selector |
str |
A selector usable as-is against the same scope the group had — |
role |
str |
The element’s role, snake_case as everywhere else. |
name |
str | None |
The element’s accessible name, when it has one. |
bounds |
Rect |
The element’s bounds in logical screen coordinates. |
color |
tuple[int, int, int] |
The box colour as an (r, g, b) tuple, for correlating a box |
Omission
Section titled “Omission”An element that matched an annotate= selector but is not in the
image.
Reported rather than dropped: a legend that disagreed with the picture, with no way to find out why, is what this exists to prevent.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
selector |
str |
The selector that would reach this element. |
role |
str |
The element’s role, snake_case. |
name |
str | None |
The element’s accessible name, when it has one. |
reason |
Literal['no_bounds', 'zero_area', 'outside_capture'] |
Why it could not be drawn: no bounds at all, zero-area bounds, or |
Screenshot
Section titled “Screenshot”A captured image: raw RGBA8 pixels plus dimensions and mapping.
width and height describe the actual returned image. scale is
a compatibility hint for simple single-display captures; use the explicit
coordinate methods for mixed-DPI, cropped, or resized images. pixels
has length width * height * 4.
legend, omitted and truncated describe what annotate=
drew. They are [], [] and 0 on an unannotated capture, so
consumers need no version check.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
width |
int |
|
height |
int |
|
scale |
float |
|
mapping_available |
bool |
Whether desktop/image coordinate conversion metadata is available. |
pixels |
bytes |
Raw RGBA8 pixel bytes (width * height * 4). |
legend |
list[LegendEntry] |
One entry per drawn box, in group order and then match order. |
omitted |
list[Omission] |
Elements that matched an annotate= selector but could not be |
truncated |
int |
How many matched elements were not described at all because the |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
to_png() |
bytes |
Encode the image as a PNG and return the bytes. |
save_png(path: str | bytes | object) |
Encode as PNG and write to path. Accepts str, bytes or os.PathLike. |
|
desktop_to_image(x: int, y: int) |
tuple[int, int] |
Convert a desktop point to a pixel in this image. |
image_to_desktop(x: int, y: int) |
tuple[int, int] |
Convert an image pixel to a desktop point suitable for input. |
desktop_rect_to_image(x: int, y: int, width: int, height: int) |
list[Rect] |
Convert a desktop rectangle to one image rectangle per display piece. |
crop(x: int, y: int, width: int, height: int) |
Screenshot |
Crop by image pixels while preserving coordinate mapping. |
resize(width: int, height: int) |
Screenshot |
Resize image pixels while scaling coordinate mapping. |
Capability
Section titled “Capability”One feature’s answer on one platform.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
name |
str |
Feature name, <area>:<name> ("event:menu_opened"). |
description |
str |
What the feature is, in one sentence. |
support |
Literal['supported', 'partial', 'unsupported'] |
"supported", "partial" or "unsupported". |
note |
str | None |
How the platform provides it, or why it does not; None when there |
since |
str | None |
The first OS version that supports it, when older ones do not. |
Capabilities
Section titled “Capabilities”Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
backend |
str |
|
platform |
Literal['linux', 'macos', 'windows'] |
The platform described. |
os_version |
str | None |
The OS version the answers were narrowed to, or None when none |
Methods
Section titled “Methods”| Method | Returns | Description |
|---|---|---|
names() |
list[str] |
Every feature name the table knows, in table order. |
entries() |
list[Capability] |
Every feature, in table order. |
get(name: str) |
Capability |
The capability named name. Raises InvalidActionDataError |
support(name: str) |
Literal['supported', 'partial', 'unsupported'] |
Shorthand for get(name).support. |
note(name: str) |
str | None |
Shorthand for get(name).note. |
contains(name: str) |
bool |
Whether name is a feature the table knows (also name in caps). |
__iter__() |
Iterator[Capability] |
Data Classes
Section titled “Data Classes”A bounding rectangle in logical screen coordinates (device-independent points) on every platform, origin at the top-left of the primary display.
Same coordinate space as screenshot(region=...) and input targets, so
bounds pass straight through. To index into a captured image multiply by
the screenshot’s scale (physical = logical * scale).
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
x |
int |
|
y |
int |
|
width |
int |
|
height |
int |
Exceptions
Section titled “Exceptions”All xa11y exceptions inherit from xa11y.XA11yError.
| Exception | Description |
|---|---|
XA11yError |
Base exception for all xa11y errors. |
PermissionDeniedError |
Accessibility permissions have not been granted. |
AccessibilityNotEnabledError |
The target app advertises an accessibility tree but it is empty. |
SelectorNotMatchedError |
No element in the tree matched the given selector. |
ActionNotSupportedError |
The requested action is not supported on the target element. |
TimeoutError |
An operation exceeded its timeout. |
InvalidSelectorError |
The selector string has invalid syntax. |
InvalidActionDataError |
An action received invalid data (e.g. Locator.nth(0), a |
PlatformError |
An OS-level accessibility error occurred. |