xa11y 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.
- xa11y-0.1.0/Cargo.toml +27 -0
- xa11y-0.1.0/PKG-INFO +21 -0
- xa11y-0.1.0/pyproject.toml +54 -0
- xa11y-0.1.0/python/xa11y/__init__.py +62 -0
- xa11y-0.1.0/python/xa11y/_native.pyi +278 -0
- xa11y-0.1.0/python/xa11y/py.typed +0 -0
- xa11y-0.1.0/xa11y/Cargo.toml +22 -0
- xa11y-0.1.0/xa11y/src/lib.rs +91 -0
- xa11y-0.1.0/xa11y/tests/INTEG_COVERAGE.md +175 -0
- xa11y-0.1.0/xa11y/tests/integ/mod.rs +100 -0
- xa11y-0.1.0/xa11y/tests/integ_test.rs +1812 -0
- xa11y-0.1.0/xa11y/tests/unit_test.rs +1075 -0
- xa11y-0.1.0/xa11y-core/Cargo.toml +15 -0
- xa11y-0.1.0/xa11y-core/src/action.rs +144 -0
- xa11y-0.1.0/xa11y-core/src/error.rs +50 -0
- xa11y-0.1.0/xa11y-core/src/event.rs +160 -0
- xa11y-0.1.0/xa11y-core/src/event_provider.rs +105 -0
- xa11y-0.1.0/xa11y-core/src/lib.rs +23 -0
- xa11y-0.1.0/xa11y-core/src/locator.rs +435 -0
- xa11y-0.1.0/xa11y-core/src/node.rs +181 -0
- xa11y-0.1.0/xa11y-core/src/provider.rs +91 -0
- xa11y-0.1.0/xa11y-core/src/role.rs +157 -0
- xa11y-0.1.0/xa11y-core/src/selector.rs +503 -0
- xa11y-0.1.0/xa11y-core/src/tree.rs +185 -0
- xa11y-0.1.0/xa11y-linux/Cargo.toml +13 -0
- xa11y-0.1.0/xa11y-linux/src/atspi.rs +1485 -0
- xa11y-0.1.0/xa11y-linux/src/lib.rs +16 -0
- xa11y-0.1.0/xa11y-linux/src/stub.rs +57 -0
- xa11y-0.1.0/xa11y-macos/Cargo.toml +16 -0
- xa11y-0.1.0/xa11y-macos/build.rs +13 -0
- xa11y-0.1.0/xa11y-macos/src/ax.rs +1863 -0
- xa11y-0.1.0/xa11y-macos/src/exception_safe.m +309 -0
- xa11y-0.1.0/xa11y-macos/src/lib.rs +71 -0
- xa11y-0.1.0/xa11y-python/.gitignore +7 -0
- xa11y-0.1.0/xa11y-python/Cargo.lock +1381 -0
- xa11y-0.1.0/xa11y-python/Cargo.toml +14 -0
- xa11y-0.1.0/xa11y-python/src/lib.rs +1740 -0
- xa11y-0.1.0/xa11y-python/tests/conftest.py +14 -0
- xa11y-0.1.0/xa11y-python/tests/test_actions.py +169 -0
- xa11y-0.1.0/xa11y-python/tests/test_exceptions.py +69 -0
- xa11y-0.1.0/xa11y-python/tests/test_locator.py +247 -0
- xa11y-0.1.0/xa11y-python/tests/test_module.py +76 -0
- xa11y-0.1.0/xa11y-python/tests/test_node.py +303 -0
- xa11y-0.1.0/xa11y-python/tests/test_provider.py +103 -0
- xa11y-0.1.0/xa11y-python/tests/test_tree.py +179 -0
- xa11y-0.1.0/xa11y-python/tests/test_typing.py +33 -0
- xa11y-0.1.0/xa11y-windows/Cargo.toml +20 -0
- xa11y-0.1.0/xa11y-windows/src/lib.rs +32 -0
- xa11y-0.1.0/xa11y-windows/src/stub.rs +36 -0
- xa11y-0.1.0/xa11y-windows/src/uia.rs +1620 -0
xa11y-0.1.0/Cargo.toml
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[workspace]
|
|
2
|
+
members = [
|
|
3
|
+
"xa11y-core",
|
|
4
|
+
"xa11y-macos",
|
|
5
|
+
"xa11y-windows",
|
|
6
|
+
"xa11y-linux",
|
|
7
|
+
"xa11y",
|
|
8
|
+
"xa11y-test-app",
|
|
9
|
+
"xa11y-fuzz",
|
|
10
|
+
]
|
|
11
|
+
exclude = ["xa11y-python"]
|
|
12
|
+
resolver = "2"
|
|
13
|
+
|
|
14
|
+
[workspace.package]
|
|
15
|
+
version = "0.1.1"
|
|
16
|
+
edition = "2021"
|
|
17
|
+
license = "MIT"
|
|
18
|
+
repository = "https://github.com/xa11y/xa11y"
|
|
19
|
+
|
|
20
|
+
[workspace.dependencies]
|
|
21
|
+
xa11y-core = { path = "xa11y-core", version = "0.1.1" }
|
|
22
|
+
xa11y-macos = { path = "xa11y-macos", version = "0.1.1" }
|
|
23
|
+
xa11y-windows = { path = "xa11y-windows", version = "0.1.1" }
|
|
24
|
+
xa11y-linux = { path = "xa11y-linux", version = "0.1.1" }
|
|
25
|
+
serde = { version = "1", features = ["derive"] }
|
|
26
|
+
serde_json = "1"
|
|
27
|
+
thiserror = "2"
|
xa11y-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xa11y
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Programming Language :: Rust
|
|
8
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
+
Classifier: Topic :: Software Development :: Testing
|
|
16
|
+
Summary: Cross-platform accessibility client library
|
|
17
|
+
Keywords: accessibility,a11y,automation,screen-reader
|
|
18
|
+
License-Expression: MIT
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Project-URL: Homepage, https://github.com/xa11y/xa11y
|
|
21
|
+
Project-URL: Repository, https://github.com/xa11y/xa11y
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["maturin>=1.0,<2.0"]
|
|
3
|
+
build-backend = "maturin"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xa11y"
|
|
7
|
+
requires-python = ">=3.9"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
description = "Cross-platform accessibility client library"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
keywords = ["accessibility", "a11y", "automation", "screen-reader"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Rust",
|
|
17
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Software Development :: Libraries",
|
|
24
|
+
"Topic :: Software Development :: Testing",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://github.com/xa11y/xa11y"
|
|
29
|
+
Repository = "https://github.com/xa11y/xa11y"
|
|
30
|
+
|
|
31
|
+
[tool.maturin]
|
|
32
|
+
features = ["pyo3/extension-module", "pyo3/abi3-py39"]
|
|
33
|
+
module-name = "xa11y._native"
|
|
34
|
+
manifest-path = "xa11y-python/Cargo.toml"
|
|
35
|
+
python-source = "python"
|
|
36
|
+
|
|
37
|
+
[tool.ruff]
|
|
38
|
+
target-version = "py39"
|
|
39
|
+
line-length = 100
|
|
40
|
+
|
|
41
|
+
[tool.ruff.lint]
|
|
42
|
+
select = [
|
|
43
|
+
"E", # pycodestyle errors
|
|
44
|
+
"W", # pycodestyle warnings
|
|
45
|
+
"F", # pyflakes
|
|
46
|
+
"I", # isort
|
|
47
|
+
"UP", # pyupgrade
|
|
48
|
+
"B", # flake8-bugbear
|
|
49
|
+
"SIM", # flake8-simplify
|
|
50
|
+
"RUF", # ruff-specific
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""xa11y — Cross-Platform Accessibility Client Library for Python.
|
|
2
|
+
|
|
3
|
+
Quick start:
|
|
4
|
+
>>> import xa11y
|
|
5
|
+
>>> tree = xa11y.app("Safari")
|
|
6
|
+
>>> for button in tree.query("button"):
|
|
7
|
+
... print(button.name)
|
|
8
|
+
>>> tree.press("button[name='OK']")
|
|
9
|
+
|
|
10
|
+
With explicit provider:
|
|
11
|
+
>>> with xa11y.connect() as provider:
|
|
12
|
+
... tree = provider.app("Safari")
|
|
13
|
+
... loc = tree.locator("button[name='Submit']")
|
|
14
|
+
... loc.press()
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from xa11y._native import (
|
|
18
|
+
ActionNotSupportedError,
|
|
19
|
+
AppInfo,
|
|
20
|
+
AppNotFoundError,
|
|
21
|
+
InvalidSelectorError,
|
|
22
|
+
Locator,
|
|
23
|
+
Node,
|
|
24
|
+
NormalizedRect,
|
|
25
|
+
PermissionDeniedError,
|
|
26
|
+
PlatformError,
|
|
27
|
+
# Classes
|
|
28
|
+
Provider,
|
|
29
|
+
Rect,
|
|
30
|
+
SelectorNotMatchedError,
|
|
31
|
+
TimeoutError,
|
|
32
|
+
Tree,
|
|
33
|
+
# Exceptions
|
|
34
|
+
XA11yError,
|
|
35
|
+
app,
|
|
36
|
+
check_permissions,
|
|
37
|
+
# Convenience functions
|
|
38
|
+
connect,
|
|
39
|
+
list_apps,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"ActionNotSupportedError",
|
|
44
|
+
"AppInfo",
|
|
45
|
+
"AppNotFoundError",
|
|
46
|
+
"InvalidSelectorError",
|
|
47
|
+
"Locator",
|
|
48
|
+
"Node",
|
|
49
|
+
"NormalizedRect",
|
|
50
|
+
"PermissionDeniedError",
|
|
51
|
+
"PlatformError",
|
|
52
|
+
"Provider",
|
|
53
|
+
"Rect",
|
|
54
|
+
"SelectorNotMatchedError",
|
|
55
|
+
"TimeoutError",
|
|
56
|
+
"Tree",
|
|
57
|
+
"XA11yError",
|
|
58
|
+
"app",
|
|
59
|
+
"check_permissions",
|
|
60
|
+
"connect",
|
|
61
|
+
"list_apps",
|
|
62
|
+
]
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Type stubs for the xa11y native extension module."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterator
|
|
6
|
+
from types import TracebackType
|
|
7
|
+
|
|
8
|
+
# ── Exceptions ───────────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
class XA11yError(Exception): ...
|
|
11
|
+
class PermissionDeniedError(XA11yError): ...
|
|
12
|
+
class AppNotFoundError(XA11yError): ...
|
|
13
|
+
class SelectorNotMatchedError(XA11yError): ...
|
|
14
|
+
class ActionNotSupportedError(XA11yError): ...
|
|
15
|
+
class TimeoutError(XA11yError): ...
|
|
16
|
+
class InvalidSelectorError(XA11yError): ...
|
|
17
|
+
class PlatformError(XA11yError): ...
|
|
18
|
+
|
|
19
|
+
# ── Data Classes ─────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
class Rect:
|
|
22
|
+
@property
|
|
23
|
+
def x(self) -> int: ...
|
|
24
|
+
@property
|
|
25
|
+
def y(self) -> int: ...
|
|
26
|
+
@property
|
|
27
|
+
def width(self) -> int: ...
|
|
28
|
+
@property
|
|
29
|
+
def height(self) -> int: ...
|
|
30
|
+
def __repr__(self) -> str: ...
|
|
31
|
+
def __eq__(self, other: object) -> bool: ...
|
|
32
|
+
|
|
33
|
+
class NormalizedRect:
|
|
34
|
+
@property
|
|
35
|
+
def left(self) -> float: ...
|
|
36
|
+
@property
|
|
37
|
+
def top(self) -> float: ...
|
|
38
|
+
@property
|
|
39
|
+
def right(self) -> float: ...
|
|
40
|
+
@property
|
|
41
|
+
def bottom(self) -> float: ...
|
|
42
|
+
def __repr__(self) -> str: ...
|
|
43
|
+
|
|
44
|
+
class AppInfo:
|
|
45
|
+
@property
|
|
46
|
+
def name(self) -> str: ...
|
|
47
|
+
@property
|
|
48
|
+
def pid(self) -> int: ...
|
|
49
|
+
@property
|
|
50
|
+
def bundle_id(self) -> str | None: ...
|
|
51
|
+
def __repr__(self) -> str: ...
|
|
52
|
+
|
|
53
|
+
# ── Node ─────────────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
class Node:
|
|
56
|
+
@property
|
|
57
|
+
def role(self) -> str: ...
|
|
58
|
+
@property
|
|
59
|
+
def name(self) -> str | None: ...
|
|
60
|
+
@property
|
|
61
|
+
def value(self) -> str | None: ...
|
|
62
|
+
@property
|
|
63
|
+
def description(self) -> str | None: ...
|
|
64
|
+
@property
|
|
65
|
+
def depth(self) -> int: ...
|
|
66
|
+
@property
|
|
67
|
+
def numeric_value(self) -> float | None: ...
|
|
68
|
+
@property
|
|
69
|
+
def min_value(self) -> float | None: ...
|
|
70
|
+
@property
|
|
71
|
+
def max_value(self) -> float | None: ...
|
|
72
|
+
@property
|
|
73
|
+
def stable_id(self) -> str | None: ...
|
|
74
|
+
@property
|
|
75
|
+
def actions(self) -> list[str]: ...
|
|
76
|
+
@property
|
|
77
|
+
def bounds(self) -> Rect | None: ...
|
|
78
|
+
@property
|
|
79
|
+
def bounds_normalized(self) -> NormalizedRect | None: ...
|
|
80
|
+
@property
|
|
81
|
+
def enabled(self) -> bool: ...
|
|
82
|
+
@property
|
|
83
|
+
def visible(self) -> bool: ...
|
|
84
|
+
@property
|
|
85
|
+
def focused(self) -> bool: ...
|
|
86
|
+
@property
|
|
87
|
+
def checked(self) -> str | None: ...
|
|
88
|
+
@property
|
|
89
|
+
def selected(self) -> bool: ...
|
|
90
|
+
@property
|
|
91
|
+
def expanded(self) -> bool | None: ...
|
|
92
|
+
@property
|
|
93
|
+
def editable(self) -> bool: ...
|
|
94
|
+
@property
|
|
95
|
+
def focusable(self) -> bool: ...
|
|
96
|
+
@property
|
|
97
|
+
def modal(self) -> bool: ...
|
|
98
|
+
@property
|
|
99
|
+
def required(self) -> bool: ...
|
|
100
|
+
@property
|
|
101
|
+
def busy(self) -> bool: ...
|
|
102
|
+
def __repr__(self) -> str: ...
|
|
103
|
+
def __str__(self) -> str: ...
|
|
104
|
+
def __len__(self) -> int: ...
|
|
105
|
+
|
|
106
|
+
# ── Target type for action methods ───────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
_Target = Node | str
|
|
109
|
+
|
|
110
|
+
# ── Tree ─────────────────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
class Tree:
|
|
113
|
+
@property
|
|
114
|
+
def app_name(self) -> str: ...
|
|
115
|
+
@property
|
|
116
|
+
def pid(self) -> int | None: ...
|
|
117
|
+
@property
|
|
118
|
+
def screen_size(self) -> tuple[int, int]: ...
|
|
119
|
+
@property
|
|
120
|
+
def root(self) -> Node: ...
|
|
121
|
+
def children(self, node: Node) -> list[Node]: ...
|
|
122
|
+
def parent(self, node: Node) -> Node | None: ...
|
|
123
|
+
def query(self, selector: str) -> list[Node]: ...
|
|
124
|
+
def find_by_role(self, role: str) -> list[Node]: ...
|
|
125
|
+
def find_by_name(self, pattern: str) -> list[Node]: ...
|
|
126
|
+
def perform(
|
|
127
|
+
self,
|
|
128
|
+
target: _Target,
|
|
129
|
+
action: str,
|
|
130
|
+
*,
|
|
131
|
+
value: str | None = None,
|
|
132
|
+
numeric_value: float | None = None,
|
|
133
|
+
direction: str | None = None,
|
|
134
|
+
amount: float | None = None,
|
|
135
|
+
start: int | None = None,
|
|
136
|
+
end: int | None = None,
|
|
137
|
+
) -> None: ...
|
|
138
|
+
def press(self, target: _Target) -> None: ...
|
|
139
|
+
def focus(self, target: _Target) -> None: ...
|
|
140
|
+
def blur(self, target: _Target) -> None: ...
|
|
141
|
+
def toggle(self, target: _Target) -> None: ...
|
|
142
|
+
def expand(self, target: _Target) -> None: ...
|
|
143
|
+
def collapse(self, target: _Target) -> None: ...
|
|
144
|
+
def select(self, target: _Target) -> None: ...
|
|
145
|
+
def increment(self, target: _Target) -> None: ...
|
|
146
|
+
def decrement(self, target: _Target) -> None: ...
|
|
147
|
+
def show_menu(self, target: _Target) -> None: ...
|
|
148
|
+
def scroll_into_view(self, target: _Target) -> None: ...
|
|
149
|
+
def set_value(self, target: _Target, value: str) -> None: ...
|
|
150
|
+
def set_numeric_value(self, target: _Target, value: float) -> None: ...
|
|
151
|
+
def type_text(self, target: _Target, text: str) -> None: ...
|
|
152
|
+
def scroll(self, target: _Target, direction: str, amount: float = 1.0) -> None: ...
|
|
153
|
+
def select_text(self, target: _Target, start: int, end: int) -> None: ...
|
|
154
|
+
def locator(
|
|
155
|
+
self,
|
|
156
|
+
selector: str,
|
|
157
|
+
*,
|
|
158
|
+
max_depth: int | None = None,
|
|
159
|
+
max_elements: int | None = None,
|
|
160
|
+
visible_only: bool = False,
|
|
161
|
+
roles: list[str] | None = None,
|
|
162
|
+
include_raw: bool = False,
|
|
163
|
+
) -> Locator: ...
|
|
164
|
+
def dump(self) -> str: ...
|
|
165
|
+
def __len__(self) -> int: ...
|
|
166
|
+
def __iter__(self) -> Iterator[Node]: ...
|
|
167
|
+
def __repr__(self) -> str: ...
|
|
168
|
+
def __str__(self) -> str: ...
|
|
169
|
+
|
|
170
|
+
# ── Provider ─────────────────────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
class Provider:
|
|
173
|
+
def __init__(self) -> None: ...
|
|
174
|
+
def app(
|
|
175
|
+
self,
|
|
176
|
+
name: str | None = None,
|
|
177
|
+
*,
|
|
178
|
+
pid: int | None = None,
|
|
179
|
+
max_depth: int | None = None,
|
|
180
|
+
max_elements: int | None = None,
|
|
181
|
+
visible_only: bool = False,
|
|
182
|
+
roles: list[str] | None = None,
|
|
183
|
+
include_raw: bool = False,
|
|
184
|
+
) -> Tree: ...
|
|
185
|
+
def all_apps(
|
|
186
|
+
self,
|
|
187
|
+
*,
|
|
188
|
+
max_depth: int | None = None,
|
|
189
|
+
max_elements: int | None = None,
|
|
190
|
+
visible_only: bool = False,
|
|
191
|
+
roles: list[str] | None = None,
|
|
192
|
+
include_raw: bool = False,
|
|
193
|
+
) -> Tree: ...
|
|
194
|
+
def list_apps(self) -> list[AppInfo]: ...
|
|
195
|
+
def check_permissions(self) -> str: ...
|
|
196
|
+
def locator(
|
|
197
|
+
self,
|
|
198
|
+
name: str | None = None,
|
|
199
|
+
*,
|
|
200
|
+
pid: int | None = None,
|
|
201
|
+
selector: str,
|
|
202
|
+
max_depth: int | None = None,
|
|
203
|
+
max_elements: int | None = None,
|
|
204
|
+
visible_only: bool = False,
|
|
205
|
+
roles: list[str] | None = None,
|
|
206
|
+
include_raw: bool = False,
|
|
207
|
+
) -> Locator: ...
|
|
208
|
+
def __enter__(self) -> Provider: ...
|
|
209
|
+
def __exit__(
|
|
210
|
+
self,
|
|
211
|
+
exc_type: type[BaseException] | None = None,
|
|
212
|
+
exc_val: BaseException | None = None,
|
|
213
|
+
exc_tb: TracebackType | None = None,
|
|
214
|
+
) -> bool: ...
|
|
215
|
+
def __repr__(self) -> str: ...
|
|
216
|
+
|
|
217
|
+
# ── Locator ──────────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
class Locator:
|
|
220
|
+
@property
|
|
221
|
+
def selector(self) -> str: ...
|
|
222
|
+
def nth(self, n: int) -> Locator: ...
|
|
223
|
+
def first(self) -> Locator: ...
|
|
224
|
+
def child(self, selector: str) -> Locator: ...
|
|
225
|
+
def descendant(self, selector: str) -> Locator: ...
|
|
226
|
+
def role(self) -> str: ...
|
|
227
|
+
def name(self) -> str | None: ...
|
|
228
|
+
def value(self) -> str | None: ...
|
|
229
|
+
def description(self) -> str | None: ...
|
|
230
|
+
def is_visible(self) -> bool: ...
|
|
231
|
+
def is_enabled(self) -> bool: ...
|
|
232
|
+
def is_focused(self) -> bool: ...
|
|
233
|
+
def exists(self) -> bool: ...
|
|
234
|
+
def count(self) -> int: ...
|
|
235
|
+
def get(self) -> Node: ...
|
|
236
|
+
def press(self) -> None: ...
|
|
237
|
+
def focus(self) -> None: ...
|
|
238
|
+
def blur(self) -> None: ...
|
|
239
|
+
def toggle(self) -> None: ...
|
|
240
|
+
def expand(self) -> None: ...
|
|
241
|
+
def collapse(self) -> None: ...
|
|
242
|
+
def select_item(self) -> None: ...
|
|
243
|
+
def show_menu(self) -> None: ...
|
|
244
|
+
def scroll_into_view(self) -> None: ...
|
|
245
|
+
def increment(self) -> None: ...
|
|
246
|
+
def decrement(self) -> None: ...
|
|
247
|
+
def set_value(self, value: str) -> None: ...
|
|
248
|
+
def set_numeric_value(self, value: float) -> None: ...
|
|
249
|
+
def type_text(self, text: str) -> None: ...
|
|
250
|
+
def select_text(self, start: int, end: int) -> None: ...
|
|
251
|
+
def scroll(self, direction: str, amount: float = 1.0) -> None: ...
|
|
252
|
+
def wait_visible(self, timeout: float = 5.0) -> None: ...
|
|
253
|
+
def wait_attached(self, timeout: float = 5.0) -> None: ...
|
|
254
|
+
def wait_detached(self, timeout: float = 5.0) -> None: ...
|
|
255
|
+
def wait_enabled(self, timeout: float = 5.0) -> None: ...
|
|
256
|
+
def wait_hidden(self, timeout: float = 5.0) -> None: ...
|
|
257
|
+
def __repr__(self) -> str: ...
|
|
258
|
+
|
|
259
|
+
# ── Module-level functions ───────────────────────────────────────────────────
|
|
260
|
+
|
|
261
|
+
def connect() -> Provider: ...
|
|
262
|
+
def app(
|
|
263
|
+
name: str | None = None,
|
|
264
|
+
*,
|
|
265
|
+
pid: int | None = None,
|
|
266
|
+
max_depth: int | None = None,
|
|
267
|
+
max_elements: int | None = None,
|
|
268
|
+
visible_only: bool = False,
|
|
269
|
+
roles: list[str] | None = None,
|
|
270
|
+
include_raw: bool = False,
|
|
271
|
+
) -> Tree: ...
|
|
272
|
+
def list_apps() -> list[AppInfo]: ...
|
|
273
|
+
def check_permissions() -> str: ...
|
|
274
|
+
|
|
275
|
+
# ── Test helpers ─────────────────────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
def _make_test_tree() -> Tree: ...
|
|
278
|
+
def _make_test_provider() -> Provider: ...
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "xa11y"
|
|
3
|
+
version.workspace = true
|
|
4
|
+
edition.workspace = true
|
|
5
|
+
license.workspace = true
|
|
6
|
+
repository.workspace = true
|
|
7
|
+
description = "Cross-platform accessibility client library — unified API for reading and interacting with accessibility trees"
|
|
8
|
+
|
|
9
|
+
[dependencies]
|
|
10
|
+
xa11y-core = { workspace = true }
|
|
11
|
+
|
|
12
|
+
[target.'cfg(target_os = "macos")'.dependencies]
|
|
13
|
+
xa11y-macos = { workspace = true }
|
|
14
|
+
|
|
15
|
+
[target.'cfg(target_os = "windows")'.dependencies]
|
|
16
|
+
xa11y-windows = { workspace = true }
|
|
17
|
+
|
|
18
|
+
[target.'cfg(target_os = "linux")'.dependencies]
|
|
19
|
+
xa11y-linux = { workspace = true }
|
|
20
|
+
|
|
21
|
+
[dev-dependencies]
|
|
22
|
+
serde_json = { workspace = true }
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
//! xa11y — Cross-Platform Accessibility Client Library
|
|
2
|
+
//!
|
|
3
|
+
//! Provides a unified API for reading and interacting with accessibility trees
|
|
4
|
+
//! across desktop platforms (macOS, Windows, Linux).
|
|
5
|
+
//!
|
|
6
|
+
//! # Quick Start
|
|
7
|
+
//!
|
|
8
|
+
//! ```no_run
|
|
9
|
+
//! use xa11y::*;
|
|
10
|
+
//!
|
|
11
|
+
//! let provider = create_provider().expect("Failed to create provider");
|
|
12
|
+
//! let status = provider.check_permissions().expect("Permission check failed");
|
|
13
|
+
//!
|
|
14
|
+
//! match status {
|
|
15
|
+
//! PermissionStatus::Granted => {
|
|
16
|
+
//! let tree = provider.get_app_tree(
|
|
17
|
+
//! &AppTarget::ByName("Safari".to_string()),
|
|
18
|
+
//! &QueryOptions::default(),
|
|
19
|
+
//! ).expect("Failed to get tree");
|
|
20
|
+
//!
|
|
21
|
+
//! let buttons = tree.query("button").expect("Query failed");
|
|
22
|
+
//! println!("Found {} buttons", buttons.len());
|
|
23
|
+
//! }
|
|
24
|
+
//! PermissionStatus::Denied { instructions } => {
|
|
25
|
+
//! eprintln!("Accessibility not enabled: {}", instructions);
|
|
26
|
+
//! }
|
|
27
|
+
//! }
|
|
28
|
+
//! ```
|
|
29
|
+
|
|
30
|
+
// Re-export all core types
|
|
31
|
+
pub use xa11y_core::*;
|
|
32
|
+
|
|
33
|
+
// Platform-specific provider creation
|
|
34
|
+
|
|
35
|
+
/// Create a platform-appropriate accessibility provider.
|
|
36
|
+
///
|
|
37
|
+
/// Returns a boxed `Provider` trait object for the current platform.
|
|
38
|
+
/// On unsupported platforms, returns a `Platform` error.
|
|
39
|
+
pub fn create_provider() -> Result<Box<dyn Provider>> {
|
|
40
|
+
#[cfg(target_os = "macos")]
|
|
41
|
+
{
|
|
42
|
+
Ok(Box::new(xa11y_macos::MacOSProvider::new()?))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#[cfg(target_os = "windows")]
|
|
46
|
+
{
|
|
47
|
+
Ok(Box::new(xa11y_windows::WindowsProvider::new()?))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[cfg(target_os = "linux")]
|
|
51
|
+
{
|
|
52
|
+
Ok(Box::new(xa11y_linux::LinuxProvider::new()?))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
|
|
56
|
+
{
|
|
57
|
+
Err(Error::Platform {
|
|
58
|
+
code: -1,
|
|
59
|
+
message: format!("Unsupported platform: {}", std::env::consts::OS),
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Create a platform-appropriate event provider (supports subscribe/wait).
|
|
65
|
+
///
|
|
66
|
+
/// Returns a boxed `EventProvider` trait object for the current platform.
|
|
67
|
+
/// EventProvider extends Provider with event subscription capabilities.
|
|
68
|
+
pub fn create_event_provider() -> Result<Box<dyn EventProvider>> {
|
|
69
|
+
#[cfg(target_os = "macos")]
|
|
70
|
+
{
|
|
71
|
+
Ok(Box::new(xa11y_macos::MacOSProvider::new()?))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#[cfg(target_os = "windows")]
|
|
75
|
+
{
|
|
76
|
+
Ok(Box::new(xa11y_windows::WindowsProvider::new()?))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[cfg(target_os = "linux")]
|
|
80
|
+
{
|
|
81
|
+
Ok(Box::new(xa11y_linux::LinuxProvider::new()?))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
|
|
85
|
+
{
|
|
86
|
+
Err(Error::Platform {
|
|
87
|
+
code: -1,
|
|
88
|
+
message: format!("Unsupported platform: {}", std::env::consts::OS),
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
}
|