pyautoassist 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.
Files changed (45) hide show
  1. pyautoassist-0.1.0/.gitignore +39 -0
  2. pyautoassist-0.1.0/PKG-INFO +245 -0
  3. pyautoassist-0.1.0/README.md +209 -0
  4. pyautoassist-0.1.0/examples/demo.py +545 -0
  5. pyautoassist-0.1.0/pyautoassist/__init__.py +464 -0
  6. pyautoassist-0.1.0/pyautoassist/_impl/__init__.py +0 -0
  7. pyautoassist-0.1.0/pyautoassist/_impl/_defaults.py +6 -0
  8. pyautoassist-0.1.0/pyautoassist/_impl/automagic.py +639 -0
  9. pyautoassist-0.1.0/pyautoassist/_impl/backend.py +208 -0
  10. pyautoassist-0.1.0/pyautoassist/_impl/element.py +281 -0
  11. pyautoassist-0.1.0/pyautoassist/_impl/fuzzy.py +75 -0
  12. pyautoassist-0.1.0/pyautoassist/_impl/locator.py +435 -0
  13. pyautoassist-0.1.0/pyautoassist/_impl/selector.py +282 -0
  14. pyautoassist-0.1.0/pyautoassist/_impl/types.py +113 -0
  15. pyautoassist-0.1.0/pyautoassist/_impl/visualize.py +394 -0
  16. pyautoassist-0.1.0/pyautoassist/_impl/wait.py +97 -0
  17. pyautoassist-0.1.0/pyautoassist/_impl/window.py +149 -0
  18. pyautoassist-0.1.0/pyautoassist/backends/__init__.py +0 -0
  19. pyautoassist-0.1.0/pyautoassist/backends/linux_backend.py +258 -0
  20. pyautoassist-0.1.0/pyautoassist/backends/macos_backend.py +329 -0
  21. pyautoassist-0.1.0/pyautoassist/backends/windows_backend.py +983 -0
  22. pyautoassist-0.1.0/pyautoassist/recorder/__init__.py +0 -0
  23. pyautoassist-0.1.0/pyautoassist/recorder/cli.py +162 -0
  24. pyautoassist-0.1.0/pyautoassist/recorder/event_recorder.py +459 -0
  25. pyautoassist-0.1.0/pyautoassist/recorder/region_selector.py +162 -0
  26. pyautoassist-0.1.0/pyautoassist/recorder/screen_capture.py +252 -0
  27. pyautoassist-0.1.0/pyautoassist/recorder/video_writer.py +123 -0
  28. pyautoassist-0.1.0/pyproject.toml +46 -0
  29. pyautoassist-0.1.0/tests/__init__.py +1 -0
  30. pyautoassist-0.1.0/tests/conftest.py +6 -0
  31. pyautoassist-0.1.0/tests/mock_backend.py +229 -0
  32. pyautoassist-0.1.0/tests/test_automagic.py +70 -0
  33. pyautoassist-0.1.0/tests/test_element.py +142 -0
  34. pyautoassist-0.1.0/tests/test_event_recorder.py +369 -0
  35. pyautoassist-0.1.0/tests/test_fuzzy.py +114 -0
  36. pyautoassist-0.1.0/tests/test_imports.py +144 -0
  37. pyautoassist-0.1.0/tests/test_locator.py +189 -0
  38. pyautoassist-0.1.0/tests/test_region_selector.py +72 -0
  39. pyautoassist-0.1.0/tests/test_screen_capture.py +198 -0
  40. pyautoassist-0.1.0/tests/test_selector.py +123 -0
  41. pyautoassist-0.1.0/tests/test_text_locator.py +405 -0
  42. pyautoassist-0.1.0/tests/test_video_writer.py +140 -0
  43. pyautoassist-0.1.0/tests/test_visualize.py +218 -0
  44. pyautoassist-0.1.0/tests/test_wait.py +77 -0
  45. pyautoassist-0.1.0/tests/test_window.py +107 -0
@@ -0,0 +1,39 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+ .eggs/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+
18
+ # IDE / Editor
19
+ .vscode/
20
+ .idea/
21
+ *.swp
22
+ *.swo
23
+ *~
24
+
25
+ # OS files
26
+ .DS_Store
27
+ Thumbs.db
28
+ Desktop.ini
29
+
30
+ # Testing
31
+ .pytest_cache/
32
+ .coverage
33
+ htmlcov/
34
+
35
+ # Environment
36
+ .env
37
+
38
+ # Misc
39
+ *.log
@@ -0,0 +1,245 @@
1
+ Metadata-Version: 2.5
2
+ Name: pyautoassist
3
+ Version: 0.1.0
4
+ Summary: Playwright-style desktop automation with native OS accessibility backends
5
+ Author: pyautoassist contributors
6
+ License-Expression: MIT
7
+ Keywords: accessibility,automation,desktop,playwright,pyautogui,pywinauto,uia
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Classifier: Topic :: Software Development :: Testing
18
+ Requires-Python: >=3.10
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
21
+ Requires-Dist: pytest>=8.0; extra == 'dev'
22
+ Provides-Extra: linux
23
+ Requires-Dist: pygobject>=3.48; extra == 'linux'
24
+ Provides-Extra: macos
25
+ Requires-Dist: pyobjc>=10.0; extra == 'macos'
26
+ Provides-Extra: recorder
27
+ Requires-Dist: mss>=9.0; extra == 'recorder'
28
+ Requires-Dist: opencv-python>=4.8; extra == 'recorder'
29
+ Requires-Dist: pillow>=10.0; extra == 'recorder'
30
+ Provides-Extra: visualize
31
+ Requires-Dist: matplotlib>=3.7; extra == 'visualize'
32
+ Requires-Dist: networkx>=3.0; extra == 'visualize'
33
+ Provides-Extra: windows
34
+ Requires-Dist: comtypes>=1.4; extra == 'windows'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # pyautoassist
38
+
39
+ **Playwright-style desktop automation with native OS accessibility backends.**
40
+
41
+ pyautoassist brings the developer experience of Playwright to desktop automation.
42
+ No more `time.sleep()`. No more fragile coordinate-based clicking.
43
+ Just explicit locators, native auto-waiting, and real OS accessibility APIs.
44
+
45
+ ```python
46
+ import pyautoassist
47
+
48
+ app = pyautoassist.using_backend()
49
+
50
+ # XPath-style locators targeting OS accessibility properties
51
+ app.locator("//Button[@Name='Submit']").click()
52
+ app.locator("//Edit[@AutomationId='email-input']").fill("Hello World")
53
+
54
+ # CSS-style shorthand
55
+ app.locator("button.submit-btn").click()
56
+ app.locator("edit-text#main-input").fill("Hello")
57
+
58
+ # Auto-waiting: no time.sleep() needed
59
+ app.locator("//Button[@Name='Save']").click() # waits until clickable
60
+ ```
61
+
62
+ ## Why pyautoassist?
63
+
64
+ | Feature | pyautogui | pywinauto | pyautoassist |
65
+ |---------|-----------|-----------|-----------|
66
+ | Locator style | Coordinates/fragile selectors | Custom syntax | CSS/XPath-style |
67
+ | Auto-waiting | None | Basic | Full (Playwright-style) |
68
+ | OS backend | Screen capture | Win32 COM | Native UIA/AX/AT-SPI |
69
+ | Codegen recorder | No | No | Yes (`pyautoassist record`) |
70
+ | Cross-platform | Yes | Windows only | Windows/macOS/Linux |
71
+
72
+ ## Installation
73
+
74
+ ```bash
75
+ # Core (auto-detects platform)
76
+ pip install pyautoassist
77
+
78
+ # Platform-specific extras
79
+ pip install pyautoassist[windows] # Windows UIA
80
+ pip install pyautoassist[macos] # macOS Accessibility
81
+ pip install pyautoassist[linux] # Linux AT-SPI2
82
+ ```
83
+
84
+ ## Quick Start
85
+
86
+ ```python
87
+ import pyautoassist
88
+
89
+ # Create an automation session
90
+ app = pyautoassist.using_backend()
91
+
92
+ # Find a window
93
+ notepad = app.open("Notepad")
94
+
95
+ # Use locators (auto-waits for element)
96
+ app.locator("//Edit").fill("Hello, pyautoassist!")
97
+
98
+ # Chain locators within elements
99
+ notepad.locator("//MenuItem[@Name='File']").click()
100
+ notepad.locator("//MenuItem[@Name='Save']").click()
101
+ ```
102
+
103
+ ## Selectors
104
+
105
+ ### XPath Style
106
+
107
+ Target elements by their OS accessibility properties:
108
+
109
+ ```python
110
+ # By control type and name
111
+ app.locator("//Button[@Name='Submit']")
112
+ app.locator("//Edit[@Name='Username']")
113
+
114
+ # By AutomationId (most reliable)
115
+ app.locator("//Button[@AutomationId='btn-submit']")
116
+ app.locator("//Edit[@AutomationId='email-input']")
117
+
118
+ # By ClassName
119
+ app.locator("//Pane[@ClassName='Notepad']")
120
+
121
+ # Chained: nested elements
122
+ app.locator("//Pane[@ClassName='Notepad']//Button[@Name='File']")
123
+ ```
124
+
125
+ ### CSS Style
126
+
127
+ Shorthand selectors for quick access:
128
+
129
+ ```python
130
+ # Type + ID (AutomationId)
131
+ app.locator("button#submit-btn")
132
+
133
+ # Type + class (ClassName)
134
+ app.locator("button.submit")
135
+
136
+ # Type + attribute
137
+ app.locator('button[name="OK"]')
138
+
139
+ # Child combinator
140
+ app.locator("pane > button")
141
+ ```
142
+
143
+ ### Supported Control Types
144
+
145
+ `button`, `edit`/`edit-text`/`textbox`, `pane`, `window`/`dialog`,
146
+ `menu`, `menuitem`, `checkbox`, `radio`/`radiobutton`,
147
+ `combobox`/`dropdown`, `list`, `listitem`, `tree`, `treeitem`,
148
+ `toolbar`, `tab`, `tabitem`, `image`, `hyperlink`, `slider`,
149
+ `progressbar`, `scrollbar`, `group`, `tooltip`, `statusbar`,
150
+ `header`, `separator`, `document`, `dataitem`, `custom`
151
+
152
+ ## Auto-Waiting
153
+
154
+ Every action on a Locator automatically waits for the element to be ready:
155
+
156
+ ```python
157
+ # Waits up to 30s for the button to exist, be visible, and be enabled
158
+ app.locator("//Button[@Name='Submit']").click()
159
+
160
+ # Custom timeout
161
+ app.locator("//Button[@Name='Submit']").with_timeout(5000).click()
162
+
163
+ # Wait for specific states
164
+ app.locator("//Button[@Name='Loading']").visible().click()
165
+ app.locator("//Edit[@Name='Email']").enabled().click()
166
+ ```
167
+
168
+ ## Element Actions
169
+
170
+ ```python
171
+ el = app.locator("//Button[@Name='Submit']")
172
+
173
+ el.click() # Left click
174
+ el.double_click() # Double click
175
+ el.right_click() # Context menu
176
+ el.fill("text") # Set value (input fields)
177
+ el.type_text("text") # Type character by character
178
+ el.clear() # Clear input
179
+ el.select_option(label="Option 1") # Dropdown selection
180
+ el.focus() # Move keyboard focus
181
+ el.hover() # Move mouse to element
182
+ el.press_key("Enter") # Send key press
183
+ ```
184
+
185
+ ## Window Management
186
+
187
+ ```python
188
+ # List all windows
189
+ for w in app.get_windows():
190
+ print(f"{w.title} (PID: {w.pid})")
191
+
192
+ # Find by title
193
+ notepad = app.find_window(title="Notepad")
194
+ notepad.focus()
195
+ notepad.move(100, 100)
196
+ notepad.resize(800, 600)
197
+ notepad.close()
198
+
199
+ # Find by PID
200
+ window = app.find_window(pid=12345)
201
+ ```
202
+
203
+ ## Codegen Recorder
204
+
205
+ Generate automation code by clicking around:
206
+
207
+ ```bash
208
+ # Start recording (Windows)
209
+ pyautoassist record
210
+
211
+ # Save to file
212
+ pyautoassist record --output recorded.py
213
+
214
+ # Specify backend
215
+ pyautoassist record --backend macos
216
+ ```
217
+
218
+ The recorder hooks into OS mouse events, inspects the accessibility tree
219
+ at each click location, and prints pyautoassist-style code in real time.
220
+
221
+ ## Architecture
222
+
223
+ ```
224
+ pyautoassist/
225
+ __init__.py # Public API
226
+ _impl/
227
+ pyautoassist.py # Main entry point (pyautoassist class)
228
+ locator.py # Playwright-style Locator with auto-wait
229
+ element.py # Element wrapper with actions
230
+ window.py # Window management
231
+ selector.py # CSS/XPath-style selector engine
232
+ wait.py # Auto-wait polling loop
233
+ types.py # Data types and enums
234
+ backend.py # Abstract backend interface
235
+ backends/
236
+ windows_backend.py # Windows UIA (UIA3 COM API)
237
+ macos_backend.py # macOS AXUIElement (PyObjC)
238
+ linux_backend.py # Linux AT-SPI2 (GObject)
239
+ recorder/
240
+ cli.py # Codegen CLI tool
241
+ ```
242
+
243
+ ## License
244
+
245
+ MIT
@@ -0,0 +1,209 @@
1
+ # pyautoassist
2
+
3
+ **Playwright-style desktop automation with native OS accessibility backends.**
4
+
5
+ pyautoassist brings the developer experience of Playwright to desktop automation.
6
+ No more `time.sleep()`. No more fragile coordinate-based clicking.
7
+ Just explicit locators, native auto-waiting, and real OS accessibility APIs.
8
+
9
+ ```python
10
+ import pyautoassist
11
+
12
+ app = pyautoassist.using_backend()
13
+
14
+ # XPath-style locators targeting OS accessibility properties
15
+ app.locator("//Button[@Name='Submit']").click()
16
+ app.locator("//Edit[@AutomationId='email-input']").fill("Hello World")
17
+
18
+ # CSS-style shorthand
19
+ app.locator("button.submit-btn").click()
20
+ app.locator("edit-text#main-input").fill("Hello")
21
+
22
+ # Auto-waiting: no time.sleep() needed
23
+ app.locator("//Button[@Name='Save']").click() # waits until clickable
24
+ ```
25
+
26
+ ## Why pyautoassist?
27
+
28
+ | Feature | pyautogui | pywinauto | pyautoassist |
29
+ |---------|-----------|-----------|-----------|
30
+ | Locator style | Coordinates/fragile selectors | Custom syntax | CSS/XPath-style |
31
+ | Auto-waiting | None | Basic | Full (Playwright-style) |
32
+ | OS backend | Screen capture | Win32 COM | Native UIA/AX/AT-SPI |
33
+ | Codegen recorder | No | No | Yes (`pyautoassist record`) |
34
+ | Cross-platform | Yes | Windows only | Windows/macOS/Linux |
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ # Core (auto-detects platform)
40
+ pip install pyautoassist
41
+
42
+ # Platform-specific extras
43
+ pip install pyautoassist[windows] # Windows UIA
44
+ pip install pyautoassist[macos] # macOS Accessibility
45
+ pip install pyautoassist[linux] # Linux AT-SPI2
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ```python
51
+ import pyautoassist
52
+
53
+ # Create an automation session
54
+ app = pyautoassist.using_backend()
55
+
56
+ # Find a window
57
+ notepad = app.open("Notepad")
58
+
59
+ # Use locators (auto-waits for element)
60
+ app.locator("//Edit").fill("Hello, pyautoassist!")
61
+
62
+ # Chain locators within elements
63
+ notepad.locator("//MenuItem[@Name='File']").click()
64
+ notepad.locator("//MenuItem[@Name='Save']").click()
65
+ ```
66
+
67
+ ## Selectors
68
+
69
+ ### XPath Style
70
+
71
+ Target elements by their OS accessibility properties:
72
+
73
+ ```python
74
+ # By control type and name
75
+ app.locator("//Button[@Name='Submit']")
76
+ app.locator("//Edit[@Name='Username']")
77
+
78
+ # By AutomationId (most reliable)
79
+ app.locator("//Button[@AutomationId='btn-submit']")
80
+ app.locator("//Edit[@AutomationId='email-input']")
81
+
82
+ # By ClassName
83
+ app.locator("//Pane[@ClassName='Notepad']")
84
+
85
+ # Chained: nested elements
86
+ app.locator("//Pane[@ClassName='Notepad']//Button[@Name='File']")
87
+ ```
88
+
89
+ ### CSS Style
90
+
91
+ Shorthand selectors for quick access:
92
+
93
+ ```python
94
+ # Type + ID (AutomationId)
95
+ app.locator("button#submit-btn")
96
+
97
+ # Type + class (ClassName)
98
+ app.locator("button.submit")
99
+
100
+ # Type + attribute
101
+ app.locator('button[name="OK"]')
102
+
103
+ # Child combinator
104
+ app.locator("pane > button")
105
+ ```
106
+
107
+ ### Supported Control Types
108
+
109
+ `button`, `edit`/`edit-text`/`textbox`, `pane`, `window`/`dialog`,
110
+ `menu`, `menuitem`, `checkbox`, `radio`/`radiobutton`,
111
+ `combobox`/`dropdown`, `list`, `listitem`, `tree`, `treeitem`,
112
+ `toolbar`, `tab`, `tabitem`, `image`, `hyperlink`, `slider`,
113
+ `progressbar`, `scrollbar`, `group`, `tooltip`, `statusbar`,
114
+ `header`, `separator`, `document`, `dataitem`, `custom`
115
+
116
+ ## Auto-Waiting
117
+
118
+ Every action on a Locator automatically waits for the element to be ready:
119
+
120
+ ```python
121
+ # Waits up to 30s for the button to exist, be visible, and be enabled
122
+ app.locator("//Button[@Name='Submit']").click()
123
+
124
+ # Custom timeout
125
+ app.locator("//Button[@Name='Submit']").with_timeout(5000).click()
126
+
127
+ # Wait for specific states
128
+ app.locator("//Button[@Name='Loading']").visible().click()
129
+ app.locator("//Edit[@Name='Email']").enabled().click()
130
+ ```
131
+
132
+ ## Element Actions
133
+
134
+ ```python
135
+ el = app.locator("//Button[@Name='Submit']")
136
+
137
+ el.click() # Left click
138
+ el.double_click() # Double click
139
+ el.right_click() # Context menu
140
+ el.fill("text") # Set value (input fields)
141
+ el.type_text("text") # Type character by character
142
+ el.clear() # Clear input
143
+ el.select_option(label="Option 1") # Dropdown selection
144
+ el.focus() # Move keyboard focus
145
+ el.hover() # Move mouse to element
146
+ el.press_key("Enter") # Send key press
147
+ ```
148
+
149
+ ## Window Management
150
+
151
+ ```python
152
+ # List all windows
153
+ for w in app.get_windows():
154
+ print(f"{w.title} (PID: {w.pid})")
155
+
156
+ # Find by title
157
+ notepad = app.find_window(title="Notepad")
158
+ notepad.focus()
159
+ notepad.move(100, 100)
160
+ notepad.resize(800, 600)
161
+ notepad.close()
162
+
163
+ # Find by PID
164
+ window = app.find_window(pid=12345)
165
+ ```
166
+
167
+ ## Codegen Recorder
168
+
169
+ Generate automation code by clicking around:
170
+
171
+ ```bash
172
+ # Start recording (Windows)
173
+ pyautoassist record
174
+
175
+ # Save to file
176
+ pyautoassist record --output recorded.py
177
+
178
+ # Specify backend
179
+ pyautoassist record --backend macos
180
+ ```
181
+
182
+ The recorder hooks into OS mouse events, inspects the accessibility tree
183
+ at each click location, and prints pyautoassist-style code in real time.
184
+
185
+ ## Architecture
186
+
187
+ ```
188
+ pyautoassist/
189
+ __init__.py # Public API
190
+ _impl/
191
+ pyautoassist.py # Main entry point (pyautoassist class)
192
+ locator.py # Playwright-style Locator with auto-wait
193
+ element.py # Element wrapper with actions
194
+ window.py # Window management
195
+ selector.py # CSS/XPath-style selector engine
196
+ wait.py # Auto-wait polling loop
197
+ types.py # Data types and enums
198
+ backend.py # Abstract backend interface
199
+ backends/
200
+ windows_backend.py # Windows UIA (UIA3 COM API)
201
+ macos_backend.py # macOS AXUIElement (PyObjC)
202
+ linux_backend.py # Linux AT-SPI2 (GObject)
203
+ recorder/
204
+ cli.py # Codegen CLI tool
205
+ ```
206
+
207
+ ## License
208
+
209
+ MIT