PyClickerRPA 0.1.0__tar.gz → 0.3.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 (70) hide show
  1. pyclickerrpa-0.3.0/LICENSE +21 -0
  2. pyclickerrpa-0.3.0/PKG-INFO +138 -0
  3. pyclickerrpa-0.3.0/PyClickerRPA.egg-info/PKG-INFO +138 -0
  4. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/PyClickerRPA.egg-info/SOURCES.txt +27 -1
  5. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/PyClickerRPA.egg-info/entry_points.txt +2 -0
  6. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/PyClickerRPA.egg-info/requires.txt +8 -0
  7. pyclickerrpa-0.3.0/README.md +100 -0
  8. pyclickerrpa-0.3.0/autoclicker/adb.py +163 -0
  9. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/capture.py +26 -10
  10. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/flow_connection.py +8 -1
  11. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/flow_editor.py +194 -67
  12. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/flow_node.py +57 -8
  13. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/main_window.py +177 -33
  14. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/task_widget.py +55 -4
  15. pyclickerrpa-0.3.0/autoclicker/gui/testkit_widget.py +167 -0
  16. pyclickerrpa-0.3.0/autoclicker/matcher.py +262 -0
  17. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/models.py +53 -1
  18. pyclickerrpa-0.3.0/autoclicker/ocr.py +107 -0
  19. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/run.py +11 -2
  20. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/runner.py +233 -29
  21. pyclickerrpa-0.3.0/autoclicker/testkit/__init__.py +25 -0
  22. pyclickerrpa-0.3.0/autoclicker/testkit/__main__.py +51 -0
  23. pyclickerrpa-0.3.0/autoclicker/testkit/assertions.py +256 -0
  24. pyclickerrpa-0.3.0/autoclicker/testkit/case.py +130 -0
  25. pyclickerrpa-0.3.0/autoclicker/testkit/loader.py +82 -0
  26. pyclickerrpa-0.3.0/autoclicker/testkit/pytest_plugin.py +100 -0
  27. pyclickerrpa-0.3.0/autoclicker/testkit/report.py +124 -0
  28. pyclickerrpa-0.3.0/autoclicker/testkit/runner.py +147 -0
  29. pyclickerrpa-0.3.0/autoclicker/testkit/visual.py +87 -0
  30. pyclickerrpa-0.3.0/autoclicker/web/__init__.py +4 -0
  31. pyclickerrpa-0.3.0/autoclicker/web/__main__.py +33 -0
  32. pyclickerrpa-0.3.0/autoclicker/web/run_manager.py +181 -0
  33. pyclickerrpa-0.3.0/autoclicker/web/scheduler.py +73 -0
  34. pyclickerrpa-0.3.0/autoclicker/web/serialize.py +40 -0
  35. pyclickerrpa-0.3.0/autoclicker/web/server.py +178 -0
  36. pyclickerrpa-0.3.0/autoclicker/web/static/app.js +244 -0
  37. pyclickerrpa-0.3.0/autoclicker/web/static/index.html +58 -0
  38. pyclickerrpa-0.3.0/autoclicker/web/static/style.css +61 -0
  39. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/windows.py +24 -0
  40. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/pyproject.toml +17 -3
  41. pyclickerrpa-0.3.0/tests/test_adb.py +122 -0
  42. pyclickerrpa-0.3.0/tests/test_flow_branch.py +146 -0
  43. pyclickerrpa-0.3.0/tests/test_matcher.py +140 -0
  44. pyclickerrpa-0.3.0/tests/test_runner.py +450 -0
  45. pyclickerrpa-0.3.0/tests/test_testkit.py +303 -0
  46. pyclickerrpa-0.3.0/tests/test_testkit_gui.py +48 -0
  47. pyclickerrpa-0.3.0/tests/test_web.py +155 -0
  48. pyclickerrpa-0.1.0/PKG-INFO +0 -90
  49. pyclickerrpa-0.1.0/PyClickerRPA.egg-info/PKG-INFO +0 -90
  50. pyclickerrpa-0.1.0/README.md +0 -66
  51. pyclickerrpa-0.1.0/autoclicker/matcher.py +0 -152
  52. pyclickerrpa-0.1.0/autoclicker/ocr.py +0 -63
  53. pyclickerrpa-0.1.0/tests/test_matcher.py +0 -64
  54. pyclickerrpa-0.1.0/tests/test_runner.py +0 -196
  55. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/PyClickerRPA.egg-info/dependency_links.txt +0 -0
  56. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/PyClickerRPA.egg-info/top_level.txt +0 -0
  57. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/__init__.py +0 -0
  58. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/app.py +0 -0
  59. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/clicker.py +0 -0
  60. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/dpi.py +0 -0
  61. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/__init__.py +0 -0
  62. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/hotkeys.py +0 -0
  63. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/monitor.py +0 -0
  64. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/preview_label.py +0 -0
  65. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/qt_runner.py +0 -0
  66. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/recorder.py +0 -0
  67. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/scheduler_widget.py +0 -0
  68. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/autoclicker/gui/snippet_library.py +0 -0
  69. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/setup.cfg +0 -0
  70. {pyclickerrpa-0.1.0 → pyclickerrpa-0.3.0}/tests/test_models.py +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Equinox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,138 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyClickerRPA
3
+ Version: 0.3.0
4
+ Summary: Visual UI automation & testing tool: Windows + Android(ADB) automation, robust/self-healing image matching, OCR, node flow editor, recorder, a visual test framework (assertions, visual regression, HTML/JUnit reports) and a web console.
5
+ Author: Equinox
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Equinox/PyClickerRPA
8
+ Keywords: autoclicker,rpa,automation,opencv,template-matching,ocr,gui,windows,android,adb,testing,visual-regression,ui-testing
9
+ Classifier: Environment :: Win32 (MS Windows)
10
+ Classifier: Operating System :: Microsoft :: Windows
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: Topic :: Desktop Environment
16
+ Classifier: Topic :: Software Development :: Testing
17
+ Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: Intended Audience :: End Users/Desktop
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy>=1.23
24
+ Requires-Dist: opencv-python>=4.8
25
+ Requires-Dist: pywin32>=305; sys_platform == "win32"
26
+ Requires-Dist: pynput>=1.7
27
+ Requires-Dist: PySide6>=6.5
28
+ Provides-Extra: ocr
29
+ Requires-Dist: paddleocr>=2.7; extra == "ocr"
30
+ Requires-Dist: paddlepaddle>=2.5; extra == "ocr"
31
+ Provides-Extra: web
32
+ Requires-Dist: fastapi>=0.110; extra == "web"
33
+ Requires-Dist: uvicorn[standard]>=0.27; extra == "web"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=7; extra == "dev"
36
+ Requires-Dist: httpx>=0.24; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # PyClickerRPA
40
+
41
+ A visual UI **automation & testing** tool. Automate Windows apps *and* Android
42
+ devices/emulators by what's on screen — image/text matching + mouse/keyboard (or
43
+ ADB) input — then turn those flows into a **visual test framework** with
44
+ assertions, visual-regression baselines, HTML/JUnit reports, and a **web console**
45
+ for remote runs.
46
+
47
+ Python/PySide6, started as a port of a Qt/C++ AutoClicker (still reads/writes the
48
+ same `.json` task format).
49
+
50
+ ## Install
51
+
52
+ ```
53
+ pip install PyClickerRPA
54
+ ```
55
+
56
+ Optional extras:
57
+
58
+ ```
59
+ pip install "PyClickerRPA[ocr]" # PaddleOCR — find-text / read-text steps
60
+ pip install "PyClickerRPA[web]" # FastAPI + uvicorn — web console
61
+ ```
62
+
63
+ ## Entry points
64
+
65
+ ```
66
+ autoclicker # desktop GUI (flow editor / list editor / test tab)
67
+ autoclicker-run task.json --window "Notepad" # headless run against a window
68
+ autoclicker-run task.json --adb # run against an Android device (adb)
69
+ autoclicker-testkit suite.json --report out.html --junit out.xml # run a test suite
70
+ autoclicker-web --suites-dir examples # web console at http://127.0.0.1:8000
71
+ ```
72
+
73
+ ## Automation engine
74
+
75
+ - **Targets**: any visible window, the whole screen (multi-monitor + high-DPI
76
+ aware), or an **Android device/emulator via ADB** (`--adb [serial]`).
77
+ - **Image matching**: OpenCV template match with **self-healing** by default —
78
+ template → multi-scale → **ORB feature match** fallback (survives scaling /
79
+ minor UI changes); **transparent-mask** templates (PNG alpha) ignore
80
+ don't-care regions. Per-step `matchMode` = `robust` / `template` / `feature`.
81
+ - **Also**: pixel-color checks, optional PaddleOCR text find / read-to-variable.
82
+ - **Smart wait**: `wait_stable` waits until the screen (or an ROI) stops
83
+ changing — replaces guessed `sleep`s (fast when ready, patient when slow).
84
+ - **~30+ step types**: click image/text/position, click-all, relative/offset
85
+ clicks, wait / random / wait-stable, drag / long-press / pinch / scroll,
86
+ key / type / hotkey, loop / goto / while / do-until, if image/text/color/
87
+ count/var with **true/false branching** (if-else), set-var, read-text→variable,
88
+ activate-window, HTTP request, run-Python-script, call sub-task, groups, and a
89
+ **stop** step to end a run — with retry / repeat / until policies.
90
+
91
+ ## Authoring (desktop GUI)
92
+
93
+ Drag-and-drop **node flow graph** (condition nodes have **true/false branch
94
+ ports** for visual if-else; a terminal **stop** node ends the flow) and an
95
+ interoperable **step list** with a full
96
+ per-step dialog; an action **recorder** (global hooks), snippet library, task
97
+ packages (`.zip` with templates), on-preview coordinate/color picking, template
98
+ crop, single-step test run; global hotkeys (F6 run/stop, ESC stop), scheduler,
99
+ and an image/color **monitor/trigger** with tray icon; a **Test** tab to load and
100
+ run visual test suites.
101
+
102
+ ## Visual test framework (`autoclicker.testkit`)
103
+
104
+ Turn automation into tests:
105
+
106
+ - **Assertions**: image / text / color present-or-absent, variable comparison.
107
+ - **Visual regression**: baseline diff (first run captures the baseline; later
108
+ runs flag changed-pixel ratio and emit a baseline|actual|heatmap image).
109
+ - **Cases & suites**: declarative JSON suites *or* pytest fixtures (`screen`,
110
+ `visual`); **data-driven** cases (a data table / CSV runs the case per row).
111
+ - **Reports**: self-contained **HTML** (embedded screenshots + per-step
112
+ timeline, optional GIF) and **JUnit XML** for CI; retries mark **flaky**.
113
+
114
+ ```python
115
+ # pytest style
116
+ def test_login(screen, visual):
117
+ screen.assert_image("assets/login_btn.png")
118
+ screen.assert_text("Username")
119
+ visual.check("login.png", tolerance=0.02)
120
+ ```
121
+
122
+ ## Web console (`autoclicker-web`)
123
+
124
+ Browser UI to trigger suites (single or batched), watch **live per-line logs**
125
+ and per-case results, schedule recurring runs, list ADB devices and grab
126
+ **screenshots**, browse **persisted run history**, and open the HTML report — all
127
+ served by FastAPI with a zero-build vanilla-JS front end.
128
+
129
+ ## Notes
130
+
131
+ - Host is **Windows** (Win32 capture + `SendInput`); ADB targets are
132
+ cross-platform via the `adb` CLI (must be on `PATH`).
133
+ - OCR's first run downloads PaddleOCR models (~100 MB).
134
+ - Some target windows may require running as administrator.
135
+
136
+ ## License
137
+
138
+ MIT
@@ -0,0 +1,138 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyClickerRPA
3
+ Version: 0.3.0
4
+ Summary: Visual UI automation & testing tool: Windows + Android(ADB) automation, robust/self-healing image matching, OCR, node flow editor, recorder, a visual test framework (assertions, visual regression, HTML/JUnit reports) and a web console.
5
+ Author: Equinox
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Equinox/PyClickerRPA
8
+ Keywords: autoclicker,rpa,automation,opencv,template-matching,ocr,gui,windows,android,adb,testing,visual-regression,ui-testing
9
+ Classifier: Environment :: Win32 (MS Windows)
10
+ Classifier: Operating System :: Microsoft :: Windows
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: Topic :: Desktop Environment
16
+ Classifier: Topic :: Software Development :: Testing
17
+ Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: Intended Audience :: End Users/Desktop
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy>=1.23
24
+ Requires-Dist: opencv-python>=4.8
25
+ Requires-Dist: pywin32>=305; sys_platform == "win32"
26
+ Requires-Dist: pynput>=1.7
27
+ Requires-Dist: PySide6>=6.5
28
+ Provides-Extra: ocr
29
+ Requires-Dist: paddleocr>=2.7; extra == "ocr"
30
+ Requires-Dist: paddlepaddle>=2.5; extra == "ocr"
31
+ Provides-Extra: web
32
+ Requires-Dist: fastapi>=0.110; extra == "web"
33
+ Requires-Dist: uvicorn[standard]>=0.27; extra == "web"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=7; extra == "dev"
36
+ Requires-Dist: httpx>=0.24; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # PyClickerRPA
40
+
41
+ A visual UI **automation & testing** tool. Automate Windows apps *and* Android
42
+ devices/emulators by what's on screen — image/text matching + mouse/keyboard (or
43
+ ADB) input — then turn those flows into a **visual test framework** with
44
+ assertions, visual-regression baselines, HTML/JUnit reports, and a **web console**
45
+ for remote runs.
46
+
47
+ Python/PySide6, started as a port of a Qt/C++ AutoClicker (still reads/writes the
48
+ same `.json` task format).
49
+
50
+ ## Install
51
+
52
+ ```
53
+ pip install PyClickerRPA
54
+ ```
55
+
56
+ Optional extras:
57
+
58
+ ```
59
+ pip install "PyClickerRPA[ocr]" # PaddleOCR — find-text / read-text steps
60
+ pip install "PyClickerRPA[web]" # FastAPI + uvicorn — web console
61
+ ```
62
+
63
+ ## Entry points
64
+
65
+ ```
66
+ autoclicker # desktop GUI (flow editor / list editor / test tab)
67
+ autoclicker-run task.json --window "Notepad" # headless run against a window
68
+ autoclicker-run task.json --adb # run against an Android device (adb)
69
+ autoclicker-testkit suite.json --report out.html --junit out.xml # run a test suite
70
+ autoclicker-web --suites-dir examples # web console at http://127.0.0.1:8000
71
+ ```
72
+
73
+ ## Automation engine
74
+
75
+ - **Targets**: any visible window, the whole screen (multi-monitor + high-DPI
76
+ aware), or an **Android device/emulator via ADB** (`--adb [serial]`).
77
+ - **Image matching**: OpenCV template match with **self-healing** by default —
78
+ template → multi-scale → **ORB feature match** fallback (survives scaling /
79
+ minor UI changes); **transparent-mask** templates (PNG alpha) ignore
80
+ don't-care regions. Per-step `matchMode` = `robust` / `template` / `feature`.
81
+ - **Also**: pixel-color checks, optional PaddleOCR text find / read-to-variable.
82
+ - **Smart wait**: `wait_stable` waits until the screen (or an ROI) stops
83
+ changing — replaces guessed `sleep`s (fast when ready, patient when slow).
84
+ - **~30+ step types**: click image/text/position, click-all, relative/offset
85
+ clicks, wait / random / wait-stable, drag / long-press / pinch / scroll,
86
+ key / type / hotkey, loop / goto / while / do-until, if image/text/color/
87
+ count/var with **true/false branching** (if-else), set-var, read-text→variable,
88
+ activate-window, HTTP request, run-Python-script, call sub-task, groups, and a
89
+ **stop** step to end a run — with retry / repeat / until policies.
90
+
91
+ ## Authoring (desktop GUI)
92
+
93
+ Drag-and-drop **node flow graph** (condition nodes have **true/false branch
94
+ ports** for visual if-else; a terminal **stop** node ends the flow) and an
95
+ interoperable **step list** with a full
96
+ per-step dialog; an action **recorder** (global hooks), snippet library, task
97
+ packages (`.zip` with templates), on-preview coordinate/color picking, template
98
+ crop, single-step test run; global hotkeys (F6 run/stop, ESC stop), scheduler,
99
+ and an image/color **monitor/trigger** with tray icon; a **Test** tab to load and
100
+ run visual test suites.
101
+
102
+ ## Visual test framework (`autoclicker.testkit`)
103
+
104
+ Turn automation into tests:
105
+
106
+ - **Assertions**: image / text / color present-or-absent, variable comparison.
107
+ - **Visual regression**: baseline diff (first run captures the baseline; later
108
+ runs flag changed-pixel ratio and emit a baseline|actual|heatmap image).
109
+ - **Cases & suites**: declarative JSON suites *or* pytest fixtures (`screen`,
110
+ `visual`); **data-driven** cases (a data table / CSV runs the case per row).
111
+ - **Reports**: self-contained **HTML** (embedded screenshots + per-step
112
+ timeline, optional GIF) and **JUnit XML** for CI; retries mark **flaky**.
113
+
114
+ ```python
115
+ # pytest style
116
+ def test_login(screen, visual):
117
+ screen.assert_image("assets/login_btn.png")
118
+ screen.assert_text("Username")
119
+ visual.check("login.png", tolerance=0.02)
120
+ ```
121
+
122
+ ## Web console (`autoclicker-web`)
123
+
124
+ Browser UI to trigger suites (single or batched), watch **live per-line logs**
125
+ and per-case results, schedule recurring runs, list ADB devices and grab
126
+ **screenshots**, browse **persisted run history**, and open the HTML report — all
127
+ served by FastAPI with a zero-build vanilla-JS front end.
128
+
129
+ ## Notes
130
+
131
+ - Host is **Windows** (Win32 capture + `SendInput`); ADB targets are
132
+ cross-platform via the `adb` CLI (must be on `PATH`).
133
+ - OCR's first run downloads PaddleOCR models (~100 MB).
134
+ - Some target windows may require running as administrator.
135
+
136
+ ## License
137
+
138
+ MIT
@@ -1,3 +1,4 @@
1
+ LICENSE
1
2
  README.md
2
3
  pyproject.toml
3
4
  PyClickerRPA.egg-info/PKG-INFO
@@ -7,6 +8,7 @@ PyClickerRPA.egg-info/entry_points.txt
7
8
  PyClickerRPA.egg-info/requires.txt
8
9
  PyClickerRPA.egg-info/top_level.txt
9
10
  autoclicker/__init__.py
11
+ autoclicker/adb.py
10
12
  autoclicker/app.py
11
13
  autoclicker/capture.py
12
14
  autoclicker/clicker.py
@@ -30,6 +32,30 @@ autoclicker/gui/recorder.py
30
32
  autoclicker/gui/scheduler_widget.py
31
33
  autoclicker/gui/snippet_library.py
32
34
  autoclicker/gui/task_widget.py
35
+ autoclicker/gui/testkit_widget.py
36
+ autoclicker/testkit/__init__.py
37
+ autoclicker/testkit/__main__.py
38
+ autoclicker/testkit/assertions.py
39
+ autoclicker/testkit/case.py
40
+ autoclicker/testkit/loader.py
41
+ autoclicker/testkit/pytest_plugin.py
42
+ autoclicker/testkit/report.py
43
+ autoclicker/testkit/runner.py
44
+ autoclicker/testkit/visual.py
45
+ autoclicker/web/__init__.py
46
+ autoclicker/web/__main__.py
47
+ autoclicker/web/run_manager.py
48
+ autoclicker/web/scheduler.py
49
+ autoclicker/web/serialize.py
50
+ autoclicker/web/server.py
51
+ autoclicker/web/static/app.js
52
+ autoclicker/web/static/index.html
53
+ autoclicker/web/static/style.css
54
+ tests/test_adb.py
55
+ tests/test_flow_branch.py
33
56
  tests/test_matcher.py
34
57
  tests/test_models.py
35
- tests/test_runner.py
58
+ tests/test_runner.py
59
+ tests/test_testkit.py
60
+ tests/test_testkit_gui.py
61
+ tests/test_web.py
@@ -1,5 +1,7 @@
1
1
  [console_scripts]
2
2
  autoclicker-run = autoclicker.run:main
3
+ autoclicker-testkit = autoclicker.testkit.__main__:main
4
+ autoclicker-web = autoclicker.web.__main__:main
3
5
 
4
6
  [gui_scripts]
5
7
  autoclicker = autoclicker.app:main
@@ -6,6 +6,14 @@ PySide6>=6.5
6
6
  [:sys_platform == "win32"]
7
7
  pywin32>=305
8
8
 
9
+ [dev]
10
+ pytest>=7
11
+ httpx>=0.24
12
+
9
13
  [ocr]
10
14
  paddleocr>=2.7
11
15
  paddlepaddle>=2.5
16
+
17
+ [web]
18
+ fastapi>=0.110
19
+ uvicorn[standard]>=0.27
@@ -0,0 +1,100 @@
1
+ # PyClickerRPA
2
+
3
+ A visual UI **automation & testing** tool. Automate Windows apps *and* Android
4
+ devices/emulators by what's on screen — image/text matching + mouse/keyboard (or
5
+ ADB) input — then turn those flows into a **visual test framework** with
6
+ assertions, visual-regression baselines, HTML/JUnit reports, and a **web console**
7
+ for remote runs.
8
+
9
+ Python/PySide6, started as a port of a Qt/C++ AutoClicker (still reads/writes the
10
+ same `.json` task format).
11
+
12
+ ## Install
13
+
14
+ ```
15
+ pip install PyClickerRPA
16
+ ```
17
+
18
+ Optional extras:
19
+
20
+ ```
21
+ pip install "PyClickerRPA[ocr]" # PaddleOCR — find-text / read-text steps
22
+ pip install "PyClickerRPA[web]" # FastAPI + uvicorn — web console
23
+ ```
24
+
25
+ ## Entry points
26
+
27
+ ```
28
+ autoclicker # desktop GUI (flow editor / list editor / test tab)
29
+ autoclicker-run task.json --window "Notepad" # headless run against a window
30
+ autoclicker-run task.json --adb # run against an Android device (adb)
31
+ autoclicker-testkit suite.json --report out.html --junit out.xml # run a test suite
32
+ autoclicker-web --suites-dir examples # web console at http://127.0.0.1:8000
33
+ ```
34
+
35
+ ## Automation engine
36
+
37
+ - **Targets**: any visible window, the whole screen (multi-monitor + high-DPI
38
+ aware), or an **Android device/emulator via ADB** (`--adb [serial]`).
39
+ - **Image matching**: OpenCV template match with **self-healing** by default —
40
+ template → multi-scale → **ORB feature match** fallback (survives scaling /
41
+ minor UI changes); **transparent-mask** templates (PNG alpha) ignore
42
+ don't-care regions. Per-step `matchMode` = `robust` / `template` / `feature`.
43
+ - **Also**: pixel-color checks, optional PaddleOCR text find / read-to-variable.
44
+ - **Smart wait**: `wait_stable` waits until the screen (or an ROI) stops
45
+ changing — replaces guessed `sleep`s (fast when ready, patient when slow).
46
+ - **~30+ step types**: click image/text/position, click-all, relative/offset
47
+ clicks, wait / random / wait-stable, drag / long-press / pinch / scroll,
48
+ key / type / hotkey, loop / goto / while / do-until, if image/text/color/
49
+ count/var with **true/false branching** (if-else), set-var, read-text→variable,
50
+ activate-window, HTTP request, run-Python-script, call sub-task, groups, and a
51
+ **stop** step to end a run — with retry / repeat / until policies.
52
+
53
+ ## Authoring (desktop GUI)
54
+
55
+ Drag-and-drop **node flow graph** (condition nodes have **true/false branch
56
+ ports** for visual if-else; a terminal **stop** node ends the flow) and an
57
+ interoperable **step list** with a full
58
+ per-step dialog; an action **recorder** (global hooks), snippet library, task
59
+ packages (`.zip` with templates), on-preview coordinate/color picking, template
60
+ crop, single-step test run; global hotkeys (F6 run/stop, ESC stop), scheduler,
61
+ and an image/color **monitor/trigger** with tray icon; a **Test** tab to load and
62
+ run visual test suites.
63
+
64
+ ## Visual test framework (`autoclicker.testkit`)
65
+
66
+ Turn automation into tests:
67
+
68
+ - **Assertions**: image / text / color present-or-absent, variable comparison.
69
+ - **Visual regression**: baseline diff (first run captures the baseline; later
70
+ runs flag changed-pixel ratio and emit a baseline|actual|heatmap image).
71
+ - **Cases & suites**: declarative JSON suites *or* pytest fixtures (`screen`,
72
+ `visual`); **data-driven** cases (a data table / CSV runs the case per row).
73
+ - **Reports**: self-contained **HTML** (embedded screenshots + per-step
74
+ timeline, optional GIF) and **JUnit XML** for CI; retries mark **flaky**.
75
+
76
+ ```python
77
+ # pytest style
78
+ def test_login(screen, visual):
79
+ screen.assert_image("assets/login_btn.png")
80
+ screen.assert_text("Username")
81
+ visual.check("login.png", tolerance=0.02)
82
+ ```
83
+
84
+ ## Web console (`autoclicker-web`)
85
+
86
+ Browser UI to trigger suites (single or batched), watch **live per-line logs**
87
+ and per-case results, schedule recurring runs, list ADB devices and grab
88
+ **screenshots**, browse **persisted run history**, and open the HTML report — all
89
+ served by FastAPI with a zero-build vanilla-JS front end.
90
+
91
+ ## Notes
92
+
93
+ - Host is **Windows** (Win32 capture + `SendInput`); ADB targets are
94
+ cross-platform via the `adb` CLI (must be on `PATH`).
95
+ - OCR's first run downloads PaddleOCR models (~100 MB).
96
+ - Some target windows may require running as administrator.
97
+
98
+ ## License
99
+
100
+ MIT
@@ -0,0 +1,163 @@
1
+ """ADB 设备后端:自动化 Android 手机/模拟器(通用 adb CLI)。
2
+
3
+ 契约与 Windows 后端一致(capture 返回 BGR ndarray、clicker 首参 hwnd 但忽略),
4
+ 所以能直接注入 TaskRunner(target_hwnd=None, capture=AdbCapture, clicker=AdbClicker)。
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import subprocess
9
+
10
+ import numpy as np
11
+
12
+ # Windows VK -> Android keycode(覆盖常用键;其余忽略)
13
+ _VK_TO_ANDROID = {
14
+ 0x0D: 66, # ENTER
15
+ 0x1B: 4, # ESC -> BACK
16
+ 0x09: 61, # TAB
17
+ 0x20: 62, # SPACE
18
+ 0x08: 67, # BACKSPACE -> DEL
19
+ 0x2E: 112, # DELETE -> FORWARD_DEL
20
+ 0x26: 19, 0x28: 20, 0x25: 21, 0x27: 22, # UP DOWN LEFT RIGHT
21
+ 0x24: 3, # HOME
22
+ }
23
+
24
+
25
+ def _vk_to_android(vk: int) -> int | None:
26
+ if vk in _VK_TO_ANDROID:
27
+ return _VK_TO_ANDROID[vk]
28
+ if 0x41 <= vk <= 0x5A: # A-Z -> KEYCODE_A(29)..
29
+ return 29 + (vk - 0x41)
30
+ if 0x30 <= vk <= 0x39: # 0-9 -> KEYCODE_0(7)..
31
+ return 7 + (vk - 0x30)
32
+ return None
33
+
34
+
35
+ class AdbDevice:
36
+ def __init__(self, serial: str | None = None, adb: str = "adb"):
37
+ self.serial = serial
38
+ self.adb = adb
39
+
40
+ def _cmd(self, args: list[str]) -> list[str]:
41
+ base = [self.adb]
42
+ if self.serial:
43
+ base += ["-s", self.serial]
44
+ return base + args
45
+
46
+ def _run(self, args: list[str]) -> bytes:
47
+ try:
48
+ proc = subprocess.run(self._cmd(args), stdout=subprocess.PIPE,
49
+ stderr=subprocess.PIPE)
50
+ except FileNotFoundError as e:
51
+ raise RuntimeError(f"找不到 adb 可执行文件 '{self.adb}',请安装 Android Platform Tools 并加入 PATH") from e
52
+ if proc.returncode != 0:
53
+ raise RuntimeError(f"adb {' '.join(args)} 失败: {proc.stderr.decode('utf-8', 'replace').strip()}")
54
+ return proc.stdout
55
+
56
+ # ---- capture ----
57
+ def screencap(self) -> np.ndarray:
58
+ """截图 -> BGR ndarray(exec-out 避免 stdout CRLF 转换的坑)。"""
59
+ import cv2
60
+ raw = self._run(["exec-out", "screencap", "-p"])
61
+ img = cv2.imdecode(np.frombuffer(raw, dtype=np.uint8), cv2.IMREAD_COLOR)
62
+ if img is None or img.size == 0:
63
+ raise RuntimeError("screencap 解码失败(设备可能不支持 exec-out)")
64
+ return img
65
+
66
+ # ---- input ----
67
+ def tap(self, x: int, y: int) -> None:
68
+ self._run(["shell", "input", "tap", str(int(x)), str(int(y))])
69
+
70
+ def swipe(self, x1: int, y1: int, x2: int, y2: int, ms: int = 300) -> None:
71
+ self._run(["shell", "input", "swipe", str(int(x1)), str(int(y1)),
72
+ str(int(x2)), str(int(y2)), str(int(ms))])
73
+
74
+ def long_press(self, x: int, y: int, hold_ms: int = 800) -> None:
75
+ self.swipe(x, y, x, y, hold_ms) # same point + duration = long press
76
+
77
+ def text(self, s: str) -> None:
78
+ # Android `input text` 用 %s 表示空格
79
+ self._run(["shell", "input", "text", s.replace(" ", "%s")])
80
+
81
+ def keyevent(self, code: int) -> None:
82
+ self._run(["shell", "input", "keyevent", str(int(code))])
83
+
84
+ @staticmethod
85
+ def list_devices(adb: str = "adb") -> list[str]:
86
+ try:
87
+ out = subprocess.run([adb, "devices"], stdout=subprocess.PIPE,
88
+ stderr=subprocess.PIPE).stdout.decode("utf-8", "replace")
89
+ except FileNotFoundError:
90
+ return []
91
+ serials = []
92
+ for line in out.splitlines()[1:]:
93
+ parts = line.split()
94
+ if len(parts) >= 2 and parts[1] == "device":
95
+ serials.append(parts[0])
96
+ return serials
97
+
98
+
99
+ class AdbCapture:
100
+ """capture 后端:忽略 hwnd,一律截设备屏。"""
101
+ def __init__(self, device: AdbDevice):
102
+ self.device = device
103
+
104
+ def capture_screen(self) -> np.ndarray:
105
+ return self.device.screencap()
106
+
107
+ def capture_window(self, hwnd) -> np.ndarray:
108
+ return self.device.screencap()
109
+
110
+
111
+ class AdbClicker:
112
+ """clicker 后端:把 Windows 语义的调用映射到 adb input(首参 hwnd 忽略)。"""
113
+ def __init__(self, device: AdbDevice):
114
+ self.device = device
115
+
116
+ def click(self, hwnd, x: int, y: int) -> None:
117
+ self.device.tap(x, y)
118
+
119
+ def double_click(self, hwnd, x: int, y: int) -> None:
120
+ self.device.tap(x, y)
121
+ self.device.tap(x, y)
122
+
123
+ def right_click(self, hwnd, x: int, y: int) -> None:
124
+ self.device.tap(x, y) # Android 无右键,退化为点击
125
+
126
+ def long_press(self, hwnd, x: int, y: int, hold_ms: int) -> None:
127
+ self.device.long_press(x, y, hold_ms)
128
+
129
+ def swipe(self, hwnd, x1, y1, x2, y2, duration_ms: int = 300) -> None:
130
+ self.device.swipe(x1, y1, x2, y2, duration_ms)
131
+
132
+ def drag(self, hwnd, x1, y1, x2, y2, duration_ms: int = 300) -> None:
133
+ self.device.swipe(x1, y1, x2, y2, duration_ms)
134
+
135
+ def scroll(self, hwnd, x, y, amount: int) -> None:
136
+ # 正数向上滚:从 (x,y) 向上滑
137
+ self.device.swipe(x, y, x, y - amount * 100, 300)
138
+
139
+ def type_text(self, text: str) -> None:
140
+ self.device.text(text)
141
+
142
+ def key_press(self, vk: int) -> None:
143
+ code = _vk_to_android(vk)
144
+ if code is not None:
145
+ self.device.keyevent(code)
146
+
147
+ def key_down(self, vk: int) -> None:
148
+ self.key_press(vk)
149
+
150
+ def key_up(self, vk: int) -> None:
151
+ pass
152
+
153
+ def hotkey(self, modifier: int, vk: int) -> None:
154
+ self.key_press(vk) # Android input 无组合键,尽力而为
155
+
156
+ def pinch(self, hwnd, cx, cy, start_dist, end_dist, duration_ms: int = 400) -> None:
157
+ pass # adb input 不支持多点触控,跳过
158
+
159
+
160
+ def make_adb_backends(serial: str | None = None, adb: str = "adb"):
161
+ """便捷构造:返回 (capture, clicker) 供注入 TaskRunner。"""
162
+ dev = AdbDevice(serial, adb)
163
+ return AdbCapture(dev), AdbClicker(dev)