taotoolkit 2.0.0__tar.gz → 2.0.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taotoolkit
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: Tao ToolKit
5
5
  Author-email: taotaoli <taotaoli@asrmicro.com>
6
6
  License-Expression: MIT
@@ -19,7 +19,7 @@ Requires-Dist: beautifulsoup4>=4.10.0
19
19
  Requires-Dist: pyyaml>=6.0.3
20
20
  Requires-Dist: pywinpty>=3.0.5; platform_system == "Windows"
21
21
  Provides-Extra: uiautomator
22
- Requires-Dist: uiautomator2>=2.0.0; extra == "uiautomator"
22
+ Requires-Dist: uiautomator2>=2.0.2; extra == "uiautomator"
23
23
 
24
24
  # TAO - Toolkit
25
25
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "taotoolkit"
7
- version = "2.0.0"
7
+ version = "2.0.2"
8
8
  description = "Tao ToolKit"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -29,5 +29,5 @@ dependencies = [
29
29
 
30
30
  [project.optional-dependencies]
31
31
  uiautomator = [
32
- "uiautomator2>=2.0.0",
32
+ "uiautomator2>=2.0.2",
33
33
  ]
@@ -25,6 +25,10 @@ from .tao_common import (
25
25
  sysVersion,
26
26
  sleep,
27
27
  parseArgs,
28
+ renameFile,
29
+ findFilesBySuffixKeyword,
30
+ findFilesWithSuffix,
31
+ removeAnyContainStr,
28
32
  )
29
33
 
30
34
  # 导入各模块
@@ -39,7 +43,7 @@ from .tao_camDvt import camDvtMain as camDvtMain, printHelp as camDvtHelp, CamDv
39
43
 
40
44
  from .asrVrf import Vrf
41
45
 
42
- __version__ = "2.0.0"
46
+ __version__ = "2.0.2"
43
47
 
44
48
  __all__ = [
45
49
  "debugCtrl",
@@ -63,6 +67,9 @@ __all__ = [
63
67
  "createFolder",
64
68
  "fileExist",
65
69
  "findFilesBySuffixKeyword",
70
+ "findFilesWithSuffix",
71
+ "removeAnyContainStr",
72
+ "renameFile",
66
73
  "normalize_args",
67
74
  "register_command",
68
75
  "sysVersion",
@@ -1034,27 +1034,67 @@ class DevOp:
1034
1034
  sleep(interval)
1035
1035
  return False
1036
1036
 
1037
+ def getRefJpgSize(self, path: str, maxCount=5) -> Optional[int]:
1038
+ """取目录内最近几张 jpg 的中位尺寸, 用于识别 offlineSession 先落盘的小图"""
1039
+ out = rCmd(f"adb -s {self.serial} shell ls -lt {path}")[0]
1040
+ sizes = []
1041
+ for line in out.splitlines():
1042
+ parts = line.split()
1043
+ if len(parts) < 5 or not parts[4].isdigit():
1044
+ continue
1045
+ fileName = parts[-1].lower()
1046
+ if fileName.endswith((".jpg", ".jpeg")) and "thumb" not in fileName:
1047
+ sizes.append(int(parts[4]))
1048
+ if len(sizes) >= maxCount:
1049
+ break
1050
+ if not sizes:
1051
+ return None
1052
+ sizes.sort()
1053
+ return sizes[len(sizes) // 2]
1054
+
1037
1055
  def capJPG(self, name="null", wait=10):
1038
1056
  outPath = self.curPath
1039
1057
  logi(f"capture {os.path.join(outPath, name)}.jpg")
1040
1058
  jpgPath = r"/sdcard/DCIM/Camera/"
1041
1059
  oldFileList = self.getSuffixList(jpgPath, "jpg", "jpeg")
1060
+ refSize = self.getRefJpgSize(jpgPath)
1061
+ logd(f"ref jpg size {refSize}")
1042
1062
  cmd = f"adb -s {self.serial} shell input keyevent 27"
1043
1063
  rCmd(cmd, showCmd=True, logLevel="info")
1044
1064
 
1045
1065
  # 轮询替代固定等待: wait 为总超时(秒), 新文件写入稳定后立即返回
1066
+ # offlineSession 会先落一张小图(如 1440x1080)再替换为满尺寸图, 仅判稳定会拉到小图,
1067
+ # 故尺寸明显小于历史照片时跳过, 等大图替换完成; 无历史照片时加长稳定窗口
1068
+ stable_s = 1.0 if refSize else 2.5
1046
1069
  deadline = time.time() + wait
1047
1070
  jpgName = None
1071
+ fallbackName = None
1072
+ fallbackSize = 0
1048
1073
  while time.time() < deadline:
1049
1074
  fileList = [f for f in self.getSuffixList(jpgPath, "jpg", "jpeg") if "~" not in f]
1050
- jpgNameList = list(set(fileList) - set(oldFileList))
1051
- if jpgNameList:
1052
- jpgName = jpgNameList[0]
1053
- if self.waitFileStable(jpgPath + jpgName, timeOut=max(deadline - time.time(), 1.0)):
1075
+ for file in [f for f in fileList if f not in oldFileList]:
1076
+ size = self.getRemoteFileSize(jpgPath + file)
1077
+ if not size:
1078
+ continue
1079
+ if size > fallbackSize:
1080
+ fallbackName = file
1081
+ fallbackSize = size
1082
+ if refSize and size < refSize * 0.5:
1083
+ logd(f"skip intermediate jpg {file} size {size} < ref {refSize}")
1084
+ continue
1085
+ jpgName = file
1086
+ break
1087
+ if jpgName is not None:
1088
+ if self.waitFileStable(jpgPath + jpgName, timeOut=max(deadline - time.time(), 1.0), stable_s=stable_s):
1054
1089
  break
1055
1090
  jpgName = None
1056
1091
  sleep(0.2)
1057
1092
 
1093
+ if jpgName is None and fallbackName is not None:
1094
+ # 超时仍无满尺寸图时退回最大新文件, 避免直接失败
1095
+ logw(f"no full-size jpg before timeout, use largest new file {fallbackName}")
1096
+ if self.waitFileStable(jpgPath + fallbackName, timeOut=1.0, stable_s=0.5):
1097
+ jpgName = fallbackName
1058
1098
  if jpgName is None:
1059
1099
  loge(f"capture {os.path.join(outPath, name)}.jpg failed")
1060
1100
  return False
@@ -1206,20 +1246,25 @@ class DevOp:
1206
1246
 
1207
1247
  def CLI_pushSo(argsList):
1208
1248
  parser = argparse.ArgumentParser(prog="pushso", description="android设备push so文件")
1209
- parser.add_argument("-p", "--path", required=True, nargs="+", help="so文件名或路径,支持多so文件 push")
1249
+ parser.add_argument("posPath", nargs="*", default=None, help="so文件名或路径, 可直接输入(pushso xxx.so)")
1250
+ parser.add_argument("-p", "--path", required=False, nargs="+", default=None, help="so文件名或路径,支持多so文件 push")
1210
1251
  parser.add_argument("-s", "--serial", type=str, default="", help="设备SN号(多设备需指定)")
1211
1252
  args = parser.parse_args(argsList)
1212
1253
 
1254
+ paths = list(args.path or []) + list(args.posPath or [])
1255
+ if not paths:
1256
+ parser.error("至少需要指定一个so文件或路径")
1257
+
1213
1258
  dev = DevOp(args.serial)
1214
1259
  so = []
1215
- if len(args.path) == 1:
1216
- if os.path.isdir(args.path[0]):
1217
- so = findFilesBySuffixKeyword(args.path[0], ".so", "")
1260
+ if len(paths) == 1:
1261
+ if os.path.isdir(paths[0]):
1262
+ so = findFilesBySuffixKeyword(paths[0], ".so", "")
1218
1263
  dev.pushso(so)
1219
1264
  else:
1220
- dev.pushso(args.path)
1265
+ dev.pushso(paths)
1221
1266
  else:
1222
- dev.pushso(args.path)
1267
+ dev.pushso(paths)
1223
1268
 
1224
1269
 
1225
1270
  def CLI_scrcpy(argsList):
@@ -1295,6 +1340,7 @@ def CLI_screenCap(argsList):
1295
1340
 
1296
1341
  # 默认:主屏或指定 display_id
1297
1342
  dev.adbScreenCap(args.file, display_id=args.display, hdr=args.hdr)
1343
+ logi(f"screen capture {args.file}.png")
1298
1344
 
1299
1345
 
1300
1346
  def CLI_screenRec(argsList):
@@ -1387,12 +1433,15 @@ def CLI_kcam(args):
1387
1433
 
1388
1434
  def _capJpg(argsList):
1389
1435
  parser = argparse.ArgumentParser(prog="capjpg", description="拍摄jpg并导出到PC指定文件名")
1390
- parser.add_argument("-f", "--file", type=str, default="null", help="jpg名称")
1436
+ parser.add_argument("posFile", nargs="?", default=None, help="jpg名称,无需后缀, 可直接输入(capjpg test)")
1437
+ parser.add_argument("-f", "--file", type=str, default="null", help="jpg名称,无需后缀")
1391
1438
  parser.add_argument("-s", "--serial", type=str, default="", help="设备SN号")
1392
1439
  parser.add_argument("-w", "--wait", type=int, default=10, help="拍照后等待新照片写入完成的超时时间,单位秒,default 10s")
1393
1440
  parser.add_argument("-d", "--devname", type=str, default=None, help="jpg名称后缀标签")
1394
1441
  parser.add_argument("--reset", action="store_true", help="清除缓存,重新扫描设备")
1395
1442
  args = parser.parse_args(argsList)
1443
+ if args.file == "null" and args.posFile is not None:
1444
+ args.file = args.posFile
1396
1445
  if args.reset and os.path.exists(CACHE_FILE):
1397
1446
  os.remove(CACHE_FILE)
1398
1447
  logi("[cache] 缓存已清除")
@@ -748,9 +748,11 @@ class jenkinsTool:
748
748
  else:
749
749
  cmd = f"{self.aimgTool} download -t {finalCfg}"
750
750
  if sysVersion == "linux":
751
- oCmd(cmd, sleep_s=1.0, showCmd=True, logLevel="info")
751
+ oCmd(cmd, sleep_s=1.0, showCmd=False, logLevel="info")
752
752
  else:
753
- rCmdRealtime(cmd, showCmd=True, logLevel="info")
753
+ rCmdRealtime(cmd, showCmd=False, logLevel="info")
754
+
755
+ logh(cmd)
754
756
 
755
757
  def joinBackslash(self, *args):
756
758
  # 将字符串用/拼接起来,最后一个不加
@@ -776,7 +778,7 @@ class jenkinsTool:
776
778
  buildNumber, targetUrl = self.findTargetBuild(buildNumber, self.ciOwner, ciTag, buildBoard)
777
779
  buildBoard = targetUrl.split("/")[-2]
778
780
 
779
- logi(f"download {buildNumber} {targetUrl}")
781
+ logh(f"download {buildNumber} {targetUrl}")
780
782
 
781
783
  packageName = buildTag + buildNumber + "android" + adVersion + "_" + buildBoard
782
784
  imgName = os.path.join(self.downloadPath, packageName + ".zip")
@@ -717,9 +717,9 @@ class asrCamOp(DevOp):
717
717
  woke = False
718
718
  while True:
719
719
  if not self.uiClick(textList, slp=0):
720
- # 相机控制面板会自动隐藏, 轻点预览区中心(参考分辨率)唤出后再试
720
+ # 相机控制面板会自动隐藏, 轻点预览区中心唤出后再试(参考分辨率坐标, adbTap 内部按实际分辨率换算)
721
721
  if not woke:
722
- self.adbTap((360, 800), 0)
722
+ self.adbTap((self.refScreenW // 2, self.refScreenH // 2), 0)
723
723
  woke = True
724
724
  if time.time() >= deadline:
725
725
  loge(f"switch to {'video' if video else 'preview'} mode timeout")
@@ -1194,8 +1194,13 @@ class asrCamOp(DevOp):
1194
1194
 
1195
1195
  def CLI_tuningRemoveInfo(argsList):
1196
1196
  parser = argparse.ArgumentParser(prog="tuningRemoveInfo", description="移除tuning参数fw_info")
1197
- parser.add_argument("-p", "--path", required=True, help="tuning文件名或路径")
1197
+ parser.add_argument("posPath", nargs="?", default=None, help="tuning文件名或路径, 可直接输入(tuningr xxx.data)")
1198
+ parser.add_argument("-p", "--path", required=False, default=None, help="tuning文件名或路径")
1198
1199
  args = parser.parse_args(argsList)
1200
+ if args.path is None:
1201
+ args.path = args.posPath
1202
+ if args.path is None:
1203
+ parser.error("至少需要指定tuning文件名或路径")
1199
1204
  inFile = args.path
1200
1205
  if os.path.isfile(inFile):
1201
1206
  _fileProcessTuningRemoveInfo(inFile)
@@ -1223,7 +1228,8 @@ def CLI_tuningRemoveInfo(argsList):
1223
1228
 
1224
1229
  def CLI_pushVrf(argsList):
1225
1230
  parser = argparse.ArgumentParser(prog="pushvrf", description="push vrf到设备")
1226
- parser.add_argument("-p", "--path", required=True, help="vrf文件名或路径")
1231
+ parser.add_argument("posPath", nargs="?", default=None, help="vrf文件名或路径, 可直接输入(psvrf xxx.vrf)")
1232
+ parser.add_argument("-p", "--path", required=False, default=None, help="vrf文件名或路径")
1227
1233
  parser.add_argument(
1228
1234
  "-i",
1229
1235
  "--index",
@@ -1239,6 +1245,10 @@ def CLI_pushVrf(argsList):
1239
1245
  parser.add_argument("--matchcase", action="store_true", dest="matchcase", help="是否区分tag大小写")
1240
1246
  parser.set_defaults(matchcase=False)
1241
1247
  args = parser.parse_args(argsList)
1248
+ if args.path is None:
1249
+ args.path = args.posPath
1250
+ if args.path is None:
1251
+ parser.error("至少需要指定vrf文件名或路径")
1242
1252
 
1243
1253
  logi(f"psvrf {args.path} indxe={args.index}, rename={args.rename}, ignoreTag={args.tag}, matchcase={args.matchcase}")
1244
1254
 
@@ -1251,8 +1261,11 @@ def CLI_pushVrf(argsList):
1251
1261
 
1252
1262
  def CLI_capVrf(argsList):
1253
1263
  parser = argparse.ArgumentParser(prog="capvrf", description="抓取vrf")
1254
- parser.add_argument("-f", "--file", type=str, required=False, help="抓取vrf 文件名")
1264
+ parser.add_argument("posFile", nargs="?", default=None, help="抓取vrf 文件名,,无需后缀 可直接输入(capvrf test)")
1265
+ parser.add_argument("-f", "--file", type=str, required=False, help="抓取vrf 文件名,无需后缀")
1255
1266
  args = parser.parse_args(argsList)
1267
+ if args.file is None and args.posFile is not None:
1268
+ args.file = args.posFile
1256
1269
  asrCam = asrCamOp(True)
1257
1270
  asrCam.setRawDump(1)
1258
1271
  ok = False
@@ -1320,8 +1333,13 @@ def CLI_saveTuning(argsList):
1320
1333
 
1321
1334
  def CLI_pushTuning(argsList):
1322
1335
  parser = argparse.ArgumentParser(prog="pushtuning", description="push tuning参数")
1323
- parser.add_argument("-p", "--path", required=True, help="push tuning文件名或路径")
1336
+ parser.add_argument("posPath", nargs="?", default=None, help="push tuning文件名或路径, 可直接输入(pushtuning xxx.data)")
1337
+ parser.add_argument("-p", "--path", required=False, default=None, help="push tuning文件名或路径")
1324
1338
  args = parser.parse_args(argsList)
1339
+ if args.path is None:
1340
+ args.path = args.posPath
1341
+ if args.path is None:
1342
+ parser.error("至少需要指定tuning文件名或路径")
1325
1343
  inFile = args.path
1326
1344
  asrCam = asrCamOp()
1327
1345
  if os.path.isfile(inFile):
@@ -1337,9 +1355,14 @@ def CLI_pushTuning(argsList):
1337
1355
 
1338
1356
  def CLI_tuning2c(argsList):
1339
1357
  parser = argparse.ArgumentParser(prog="tuning2c", description="tuning参数转 .h文件")
1340
- parser.add_argument("-p", "--path", required=True, help="tuning文件名或路径")
1358
+ parser.add_argument("posPath", nargs="?", default=None, help="tuning文件名或路径, 可直接输入(tuning2c xxx.data)")
1359
+ parser.add_argument("-p", "--path", required=False, default=None, help="tuning文件名或路径")
1341
1360
  parser.add_argument("-s", "--prefix", required=False, help="转为头文件替换的前缀")
1342
1361
  args = parser.parse_args(argsList)
1362
+ if args.path is None:
1363
+ args.path = args.posPath
1364
+ if args.path is None:
1365
+ parser.error("至少需要指定tuning文件名或路径")
1343
1366
 
1344
1367
  inFile = args.path
1345
1368
  sensorName = args.prefix
@@ -1373,9 +1396,14 @@ def CLI_tuning2c(argsList):
1373
1396
 
1374
1397
  def CLI_c2tuning(argsList):
1375
1398
  parser = argparse.ArgumentParser(prog="c2tuning", description="将 .h文件转为 tuning文件")
1376
- parser.add_argument("-p", "--path", required=True, help="tuning文件名或路径")
1399
+ parser.add_argument("posPath", nargs="?", default=None, help="tuning文件名或路径, 可直接输入(c2tuning xxx.h)")
1400
+ parser.add_argument("-p", "--path", required=False, default=None, help="tuning文件名或路径")
1377
1401
  parser.add_argument("-s", "--prefix", required=False, help="转为头文件替换的前缀")
1378
1402
  args = parser.parse_args(argsList)
1403
+ if args.path is None:
1404
+ args.path = args.posPath
1405
+ if args.path is None:
1406
+ parser.error("至少需要指定tuning文件名或路径")
1379
1407
 
1380
1408
  sensorName = args.prefix
1381
1409
  inFile = args.path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taotoolkit
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: Tao ToolKit
5
5
  Author-email: taotaoli <taotaoli@asrmicro.com>
6
6
  License-Expression: MIT
@@ -19,7 +19,7 @@ Requires-Dist: beautifulsoup4>=4.10.0
19
19
  Requires-Dist: pyyaml>=6.0.3
20
20
  Requires-Dist: pywinpty>=3.0.5; platform_system == "Windows"
21
21
  Provides-Extra: uiautomator
22
- Requires-Dist: uiautomator2>=2.0.0; extra == "uiautomator"
22
+ Requires-Dist: uiautomator2>=2.0.2; extra == "uiautomator"
23
23
 
24
24
  # TAO - Toolkit
25
25
 
@@ -14,4 +14,4 @@ pyyaml>=6.0.3
14
14
  pywinpty>=3.0.5
15
15
 
16
16
  [uiautomator]
17
- uiautomator2>=2.0.0
17
+ uiautomator2>=2.0.2
File without changes
File without changes