Skip to content

Commit f6c202a

Browse files
authored
Merge pull request #378 from j0j1j2/feat/impl-accessibility-domain
Add supports for Accessibility domain
2 parents 74f8e98 + c83c478 commit f6c202a

7 files changed

Lines changed: 947 additions & 0 deletions

File tree

pydoll/commands/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# global imports
2+
from pydoll.commands.accessibility_commands import AccessibilityCommands
23
from pydoll.commands.browser_commands import BrowserCommands
34
from pydoll.commands.dom_commands import DomCommands
45
from pydoll.commands.emulation_commands import EmulationCommands
@@ -11,6 +12,7 @@
1112
from pydoll.commands.target_commands import TargetCommands
1213

1314
__all__ = [
15+
'AccessibilityCommands',
1416
'DomCommands',
1517
'EmulationCommands',
1618
'FetchCommands',
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING, Optional
4+
5+
from pydoll.protocol.accessibility.methods import (
6+
AccessibilityMethod,
7+
GetAXNodeAndAncestorsParams,
8+
GetChildAXNodesParams,
9+
GetFullAXTreeParams,
10+
GetPartialAXTreeParams,
11+
GetRootAXNodeParams,
12+
QueryAXTreeParams,
13+
)
14+
from pydoll.protocol.base import Command
15+
16+
if TYPE_CHECKING:
17+
from pydoll.protocol.accessibility.methods import (
18+
DisableCommand,
19+
EnableCommand,
20+
GetAXNodeAndAncestorsCommand,
21+
GetChildAXNodesCommand,
22+
GetFullAXTreeCommand,
23+
GetPartialAXTreeCommand,
24+
GetRootAXNodeCommand,
25+
QueryAXTreeCommand,
26+
)
27+
from pydoll.protocol.accessibility.types import AXNodeId
28+
29+
30+
class AccessibilityCommands:
31+
"""
32+
Implementation of Chrome DevTools Protocol for the Accessibility domain.
33+
34+
This class provides commands for interacting with the accessibility tree,
35+
enabling inspection and querying of accessible nodes on a page.
36+
37+
See https://chromedevtools.github.io/devtools-protocol/tot/Accessibility/
38+
"""
39+
40+
@staticmethod
41+
def disable() -> DisableCommand:
42+
"""
43+
Disables the accessibility domain.
44+
45+
Returns:
46+
DisableCommand: CDP command to disable the accessibility domain.
47+
"""
48+
return Command(method=AccessibilityMethod.DISABLE)
49+
50+
@staticmethod
51+
def enable() -> EnableCommand:
52+
"""
53+
Enables the accessibility domain which causes AXNodeIds to remain
54+
consistent between method calls.
55+
56+
Returns:
57+
EnableCommand: CDP command to enable the accessibility domain.
58+
"""
59+
return Command(method=AccessibilityMethod.ENABLE)
60+
61+
@staticmethod
62+
def get_partial_ax_tree(
63+
node_id: Optional[int] = None,
64+
backend_node_id: Optional[int] = None,
65+
object_id: Optional[str] = None,
66+
fetch_relatives: Optional[bool] = None,
67+
) -> GetPartialAXTreeCommand:
68+
"""
69+
Fetches the accessibility node and partial accessibility tree for this
70+
DOM node, if it exists.
71+
72+
Args:
73+
node_id: Identifier of the node to get the partial accessibility
74+
tree for.
75+
backend_node_id: Identifier of the backend node to get the partial
76+
accessibility tree for.
77+
object_id: JavaScript object id of the node wrapper to get the
78+
partial accessibility tree for.
79+
fetch_relatives: Whether to fetch this node's ancestors, siblings
80+
and children. Defaults to True.
81+
82+
Returns:
83+
GetPartialAXTreeCommand: CDP command to get the partial AX tree.
84+
"""
85+
params = GetPartialAXTreeParams()
86+
if node_id is not None:
87+
params['nodeId'] = node_id
88+
if backend_node_id is not None:
89+
params['backendNodeId'] = backend_node_id
90+
if object_id is not None:
91+
params['objectId'] = object_id
92+
if fetch_relatives is not None:
93+
params['fetchRelatives'] = fetch_relatives
94+
return Command(method=AccessibilityMethod.GET_PARTIAL_AX_TREE, params=params)
95+
96+
@staticmethod
97+
def get_full_ax_tree(
98+
depth: Optional[int] = None,
99+
frame_id: Optional[str] = None,
100+
) -> GetFullAXTreeCommand:
101+
"""
102+
Fetches the entire accessibility tree for the root Document.
103+
104+
Args:
105+
depth: The maximum depth at which descendants of the root node
106+
should be retrieved. If omitted, the full tree is returned.
107+
frame_id: The frame for whose document the AX tree should be
108+
retrieved. If omitted, the root frame is used.
109+
110+
Returns:
111+
GetFullAXTreeCommand: CDP command to get the full AX tree.
112+
"""
113+
params = GetFullAXTreeParams()
114+
if depth is not None:
115+
params['depth'] = depth
116+
if frame_id is not None:
117+
params['frameId'] = frame_id
118+
return Command(method=AccessibilityMethod.GET_FULL_AX_TREE, params=params)
119+
120+
@staticmethod
121+
def get_root_ax_node(
122+
frame_id: Optional[str] = None,
123+
) -> GetRootAXNodeCommand:
124+
"""
125+
Fetches the root node of the accessibility tree for a Document.
126+
127+
Args:
128+
frame_id: The frame in whose document the node resides. If omitted,
129+
the root frame is used.
130+
131+
Returns:
132+
GetRootAXNodeCommand: CDP command to get the root AX node.
133+
"""
134+
params = GetRootAXNodeParams()
135+
if frame_id is not None:
136+
params['frameId'] = frame_id
137+
return Command(method=AccessibilityMethod.GET_ROOT_AX_NODE, params=params)
138+
139+
@staticmethod
140+
def get_ax_node_and_ancestors(
141+
node_id: Optional[int] = None,
142+
backend_node_id: Optional[int] = None,
143+
object_id: Optional[str] = None,
144+
) -> GetAXNodeAndAncestorsCommand:
145+
"""
146+
Fetches a node and all ancestors up to and including the root.
147+
148+
Args:
149+
node_id: Identifier of the node to get ancestors for.
150+
backend_node_id: Identifier of the backend node to get ancestors for.
151+
object_id: JavaScript object id of the node wrapper to get
152+
ancestors for.
153+
154+
Returns:
155+
GetAXNodeAndAncestorsCommand: CDP command to get a node and its ancestors.
156+
"""
157+
params = GetAXNodeAndAncestorsParams()
158+
if node_id is not None:
159+
params['nodeId'] = node_id
160+
if backend_node_id is not None:
161+
params['backendNodeId'] = backend_node_id
162+
if object_id is not None:
163+
params['objectId'] = object_id
164+
return Command(
165+
method=AccessibilityMethod.GET_AX_NODE_AND_ANCESTORS, params=params
166+
)
167+
168+
@staticmethod
169+
def get_child_ax_nodes(
170+
id: AXNodeId,
171+
frame_id: Optional[str] = None,
172+
) -> GetChildAXNodesCommand:
173+
"""
174+
Fetches a particular accessibility node by AXNodeId.
175+
176+
Args:
177+
id: The AXNodeId of the node whose children should be retrieved.
178+
frame_id: The frame in whose document the node resides. If omitted,
179+
the root frame is used.
180+
181+
Returns:
182+
GetChildAXNodesCommand: CDP command to get child AX nodes.
183+
"""
184+
params = GetChildAXNodesParams(id=id)
185+
if frame_id is not None:
186+
params['frameId'] = frame_id
187+
return Command(method=AccessibilityMethod.GET_CHILD_AX_NODES, params=params)
188+
189+
@staticmethod
190+
def query_ax_tree(
191+
node_id: Optional[int] = None,
192+
backend_node_id: Optional[int] = None,
193+
object_id: Optional[str] = None,
194+
accessible_name: Optional[str] = None,
195+
role: Optional[str] = None,
196+
) -> QueryAXTreeCommand:
197+
"""
198+
Queries the accessibility tree for a DOM subtree for nodes with a
199+
given name and/or role.
200+
201+
Args:
202+
node_id: Identifier of the node for the root of the subtree to
203+
search in.
204+
backend_node_id: Identifier of the backend node for the root of
205+
the subtree to search in.
206+
object_id: JavaScript object id of the node wrapper for the root
207+
of the subtree to search in.
208+
accessible_name: Find nodes with this computed name.
209+
role: Find nodes with this computed role.
210+
211+
Returns:
212+
QueryAXTreeCommand: CDP command to query the AX tree.
213+
"""
214+
params = QueryAXTreeParams()
215+
if node_id is not None:
216+
params['nodeId'] = node_id
217+
if backend_node_id is not None:
218+
params['backendNodeId'] = backend_node_id
219+
if object_id is not None:
220+
params['objectId'] = object_id
221+
if accessible_name is not None:
222+
params['accessibleName'] = accessible_name
223+
if role is not None:
224+
params['role'] = role
225+
return Command(method=AccessibilityMethod.QUERY_AX_TREE, params=params)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Accessibility domain implementation."""
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from enum import Enum
2+
3+
from typing_extensions import TypedDict
4+
5+
from pydoll.protocol.accessibility.types import AXNode
6+
from pydoll.protocol.base import CDPEvent
7+
8+
9+
class AccessibilityEvent(str, Enum):
10+
"""
11+
Events from the Accessibility domain of the Chrome DevTools Protocol.
12+
13+
See https://chromedevtools.github.io/devtools-protocol/tot/Accessibility/
14+
"""
15+
16+
LOAD_COMPLETE = 'Accessibility.loadComplete'
17+
"""
18+
Mirrors the load complete event sent by the browser to assistive technology
19+
when the web page has finished loading.
20+
21+
Args:
22+
root (AXNode): New document root node.
23+
"""
24+
25+
NODES_UPDATED = 'Accessibility.nodesUpdated'
26+
"""
27+
Fired when a node is updated in the accessibility tree.
28+
29+
Args:
30+
nodes (list[AXNode]): Updated nodes.
31+
"""
32+
33+
34+
class LoadCompleteEventParams(TypedDict):
35+
"""Parameters for the loadComplete event."""
36+
37+
root: AXNode
38+
39+
40+
class NodesUpdatedEventParams(TypedDict):
41+
"""Parameters for the nodesUpdated event."""
42+
43+
nodes: list[AXNode]
44+
45+
46+
LoadCompleteEvent = CDPEvent[LoadCompleteEventParams]
47+
NodesUpdatedEvent = CDPEvent[NodesUpdatedEventParams]

0 commit comments

Comments
 (0)