devhelmkit 0.1.0__py3-none-any.whl
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.
- devhelmkit/__init__.py +44 -0
- devhelmkit/android/__init__.py +7 -0
- devhelmkit/android/driver.py +18 -0
- devhelmkit/assets/so/arm64-v8a/agent_v1.so +0 -0
- devhelmkit/assets/so/arm64-v8a/agent_v2.so +0 -0
- devhelmkit/assets/so/x86_64/agent.so +0 -0
- devhelmkit/core/__init__.py +3 -0
- devhelmkit/core/base_component.py +214 -0
- devhelmkit/core/base_driver.py +414 -0
- devhelmkit/core/base_window.py +25 -0
- devhelmkit/core/selector_spec.py +102 -0
- devhelmkit/entry.py +90 -0
- devhelmkit/exceptions.py +56 -0
- devhelmkit/harmony/__init__.py +3 -0
- devhelmkit/harmony/agent/__init__.py +7 -0
- devhelmkit/harmony/agent/so_manager.py +300 -0
- devhelmkit/harmony/config.py +124 -0
- devhelmkit/harmony/device/__init__.py +6 -0
- devhelmkit/harmony/device/hdc.py +430 -0
- devhelmkit/harmony/driver.py +1416 -0
- devhelmkit/harmony/finder/__init__.py +12 -0
- devhelmkit/harmony/finder/component_finder.py +336 -0
- devhelmkit/harmony/finder/popup_handler.py +81 -0
- devhelmkit/harmony/finder/selector_adapter.py +101 -0
- devhelmkit/harmony/finder/xpath_query.py +110 -0
- devhelmkit/harmony/rpc/__init__.py +12 -0
- devhelmkit/harmony/rpc/client.py +126 -0
- devhelmkit/harmony/rpc/proxy_v2.py +106 -0
- devhelmkit/harmony/rpc/remote_object.py +48 -0
- devhelmkit/harmony/uiobject.py +246 -0
- devhelmkit/harmony/uiwindow.py +43 -0
- devhelmkit/harmony/webview/__init__.py +17 -0
- devhelmkit/harmony/webview/chromedriver_manager.py +251 -0
- devhelmkit/harmony/webview/devtools_finder.py +131 -0
- devhelmkit/harmony/webview/webview_driver.py +326 -0
- devhelmkit/model/__init__.py +3 -0
- devhelmkit/model/action.py +147 -0
- devhelmkit/model/app_state.py +50 -0
- devhelmkit/model/constants.py +22 -0
- devhelmkit/model/display.py +32 -0
- devhelmkit/model/format_string.py +24 -0
- devhelmkit/model/input.py +50 -0
- devhelmkit/model/json_base.py +42 -0
- devhelmkit/model/keys.py +375 -0
- devhelmkit/model/match_pattern.py +15 -0
- devhelmkit/model/page.py +13 -0
- devhelmkit/model/params.py +42 -0
- devhelmkit/model/rect.py +58 -0
- devhelmkit/model/runnable.py +18 -0
- devhelmkit/utils/__init__.py +3 -0
- devhelmkit/utils/logger.py +72 -0
- devhelmkit/utils/retry.py +46 -0
- devhelmkit/utils/timeout.py +64 -0
- devhelmkit-0.1.0.dist-info/METADATA +411 -0
- devhelmkit-0.1.0.dist-info/RECORD +58 -0
- devhelmkit-0.1.0.dist-info/WHEEL +5 -0
- devhelmkit-0.1.0.dist-info/licenses/LICENSE +201 -0
- devhelmkit-0.1.0.dist-info/top_level.txt +1 -0
devhelmkit/model/keys.py
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""KeyCode:OpenHarmony 按键码枚举。
|
|
4
|
+
|
|
5
|
+
重要:使用 OpenHarmony 按键码体系(非 Android KeyEvent),数值从
|
|
6
|
+
2000 起步。禁止套用 Android 数值。
|
|
7
|
+
采用 IntEnum 以支持数值比较。
|
|
8
|
+
"""
|
|
9
|
+
from enum import IntEnum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class KeyCode(IntEnum):
|
|
13
|
+
"""OpenHarmony 按键码。"""
|
|
14
|
+
|
|
15
|
+
# 功能与系统按键
|
|
16
|
+
FN = 0
|
|
17
|
+
UNKNOWN = -1
|
|
18
|
+
HOME = 1
|
|
19
|
+
BACK = 2
|
|
20
|
+
POWER = 18
|
|
21
|
+
CAMERA = 19
|
|
22
|
+
VOLUME_MUTE = 22
|
|
23
|
+
MUTE = 23
|
|
24
|
+
SLEEP = 2600
|
|
25
|
+
WAKE_UP = 2802
|
|
26
|
+
SCREENLOCK = 2809
|
|
27
|
+
VIRTUAL_MULTITASK = 2210
|
|
28
|
+
|
|
29
|
+
# 音量按键
|
|
30
|
+
VOLUME_UP = 16
|
|
31
|
+
VOLUME_DOWN = 17
|
|
32
|
+
|
|
33
|
+
# 亮度按键
|
|
34
|
+
BRIGHTNESS_UP = 40
|
|
35
|
+
BRIGHTNESS_DOWN = 41
|
|
36
|
+
|
|
37
|
+
# 多媒体按键
|
|
38
|
+
MEDIA_PLAY_PAUSE = 10
|
|
39
|
+
MEDIA_STOP = 11
|
|
40
|
+
MEDIA_NEXT = 12
|
|
41
|
+
MEDIA_PREVIOUS = 13
|
|
42
|
+
MEDIA_REWIND = 14
|
|
43
|
+
MEDIA_FAST_FORWARD = 15
|
|
44
|
+
MEDIA_PLAY = 2085
|
|
45
|
+
MEDIA_PAUSE = 2086
|
|
46
|
+
MEDIA_CLOSE = 2087
|
|
47
|
+
MEDIA_EJECT = 2088
|
|
48
|
+
MEDIA_RECORD = 2089
|
|
49
|
+
|
|
50
|
+
# 导航键
|
|
51
|
+
DPAD_UP = 2012
|
|
52
|
+
DPAD_DOWN = 2013
|
|
53
|
+
DPAD_LEFT = 2014
|
|
54
|
+
DPAD_RIGHT = 2015
|
|
55
|
+
DPAD_CENTER = 2016
|
|
56
|
+
PAGE_UP = 2068
|
|
57
|
+
PAGE_DOWN = 2069
|
|
58
|
+
MOVE_HOME = 2081
|
|
59
|
+
MOVE_END = 2082
|
|
60
|
+
|
|
61
|
+
# 数字键
|
|
62
|
+
NUM_0 = 2000
|
|
63
|
+
NUM_1 = 2001
|
|
64
|
+
NUM_2 = 2002
|
|
65
|
+
NUM_3 = 2003
|
|
66
|
+
NUM_4 = 2004
|
|
67
|
+
NUM_5 = 2005
|
|
68
|
+
NUM_6 = 2006
|
|
69
|
+
NUM_7 = 2007
|
|
70
|
+
NUM_8 = 2008
|
|
71
|
+
NUM_9 = 2009
|
|
72
|
+
STAR = 2010
|
|
73
|
+
POUND = 2011
|
|
74
|
+
|
|
75
|
+
# 字母键 A-Z
|
|
76
|
+
A = 2017
|
|
77
|
+
B = 2018
|
|
78
|
+
C = 2019
|
|
79
|
+
D = 2020
|
|
80
|
+
E = 2021
|
|
81
|
+
F = 2022
|
|
82
|
+
G = 2023
|
|
83
|
+
H = 2024
|
|
84
|
+
I = 2025
|
|
85
|
+
J = 2026
|
|
86
|
+
K = 2027
|
|
87
|
+
L = 2028
|
|
88
|
+
M = 2029
|
|
89
|
+
N = 2030
|
|
90
|
+
O = 2031
|
|
91
|
+
P = 2032
|
|
92
|
+
Q = 2033
|
|
93
|
+
R = 2034
|
|
94
|
+
S = 2035
|
|
95
|
+
T = 2036
|
|
96
|
+
U = 2037
|
|
97
|
+
V = 2038
|
|
98
|
+
W = 2039
|
|
99
|
+
X = 2040
|
|
100
|
+
Y = 2041
|
|
101
|
+
Z = 2042
|
|
102
|
+
|
|
103
|
+
# 标点与符号
|
|
104
|
+
COMMA = 2043
|
|
105
|
+
PERIOD = 2044
|
|
106
|
+
GRAVE = 2056
|
|
107
|
+
MINUS = 2057
|
|
108
|
+
EQUALS = 2058
|
|
109
|
+
LEFT_BRACKET = 2059
|
|
110
|
+
RIGHT_BRACKET = 2060
|
|
111
|
+
BACKSLASH = 2061
|
|
112
|
+
SEMICOLON = 2062
|
|
113
|
+
APOSTROPHE = 2063
|
|
114
|
+
SLASH = 2064
|
|
115
|
+
AT = 2065
|
|
116
|
+
PLUS = 2066
|
|
117
|
+
|
|
118
|
+
# 编辑与控制键
|
|
119
|
+
TAB = 2049
|
|
120
|
+
SPACE = 2050
|
|
121
|
+
SYM = 2051
|
|
122
|
+
EXPLORER = 2052
|
|
123
|
+
ENVELOPE = 2053
|
|
124
|
+
ENTER = 2054
|
|
125
|
+
DEL = 2055
|
|
126
|
+
ESCAPE = 2070
|
|
127
|
+
FORWARD_DEL = 2071
|
|
128
|
+
INSERT = 2083
|
|
129
|
+
FORWARD = 2084
|
|
130
|
+
MENU = 2067
|
|
131
|
+
|
|
132
|
+
# 修饰键
|
|
133
|
+
ALT_LEFT = 2045
|
|
134
|
+
ALT_RIGHT = 2046
|
|
135
|
+
SHIFT_LEFT = 2047
|
|
136
|
+
SHIFT_RIGHT = 2048
|
|
137
|
+
CTRL_LEFT = 2072
|
|
138
|
+
CTRL_RIGHT = 2073
|
|
139
|
+
CAPS_LOCK = 2074
|
|
140
|
+
SCROLL_LOCK = 2075
|
|
141
|
+
META_LEFT = 2076
|
|
142
|
+
META_RIGHT = 2077
|
|
143
|
+
FUNCTION = 2078
|
|
144
|
+
SYSRQ = 2079
|
|
145
|
+
BREAK = 2080
|
|
146
|
+
|
|
147
|
+
# 功能键 F1-F24
|
|
148
|
+
F1 = 2090
|
|
149
|
+
F2 = 2091
|
|
150
|
+
F3 = 2092
|
|
151
|
+
F4 = 2093
|
|
152
|
+
F5 = 2094
|
|
153
|
+
F6 = 2095
|
|
154
|
+
F7 = 2096
|
|
155
|
+
F8 = 2097
|
|
156
|
+
F9 = 2098
|
|
157
|
+
F10 = 2099
|
|
158
|
+
F11 = 2100
|
|
159
|
+
F12 = 2101
|
|
160
|
+
F13 = 2816
|
|
161
|
+
F14 = 2817
|
|
162
|
+
F15 = 2818
|
|
163
|
+
F16 = 2819
|
|
164
|
+
F17 = 2820
|
|
165
|
+
F18 = 2821
|
|
166
|
+
F19 = 2822
|
|
167
|
+
F20 = 2823
|
|
168
|
+
F21 = 2824
|
|
169
|
+
F22 = 2825
|
|
170
|
+
F23 = 2826
|
|
171
|
+
F24 = 2827
|
|
172
|
+
|
|
173
|
+
# 小键盘
|
|
174
|
+
NUM_LOCK = 2102
|
|
175
|
+
NUMPAD_0 = 2103
|
|
176
|
+
NUMPAD_1 = 2104
|
|
177
|
+
NUMPAD_2 = 2105
|
|
178
|
+
NUMPAD_3 = 2106
|
|
179
|
+
NUMPAD_4 = 2107
|
|
180
|
+
NUMPAD_5 = 2108
|
|
181
|
+
NUMPAD_6 = 2109
|
|
182
|
+
NUMPAD_7 = 2110
|
|
183
|
+
NUMPAD_8 = 2111
|
|
184
|
+
NUMPAD_9 = 2112
|
|
185
|
+
NUMPAD_DIVIDE = 2113
|
|
186
|
+
NUMPAD_MULTIPLY = 2114
|
|
187
|
+
NUMPAD_SUBTRACT = 2115
|
|
188
|
+
NUMPAD_ADD = 2116
|
|
189
|
+
NUMPAD_DOT = 2117
|
|
190
|
+
NUMPAD_COMMA = 2118
|
|
191
|
+
NUMPAD_ENTER = 2119
|
|
192
|
+
NUMPAD_EQUALS = 2120
|
|
193
|
+
NUMPAD_LEFT_PAREN = 2121
|
|
194
|
+
NUMPAD_RIGHT_PAREN = 2122
|
|
195
|
+
NUMPAD_PLUSMINUS = 2611
|
|
196
|
+
|
|
197
|
+
# 日文/韩文键
|
|
198
|
+
ZENKAKU_HANKAKU = 2601
|
|
199
|
+
ND = 2602
|
|
200
|
+
RO = 2603
|
|
201
|
+
KATAKANA = 2604
|
|
202
|
+
HIRAGANA = 2605
|
|
203
|
+
HENKAN = 2606
|
|
204
|
+
KATAKANA_HIRAGANA = 2607
|
|
205
|
+
MUHENKAN = 2608
|
|
206
|
+
LINEFEED = 2609
|
|
207
|
+
MACRO = 2610
|
|
208
|
+
SCALE = 2612
|
|
209
|
+
HANGUEL = 2613
|
|
210
|
+
HANJA = 2614
|
|
211
|
+
YEN = 2615
|
|
212
|
+
|
|
213
|
+
# 多媒体扩展键
|
|
214
|
+
STOP = 2616
|
|
215
|
+
AGAIN = 2617
|
|
216
|
+
PROPS = 2618
|
|
217
|
+
UNDO = 2619
|
|
218
|
+
COPY = 2620
|
|
219
|
+
OPEN = 2621
|
|
220
|
+
PASTE = 2622
|
|
221
|
+
FIND = 2623
|
|
222
|
+
CUT = 2624
|
|
223
|
+
HELP = 2625
|
|
224
|
+
CALC = 2626
|
|
225
|
+
FILE = 2627
|
|
226
|
+
BOOKMARKS = 2628
|
|
227
|
+
NEXT = 2629
|
|
228
|
+
PLAYPAUSE = 2630
|
|
229
|
+
PREVIOUS = 2631
|
|
230
|
+
STOPCD = 2632
|
|
231
|
+
CONFIG = 2634
|
|
232
|
+
REFRESH = 2635
|
|
233
|
+
EXIT = 2636
|
|
234
|
+
EDIT = 2637
|
|
235
|
+
SCROLLUP = 2638
|
|
236
|
+
SCROLLDOWN = 2639
|
|
237
|
+
NEW = 2640
|
|
238
|
+
REDO = 2641
|
|
239
|
+
CLOSE = 2642
|
|
240
|
+
PLAY = 2643
|
|
241
|
+
BASSBOOST = 2644
|
|
242
|
+
PRINT = 2645
|
|
243
|
+
CHAT = 2646
|
|
244
|
+
FINANCE = 2647
|
|
245
|
+
CANCEL = 2648
|
|
246
|
+
KBDILLUM_TOGGLE = 2649
|
|
247
|
+
KBDILLUM_DOWN = 2650
|
|
248
|
+
KBDILLUM_UP = 2651
|
|
249
|
+
SEND = 2652
|
|
250
|
+
REPLY = 2653
|
|
251
|
+
FORWARDMAIL = 2654
|
|
252
|
+
SAVE = 2655
|
|
253
|
+
DOCUMENTS = 2656
|
|
254
|
+
VIDEO_NEXT = 2657
|
|
255
|
+
VIDEO_PREV = 2658
|
|
256
|
+
BRIGHTNESS_CYCLE = 2659
|
|
257
|
+
BRIGHTNESS_ZERO = 2660
|
|
258
|
+
DISPLAY_OFF = 2661
|
|
259
|
+
BTN_MISC = 2662
|
|
260
|
+
GOTO = 2663
|
|
261
|
+
INFO = 2664
|
|
262
|
+
PROGRAM = 2665
|
|
263
|
+
PVR = 2666
|
|
264
|
+
SUBTITLE = 2667
|
|
265
|
+
FULL_SCREEN = 2668
|
|
266
|
+
KEYBOARD = 2669
|
|
267
|
+
ASPECT_RATIO = 2670
|
|
268
|
+
PC = 2671
|
|
269
|
+
TV = 2672
|
|
270
|
+
TV2 = 2673
|
|
271
|
+
VCR = 2674
|
|
272
|
+
VCR2 = 2675
|
|
273
|
+
SAT = 2676
|
|
274
|
+
CD = 2677
|
|
275
|
+
TAPE = 2678
|
|
276
|
+
TUNER = 2679
|
|
277
|
+
PLAYER = 2680
|
|
278
|
+
DVD = 2681
|
|
279
|
+
AUDIO = 2682
|
|
280
|
+
VIDEO = 2683
|
|
281
|
+
MEMO = 2684
|
|
282
|
+
CALENDAR = 2685
|
|
283
|
+
RED = 2686
|
|
284
|
+
GREEN = 2687
|
|
285
|
+
YELLOW = 2688
|
|
286
|
+
BLUE = 2689
|
|
287
|
+
CHANNELUP = 2690
|
|
288
|
+
CHANNELDOWN = 2691
|
|
289
|
+
LAST = 2692
|
|
290
|
+
RESTART = 2693
|
|
291
|
+
SLOW = 2694
|
|
292
|
+
SHUFFLE = 2695
|
|
293
|
+
VIDEOPHONE = 2696
|
|
294
|
+
GAMES = 2697
|
|
295
|
+
ZOOMIN = 2698
|
|
296
|
+
ZOOMOUT = 2699
|
|
297
|
+
ZOOMRESET = 2700
|
|
298
|
+
WORDPROCESSOR = 2701
|
|
299
|
+
EDITOR = 2702
|
|
300
|
+
SPREADSHEET = 2703
|
|
301
|
+
GRAPHICSEDITOR = 2704
|
|
302
|
+
PRESENTATION = 2705
|
|
303
|
+
DATABASE = 2706
|
|
304
|
+
NEWS = 2707
|
|
305
|
+
VOICEMAIL = 2708
|
|
306
|
+
ADDRESSBOOK = 2709
|
|
307
|
+
MESSENGER = 2710
|
|
308
|
+
BRIGHTNESS_TOGGLE = 2711
|
|
309
|
+
SPELLCHECK = 2712
|
|
310
|
+
COFFEE = 2713
|
|
311
|
+
MEDIA_REPEAT = 2714
|
|
312
|
+
IMAGES = 2715
|
|
313
|
+
BUTTONCONFIG = 2716
|
|
314
|
+
TASKMANAGER = 2717
|
|
315
|
+
JOURNAL = 2718
|
|
316
|
+
CONTROLPANEL = 2719
|
|
317
|
+
APPSELECT = 2720
|
|
318
|
+
SCREENSAVER = 2721
|
|
319
|
+
ASSISTANT = 2722
|
|
320
|
+
KBD_LAYOUT_NEXT = 2723
|
|
321
|
+
BRIGHTNESS_MIN = 2724
|
|
322
|
+
BRIGHTNESS_MAX = 2725
|
|
323
|
+
KBDINPUTASSIST_PREV = 2726
|
|
324
|
+
KBDINPUTASSIST_NEXT = 2727
|
|
325
|
+
KBDINPUTASSIST_PREVGROUP = 2728
|
|
326
|
+
KBDINPUTASSIST_NEXTGROUP = 2729
|
|
327
|
+
KBDINPUTASSIST_ACCEPT = 2730
|
|
328
|
+
KBDINPUTASSIST_CANCEL = 2731
|
|
329
|
+
|
|
330
|
+
# 其他系统键
|
|
331
|
+
FRONT = 2800
|
|
332
|
+
SETUP = 2801
|
|
333
|
+
SENDFILE = 2803
|
|
334
|
+
DELETEFILE = 2804
|
|
335
|
+
XFER = 2805
|
|
336
|
+
PROG1 = 2806
|
|
337
|
+
PROG2 = 2807
|
|
338
|
+
MSDOS = 2808
|
|
339
|
+
DIRECTION_ROTATE_DISPLAY = 2810
|
|
340
|
+
CYCLEWINDOWS = 2811
|
|
341
|
+
COMPUTER = 2812
|
|
342
|
+
EJECTCLOSECD = 2813
|
|
343
|
+
ISO = 2814
|
|
344
|
+
MOVE = 2815
|
|
345
|
+
PROG3 = 2828
|
|
346
|
+
PROG4 = 2829
|
|
347
|
+
DASHBOARD = 2830
|
|
348
|
+
SUSPEND = 2831
|
|
349
|
+
HP = 2832
|
|
350
|
+
SOUND = 2833
|
|
351
|
+
QUESTION = 2834
|
|
352
|
+
CONNECT = 2836
|
|
353
|
+
SPORT = 2837
|
|
354
|
+
SHOP = 2838
|
|
355
|
+
ALTERASE = 2839
|
|
356
|
+
SWITCHVIDEOMODE = 2841
|
|
357
|
+
BATTERY = 2842
|
|
358
|
+
BLUETOOTH = 2843
|
|
359
|
+
WLAN = 2844
|
|
360
|
+
UWB = 2845
|
|
361
|
+
WWAN_WIMAX = 2846
|
|
362
|
+
RFKILL = 2847
|
|
363
|
+
|
|
364
|
+
# 频道与游戏手柄按键
|
|
365
|
+
CHANNEL = 3001
|
|
366
|
+
BTN_0 = 3100
|
|
367
|
+
BTN_1 = 3101
|
|
368
|
+
BTN_2 = 3102
|
|
369
|
+
BTN_3 = 3103
|
|
370
|
+
BTN_4 = 3104
|
|
371
|
+
BTN_5 = 3105
|
|
372
|
+
BTN_6 = 3106
|
|
373
|
+
BTN_7 = 3107
|
|
374
|
+
BTN_8 = 3108
|
|
375
|
+
BTN_9 = 3109
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""MatchPattern:匹配模式枚举。"""
|
|
4
|
+
from enum import IntEnum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MatchPattern(IntEnum):
|
|
8
|
+
"""匹配模式,用于控件文本/属性的匹配方式。"""
|
|
9
|
+
|
|
10
|
+
EQUALS = 0 # 精确匹配(默认)
|
|
11
|
+
CONTAINS = 1 # 包含
|
|
12
|
+
STARTS_WITH = 2 # 开头匹配
|
|
13
|
+
ENDS_WITH = 3 # 结尾匹配
|
|
14
|
+
REGEXP = 4 # 正则匹配
|
|
15
|
+
REGEXP_ICASE = 5 # 正则匹配(忽略大小写)
|
devhelmkit/model/page.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""页面信息类型。"""
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class BasicPage:
|
|
10
|
+
"""页面信息。"""
|
|
11
|
+
screenshot_path: Optional[str] = None
|
|
12
|
+
layout_path: Optional[str] = None
|
|
13
|
+
display_id: int = 0
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""UI 操作参数类型:WindowFilter / UiParam / DeviceType / InputTextMode。"""
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from enum import IntEnum
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class InputTextMode(IntEnum):
|
|
10
|
+
"""输入文本模式。"""
|
|
11
|
+
DEFAULT = 0
|
|
12
|
+
CLEAR_FIRST = 1
|
|
13
|
+
APPEND = 2
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DeviceType(IntEnum):
|
|
17
|
+
"""设备类型。"""
|
|
18
|
+
PHONE = 0
|
|
19
|
+
TABLET = 1
|
|
20
|
+
TV = 2
|
|
21
|
+
WATCH = 3
|
|
22
|
+
CAR = 4
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class WindowFilter:
|
|
27
|
+
"""窗口过滤条件。"""
|
|
28
|
+
bundle: Optional[str] = None
|
|
29
|
+
title: Optional[str] = None
|
|
30
|
+
display_id: Optional[int] = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class UiParam:
|
|
34
|
+
"""UI 操作控制相关常量(类常量风格)。"""
|
|
35
|
+
|
|
36
|
+
NORMAL = "normal"
|
|
37
|
+
LONG = "long"
|
|
38
|
+
DOUBLE = "double"
|
|
39
|
+
LEFT = "LEFT"
|
|
40
|
+
RIGHT = "RIGHT"
|
|
41
|
+
UP = "UP"
|
|
42
|
+
DOWN = "DOWN"
|
devhelmkit/model/rect.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Rect 与 Point:坐标矩形与坐标点。"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Tuple
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class Point:
|
|
12
|
+
"""坐标点。"""
|
|
13
|
+
x: int
|
|
14
|
+
y: int
|
|
15
|
+
|
|
16
|
+
def as_tuple(self) -> Tuple[int, int]:
|
|
17
|
+
return (self.x, self.y)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class Rect:
|
|
22
|
+
"""矩形坐标。"""
|
|
23
|
+
|
|
24
|
+
left: int
|
|
25
|
+
top: int
|
|
26
|
+
right: int
|
|
27
|
+
bottom: int
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def width(self) -> int:
|
|
31
|
+
return self.right - self.left
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def height(self) -> int:
|
|
35
|
+
return self.bottom - self.top
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def center(self) -> Point:
|
|
39
|
+
return Point(
|
|
40
|
+
x=(self.left + self.right) // 2,
|
|
41
|
+
y=(self.top + self.bottom) // 2
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def top_left(self) -> Point:
|
|
46
|
+
return Point(x=self.left, y=self.top)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def bottom_right(self) -> Point:
|
|
50
|
+
return Point(x=self.right, y=self.bottom)
|
|
51
|
+
|
|
52
|
+
def contains(self, point: Point) -> bool:
|
|
53
|
+
"""判断点是否在矩形内。"""
|
|
54
|
+
return (self.left <= point.x <= self.right and
|
|
55
|
+
self.top <= point.y <= self.bottom)
|
|
56
|
+
|
|
57
|
+
def as_tuple(self) -> Tuple[int, int, int, int]:
|
|
58
|
+
return (self.left, self.top, self.right, self.bottom)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Runnable:可执行任务封装。"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Runnable:
|
|
7
|
+
"""延迟执行任务封装(函数 + 参数)。"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, func, args, kwargs):
|
|
10
|
+
self.func = func
|
|
11
|
+
self.args = args
|
|
12
|
+
self.kwargs = kwargs
|
|
13
|
+
|
|
14
|
+
def run(self):
|
|
15
|
+
self.func(*self.args, **self.kwargs)
|
|
16
|
+
|
|
17
|
+
def __str__(self):
|
|
18
|
+
return "%s%s-%s" % (self.func.__name__, self.args, self.kwargs)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""轻量日志:Error / Warn / Info / Debug / Trace。
|
|
4
|
+
|
|
5
|
+
仅控制台输出,无轮转、无脱敏。RPC 运行时默认不使用通用重试,
|
|
6
|
+
避免点击、输入等有副作用操作被重复执行。
|
|
7
|
+
"""
|
|
8
|
+
import logging
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
_LOGGER_NAME = "devhelmkit"
|
|
12
|
+
_logger = logging.getLogger(_LOGGER_NAME)
|
|
13
|
+
_logger.addHandler(logging.NullHandler())
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class _LogLevel:
|
|
17
|
+
ERROR = logging.ERROR
|
|
18
|
+
WARN = logging.WARNING
|
|
19
|
+
INFO = logging.INFO
|
|
20
|
+
DEBUG = logging.DEBUG
|
|
21
|
+
TRACE = 5
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
logging.addLevelName(_LogLevel.TRACE, "TRACE")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _trace(self, message, *args, **kwargs):
|
|
28
|
+
if self.isEnabledFor(_LogLevel.TRACE):
|
|
29
|
+
self._log(_LogLevel.TRACE, message, args, **kwargs)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
logging.Logger.trace = _trace # type: ignore[attr-defined]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def setup_logger(level: int = logging.INFO) -> logging.Logger:
|
|
36
|
+
"""配置并返回 devhelmkit logger,附加控制台 handler。"""
|
|
37
|
+
_logger.setLevel(level)
|
|
38
|
+
if not any(isinstance(h, logging.StreamHandler) and h.stream is sys.stderr
|
|
39
|
+
for h in _logger.handlers):
|
|
40
|
+
handler = logging.StreamHandler(sys.stderr)
|
|
41
|
+
handler.setFormatter(
|
|
42
|
+
logging.Formatter("[%(asctime)s][%(levelname)s][devhelmkit] %(message)s",
|
|
43
|
+
datefmt="%H:%M:%S")
|
|
44
|
+
)
|
|
45
|
+
_logger.addHandler(handler)
|
|
46
|
+
return _logger
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_logger() -> logging.Logger:
|
|
50
|
+
"""获取 devhelmkit logger。"""
|
|
51
|
+
return _logger
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def error(msg, *args, **kwargs):
|
|
55
|
+
_logger.error(msg, *args, **kwargs)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def warn(msg, *args, **kwargs):
|
|
59
|
+
_logger.warning(msg, *args, **kwargs)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def info(msg, *args, **kwargs):
|
|
63
|
+
_logger.info(msg, *args, **kwargs)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def debug(msg, *args, **kwargs):
|
|
67
|
+
_logger.debug(msg, *args, **kwargs)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def trace(msg, *args, **kwargs):
|
|
71
|
+
if _logger.isEnabledFor(_LogLevel.TRACE):
|
|
72
|
+
_logger._log(_LogLevel.TRACE, msg, args, **kwargs)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""可控重试工具:仅用于连接阶段与无副作用流程。
|
|
4
|
+
|
|
5
|
+
RPC 运行时(控件查找、点击、输入等)默认不重试,避免副作用操作被重复执行。
|
|
6
|
+
"""
|
|
7
|
+
import time
|
|
8
|
+
from typing import Callable, Optional, Tuple, Type
|
|
9
|
+
|
|
10
|
+
from devhelmkit.utils.logger import get_logger
|
|
11
|
+
|
|
12
|
+
_logger = get_logger()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def retry(func: Callable, retries: int = 3, delay: float = 1.0,
|
|
16
|
+
backoff: float = 2.0,
|
|
17
|
+
exceptions: Tuple[Type[BaseException], ...] = (Exception,),
|
|
18
|
+
sleep: Optional[Callable[[float], None]] = None) -> object:
|
|
19
|
+
"""指数退避重试。
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
func: 待重试的可调用对象。
|
|
23
|
+
retries: 最大重试次数(不含首次)。
|
|
24
|
+
delay: 首次失败后等待秒数。
|
|
25
|
+
backoff: 退避倍率,每次等待 = delay * backoff ** attempt。
|
|
26
|
+
exceptions: 触发重试的异常类型。
|
|
27
|
+
sleep: 自定义 sleep 函数,便于测试注入。
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
func 的返回值。
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
最后一次失败的异常。
|
|
34
|
+
"""
|
|
35
|
+
_sleep = sleep or time.sleep
|
|
36
|
+
attempt = 0
|
|
37
|
+
while True:
|
|
38
|
+
try:
|
|
39
|
+
return func()
|
|
40
|
+
except exceptions as exc:
|
|
41
|
+
attempt += 1
|
|
42
|
+
if attempt > retries:
|
|
43
|
+
raise
|
|
44
|
+
wait = delay * (backoff ** (attempt - 1))
|
|
45
|
+
_logger.debug("第 %d 次重试,等待 %.2fs:%s", attempt, wait, exc)
|
|
46
|
+
_sleep(wait)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# !/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""超时与状态轮询工具。"""
|
|
4
|
+
import time
|
|
5
|
+
from typing import Callable, Optional, Tuple, Type
|
|
6
|
+
|
|
7
|
+
from devhelmkit.exceptions import DevhelmTimeoutError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def wait_for(predicate: Callable[[], bool], timeout: float = 10.0,
|
|
11
|
+
interval: float = 0.5,
|
|
12
|
+
sleep: Optional[Callable[[float], None]] = None) -> bool:
|
|
13
|
+
"""轮询等待条件成立。
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
predicate: 返回 bool 的可调用对象,True 表示条件满足。
|
|
17
|
+
timeout: 总超时秒数。
|
|
18
|
+
interval: 轮询间隔秒数。
|
|
19
|
+
sleep: 自定义 sleep 函数,便于测试注入。
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
True 若在超时内条件成立,否则 False。
|
|
23
|
+
"""
|
|
24
|
+
_sleep = sleep or time.sleep
|
|
25
|
+
deadline = time.monotonic() + timeout
|
|
26
|
+
while True:
|
|
27
|
+
if predicate():
|
|
28
|
+
return True
|
|
29
|
+
if time.monotonic() >= deadline:
|
|
30
|
+
return False
|
|
31
|
+
_sleep(min(interval, max(0.0, deadline - time.monotonic())))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def wait_for_raise(predicate: Callable[[], bool], timeout: float = 10.0,
|
|
35
|
+
interval: float = 0.5,
|
|
36
|
+
exceptions: Tuple[Type[BaseException], ...] = (Exception,),
|
|
37
|
+
sleep: Optional[Callable[[float], None]] = None) -> bool:
|
|
38
|
+
"""轮询等待条件成立,predicate 抛异常时视为未满足继续轮询。
|
|
39
|
+
|
|
40
|
+
超时后返回 False 而非抛异常,调用方可自行决定是否抛 DevhelmTimeoutError。
|
|
41
|
+
"""
|
|
42
|
+
_sleep = sleep or time.sleep
|
|
43
|
+
deadline = time.monotonic() + timeout
|
|
44
|
+
while True:
|
|
45
|
+
try:
|
|
46
|
+
if predicate():
|
|
47
|
+
return True
|
|
48
|
+
except exceptions:
|
|
49
|
+
pass
|
|
50
|
+
if time.monotonic() >= deadline:
|
|
51
|
+
return False
|
|
52
|
+
_sleep(min(interval, max(0.0, deadline - time.monotonic())))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def ensure_timeout(timeout: Optional[float], default: float) -> float:
|
|
56
|
+
"""规范化超时:None 取默认值,负数视为 0。"""
|
|
57
|
+
if timeout is None:
|
|
58
|
+
return default
|
|
59
|
+
return max(0.0, float(timeout))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def raise_on_timeout(timeout: float, condition_desc: str) -> None:
|
|
63
|
+
"""显式抛 DevhelmTimeoutError。"""
|
|
64
|
+
raise DevhelmTimeoutError("等待超时(%.2fs):%s" % (timeout, condition_desc))
|