taotoolkit 1.0.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.
@@ -0,0 +1,435 @@
1
+ import os
2
+ import re
3
+ import subprocess
4
+ import sys
5
+ import time
6
+ from functools import wraps
7
+ from datetime import datetime
8
+ from typing import Callable, Dict, List, Optional, Any
9
+ from colorama import Back, Fore, Style, init
10
+
11
+ init(autoreset=True)
12
+
13
+ _DEBUG_MODE = False
14
+
15
+
16
+ def debugCtrl(debug: int) -> None:
17
+ global _DEBUG_MODE
18
+ _DEBUG_MODE = debug == 1
19
+
20
+ level_colors = {
21
+ "DEBUG": Fore.WHITE,
22
+ "INFO": Fore.GREEN,
23
+ "HIGH": Fore.MAGENTA,
24
+ "WARN": Fore.YELLOW,
25
+ "ERROR": Fore.RED,
26
+ }
27
+
28
+ def logDecorator(level="INFO", callStack=1):
29
+ def decorator(func):
30
+ @wraps(func)
31
+ def wrapper(*args, **kwargs):
32
+ try:
33
+ frame = sys._getframe(callStack)
34
+ fileName = os.path.basename(frame.f_code.co_filename)
35
+ funcName = frame.f_code.co_name
36
+ lineNum = frame.f_lineno
37
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
38
+
39
+ result = func(*args, **kwargs)
40
+ if level == "DEBUG" and _DEBUG_MODE != 1:
41
+ return result
42
+ color = level_colors.get(level, Fore.WHITE)
43
+ message = f"{timestamp} {color}{Back.RESET}{Style.NORMAL}{level.ljust(5)} [{fileName}:{lineNum} {funcName}] "
44
+ args_str = " ".join(map(str, args))
45
+ kwargs_str = " ".join(f"{k}={v}" for k, v in kwargs.items())
46
+ all_args = f"{args_str} {kwargs_str}".strip()
47
+
48
+ print(f"{message}: {all_args}")
49
+ return result
50
+ except Exception as e:
51
+ print(f"Error in logDecorator: {e}")
52
+ return None
53
+
54
+ return wrapper
55
+
56
+ return decorator
57
+
58
+
59
+ @logDecorator(level="DEBUG")
60
+ def logd(*args):
61
+ pass
62
+
63
+
64
+ @logDecorator(level="INFO")
65
+ def logi(*args):
66
+ pass
67
+
68
+
69
+ @logDecorator(level="HIGH")
70
+ def logh(*args):
71
+ pass
72
+
73
+
74
+ @logDecorator(level="WARN")
75
+ def logw(*args):
76
+ pass
77
+
78
+
79
+ @logDecorator(level="ERROR")
80
+ def loge(*args):
81
+ pass
82
+
83
+
84
+ def _create_log_call_func(level, default_callStack=2):
85
+ """Factory function to create log functions with customizable callStack."""
86
+ def log_func(*args, callStack=None):
87
+ if callStack is None:
88
+ callStack = default_callStack
89
+
90
+ try:
91
+ frame = sys._getframe(callStack)
92
+ fileName = os.path.basename(frame.f_code.co_filename)
93
+ funcName = frame.f_code.co_name
94
+ lineNum = frame.f_lineno
95
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
96
+
97
+ if level == "DEBUG" and _DEBUG_MODE != 1:
98
+ return None
99
+
100
+ color = level_colors.get(level, Fore.WHITE)
101
+ message = f"{timestamp} {color}{Back.RESET}{Style.NORMAL}{level.ljust(5)} [{fileName}:{lineNum} {funcName}] "
102
+ args_str = " ".join(map(str, args))
103
+
104
+ print(f"{message}: {args_str}")
105
+ return None
106
+ except Exception as e:
107
+ print(f"Error in log call: {e}")
108
+ return None
109
+
110
+ return log_func
111
+
112
+
113
+ logCallDebug = _create_log_call_func("DEBUG", default_callStack=2)
114
+ logCallInfo = _create_log_call_func("INFO", default_callStack=2)
115
+ logCallWarn = _create_log_call_func("WARN", default_callStack=2)
116
+ logCallHigh = _create_log_call_func("HIGH", default_callStack=2)
117
+ logCallErr = _create_log_call_func("ERROR", default_callStack=2)
118
+
119
+
120
+ def exit() -> None:
121
+ sys.exit(1)
122
+
123
+
124
+ def eExit(msg: str) -> None:
125
+ loge(msg)
126
+ sys.exit(1)
127
+
128
+
129
+ def iExit(msg: str) -> None:
130
+ logi(msg)
131
+ sys.exit(0)
132
+
133
+
134
+ def sleep(seconds: float) -> None:
135
+ time.sleep(seconds)
136
+
137
+
138
+ sysVersion = sys.platform
139
+
140
+
141
+ def createFolder(path: str) -> None:
142
+ os.makedirs(path, exist_ok=True)
143
+
144
+
145
+ def fileExist(path: str) -> bool:
146
+ return os.path.exists(path)
147
+
148
+
149
+ def findFilesBySuffixKeyword(path: str, suffix: str, keyword: str) -> List[str]:
150
+ result = []
151
+ for root, _dirs, files in os.walk(path):
152
+ for f in files:
153
+ if f.endswith(suffix) and keyword in f:
154
+ result.append(os.path.join(root, f))
155
+ return result
156
+
157
+
158
+ def findFilesWithSuffix(path: str, suffix: str) -> List[str]:
159
+ result = []
160
+ for root, _dirs, files in os.walk(path):
161
+ for f in files:
162
+ if f.endswith(suffix):
163
+ result.append(os.path.join(root, f))
164
+ return result
165
+
166
+
167
+ def get_file_index(prefix: str, suffix: str, filename: str) -> int:
168
+ pattern = re.compile(rf"{prefix}(\d+){suffix}")
169
+ res = pattern.findall(filename)
170
+ if len(res) != 1:
171
+ raise Exception("Cannot get file index!")
172
+ return int(res[0])
173
+
174
+
175
+ def is_number(s: str) -> bool:
176
+ try:
177
+ float(s)
178
+ return True
179
+ except ValueError:
180
+ return False
181
+
182
+
183
+ def run_as_admin() -> bool:
184
+ try:
185
+ import ctypes
186
+
187
+ return ctypes.windll.shell32.IsUserAnAdmin()
188
+ except Exception:
189
+ return False
190
+
191
+
192
+ def removeAnyContainStr(string: str, subStringList: list, matchCase=True) -> List[str]:
193
+ if matchCase:
194
+ return [s for s in subStringList if string not in s]
195
+ return [s for s in subStringList if string.lower() not in s.lower()]
196
+
197
+
198
+ def renameFile(old_path: str, new_path: str) -> None:
199
+ os.rename(old_path, new_path)
200
+
201
+
202
+ class ErrCode:
203
+ SUCCESS = 0
204
+ ERROR = -1
205
+ FILE_NOT_FOUND = -2
206
+ FILE_ILLEGAL = -3
207
+
208
+
209
+ def fileExceptionNotFound(path: str) -> Exception:
210
+ return FileNotFoundError(f"File not found: {path}")
211
+
212
+
213
+ def fileExceptionillegal(path: str) -> Exception:
214
+ return ValueError(f"Illegal file: {path}")
215
+
216
+
217
+ def normalize_args(args: List[str]) -> List[str]:
218
+ if not args:
219
+ return []
220
+ first = args[0]
221
+ if first.endswith(".py") or first.endswith(".exe") or first in {"tao", "python", "python3"}:
222
+ return args[1:]
223
+ if os.path.basename(first) in {"tao", "tao.exe"}:
224
+ return args[1:]
225
+ return list(args)
226
+
227
+
228
+ def register_command(*names: str, registry: Optional[Dict[str, Callable]] = None) -> Callable:
229
+ def decorator(func: Callable) -> Callable:
230
+ if registry is not None:
231
+ for name in names:
232
+ registry[name] = func
233
+ return func
234
+
235
+ return decorator
236
+
237
+
238
+ def inputSerial(start: int, end: int) -> int:
239
+ while True:
240
+ try:
241
+ idx = int(input(f"请输入序号 ({start}-{end}): "))
242
+ if start <= idx <= end:
243
+ return idx
244
+ loge(f"输入超出范围,请输入 {start}-{end} 之间的数字")
245
+ except ValueError:
246
+ loge("请输入有效的数字")
247
+
248
+
249
+ def refreshWait(_keyword: str, timeout: int, interval: float, func: Callable, *args) -> bool:
250
+ start = time.time()
251
+ while time.time() - start < timeout:
252
+ if func(*args):
253
+ return True
254
+ sleep(interval)
255
+ return False
256
+
257
+
258
+ def checkMsg(msg: str, *keywords: str) -> None:
259
+ if msg:
260
+ for kw in keywords:
261
+ if kw in msg.lower():
262
+ eExit(msg)
263
+
264
+
265
+ def parseArgs(argsList: List[str], prog: str, description: str = "") -> Any:
266
+ import argparse
267
+
268
+ parser = argparse.ArgumentParser(prog=prog, description=description)
269
+ return parser.parse_args(argsList)
270
+
271
+
272
+ def parseDeviceInfo(info: str) -> Dict[str, str]:
273
+ result = {}
274
+ lines = info.strip().split("\n")
275
+ for line in lines:
276
+ if "device" in line:
277
+ parts = line.split()
278
+ if len(parts) >= 2:
279
+ result["serial"] = parts[0]
280
+ result["model"] = parts[1]
281
+ return result
282
+
283
+
284
+ def pCmd(
285
+ cmd: str,
286
+ sleep_s=1.0,
287
+ showCmd=False,
288
+ shell=False,
289
+ splitCmd=True,
290
+ encoding="utf-8",
291
+ waitDone=True,
292
+ timeOut=3,
293
+ showRet=False,
294
+ checkErr=False,
295
+ ignoreTimeOut=False,
296
+ logLevel="debug",
297
+ ):
298
+ if showCmd:
299
+ if logLevel == "warn":
300
+ logCallWarn(cmd)
301
+ elif logLevel == "error":
302
+ logCallErr(cmd)
303
+ elif logLevel == "info":
304
+ logCallInfo(cmd)
305
+ else:
306
+ logCallDebug(cmd)
307
+ try:
308
+ if splitCmd:
309
+ proc = subprocess.Popen(
310
+ cmd.split(" "),
311
+ stdin=subprocess.PIPE,
312
+ stdout=subprocess.PIPE,
313
+ stderr=subprocess.PIPE,
314
+ encoding=encoding,
315
+ shell=shell,
316
+ # env=os.environ.copy(),
317
+ )
318
+ else:
319
+ proc = subprocess.Popen(
320
+ cmd,
321
+ stdin=subprocess.PIPE,
322
+ stdout=subprocess.PIPE,
323
+ stderr=subprocess.PIPE,
324
+ encoding=encoding,
325
+ shell=shell,
326
+ # env=os.environ.copy(),
327
+ )
328
+ except subprocess.TimeoutExpired:
329
+ return "", f"Command '{cmd}' timed out after {timeOut} seconds"
330
+ except subprocess.CalledProcessError as e:
331
+ return "", f"Command '{cmd}' failed with error: {e.stderr}"
332
+ out = ""
333
+ error = ""
334
+ if waitDone:
335
+ try:
336
+ out, error = proc.communicate(timeout=timeOut)
337
+ except subprocess.TimeoutExpired:
338
+ logCallErr(f"{cmd} timeout", "error")
339
+ if not ignoreTimeOut:
340
+ exit()
341
+ else:
342
+ return "None", "None"
343
+
344
+ sleep(sleep_s)
345
+ if checkErr:
346
+ checkMsg(error, "error")
347
+ checkMsg(out, "failed")
348
+ checkMsg(out, "error")
349
+ if showRet:
350
+ if out != "":
351
+ logCallInfo(re.sub(r"\n$", "", out))
352
+ if error != "" and ("error" in error or "failed" in error):
353
+ logCallErr(error)
354
+ elif error != "":
355
+ logCallInfo(error)
356
+ return out, error
357
+ else:
358
+ return "None", "None"
359
+
360
+
361
+ def rCmd(
362
+ cmd: str,
363
+ sleep_s=1.0,
364
+ showCmd=False,
365
+ shell=False,
366
+ splitCmd=True,
367
+ encoding="utf-8",
368
+ timeOut=3,
369
+ showRet=False,
370
+ checkErr=False,
371
+ logLevel="debug",
372
+ ):
373
+ if showCmd:
374
+ if logLevel == "warn":
375
+ logCallWarn(cmd,callStack=3)
376
+ elif logLevel == "error":
377
+ logCallErr(cmd,callStack=3)
378
+ elif logLevel == "info":
379
+ logCallInfo(cmd,callStack=3)
380
+ else:
381
+ logCallDebug(cmd,callStack=3)
382
+ try:
383
+ if splitCmd:
384
+ result = subprocess.run(
385
+ cmd.split(" "),
386
+ capture_output=True,
387
+ text=True,
388
+ encoding=encoding,
389
+ shell=shell,
390
+ check=True,
391
+ timeout=timeOut,
392
+ )
393
+ else:
394
+ result = subprocess.run(
395
+ cmd,
396
+ capture_output=True,
397
+ text=True,
398
+ encoding=encoding,
399
+ shell=shell,
400
+ check=True,
401
+ timeout=timeOut,
402
+ )
403
+ except subprocess.TimeoutExpired:
404
+ return "", f"Command '{cmd}' timed out after {timeOut} seconds"
405
+ except subprocess.CalledProcessError as e:
406
+ return "", f"Command '{cmd}' failed with error: {e.stderr}"
407
+
408
+ sleep(sleep_s)
409
+ if checkErr:
410
+ checkMsg(result.stderr, "error")
411
+ checkMsg(result.stderr, "failed")
412
+ checkMsg(result.stdout, "error")
413
+ if showRet:
414
+ if len(result.stdout) != 0:
415
+ logCallInfo(result.stdout.strip())
416
+ if len(result.stderr) != 0:
417
+ if "error" in result.stderr or "failed" in result.stderr:
418
+ logCallErr(result.stderr.strip())
419
+ else:
420
+ logCallInfo(result.stderr.strip())
421
+ return result.stdout, result.stderr
422
+
423
+
424
+ def oCmd(cmd: str, sleep_s=1.0, showCmd=False, logLevel="debug"):
425
+ if showCmd:
426
+ if logLevel == "warn":
427
+ logCallWarn(cmd, callStack=3)
428
+ elif logLevel == "error":
429
+ logCallErr(cmd, callStack=3)
430
+ elif logLevel == "info":
431
+ logCallInfo(cmd, callStack=3)
432
+ else:
433
+ logCallDebug(cmd, callStack=3)
434
+ os.system(cmd)
435
+ sleep(sleep_s)