pyxllib 0.0.43__py3-none-any.whl → 0.3.197__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.
Files changed (186) hide show
  1. pyxllib/__init__.py +9 -2
  2. pyxllib/algo/__init__.py +8 -0
  3. pyxllib/algo/disjoint.py +54 -0
  4. pyxllib/algo/geo.py +541 -0
  5. pyxllib/{util/mathlib.py → algo/intervals.py} +172 -36
  6. pyxllib/algo/matcher.py +389 -0
  7. pyxllib/algo/newbie.py +166 -0
  8. pyxllib/algo/pupil.py +629 -0
  9. pyxllib/algo/shapelylib.py +67 -0
  10. pyxllib/algo/specialist.py +241 -0
  11. pyxllib/algo/stat.py +494 -0
  12. pyxllib/algo/treelib.py +149 -0
  13. pyxllib/algo/unitlib.py +66 -0
  14. pyxllib/autogui/__init__.py +5 -0
  15. pyxllib/autogui/activewin.py +246 -0
  16. pyxllib/autogui/all.py +9 -0
  17. pyxllib/autogui/autogui.py +852 -0
  18. pyxllib/autogui/uiautolib.py +362 -0
  19. pyxllib/autogui/virtualkey.py +102 -0
  20. pyxllib/autogui/wechat.py +827 -0
  21. pyxllib/autogui/wechat_msg.py +421 -0
  22. pyxllib/autogui/wxautolib.py +84 -0
  23. pyxllib/cv/__init__.py +1 -11
  24. pyxllib/cv/expert.py +267 -0
  25. pyxllib/cv/{imlib.py → imfile.py} +18 -83
  26. pyxllib/cv/imhash.py +39 -0
  27. pyxllib/cv/pupil.py +9 -0
  28. pyxllib/cv/rgbfmt.py +1525 -0
  29. pyxllib/cv/slidercaptcha.py +137 -0
  30. pyxllib/cv/trackbartools.py +163 -49
  31. pyxllib/cv/xlcvlib.py +1040 -0
  32. pyxllib/cv/xlpillib.py +423 -0
  33. pyxllib/data/__init__.py +0 -0
  34. pyxllib/data/echarts.py +240 -0
  35. pyxllib/data/jsonlib.py +89 -0
  36. pyxllib/{util/oss2_.py → data/oss.py} +11 -9
  37. pyxllib/data/pglib.py +1127 -0
  38. pyxllib/data/sqlite.py +568 -0
  39. pyxllib/{util → data}/sqllib.py +13 -31
  40. pyxllib/ext/JLineViewer.py +505 -0
  41. pyxllib/ext/__init__.py +6 -0
  42. pyxllib/{util → ext}/demolib.py +119 -35
  43. pyxllib/ext/drissionlib.py +277 -0
  44. pyxllib/ext/kq5034lib.py +12 -0
  45. pyxllib/{util/main.py → ext/old.py} +122 -284
  46. pyxllib/ext/qt.py +449 -0
  47. pyxllib/ext/robustprocfile.py +497 -0
  48. pyxllib/ext/seleniumlib.py +76 -0
  49. pyxllib/{util/tklib.py → ext/tk.py} +10 -11
  50. pyxllib/ext/unixlib.py +827 -0
  51. pyxllib/ext/utools.py +351 -0
  52. pyxllib/{util/webhooklib.py → ext/webhook.py} +45 -17
  53. pyxllib/ext/win32lib.py +40 -0
  54. pyxllib/ext/wjxlib.py +88 -0
  55. pyxllib/ext/wpsapi.py +124 -0
  56. pyxllib/ext/xlwork.py +9 -0
  57. pyxllib/ext/yuquelib.py +1105 -0
  58. pyxllib/file/__init__.py +17 -0
  59. pyxllib/file/docxlib.py +761 -0
  60. pyxllib/{util → file}/gitlib.py +40 -27
  61. pyxllib/file/libreoffice.py +165 -0
  62. pyxllib/file/movielib.py +148 -0
  63. pyxllib/file/newbie.py +10 -0
  64. pyxllib/file/onenotelib.py +1469 -0
  65. pyxllib/file/packlib/__init__.py +330 -0
  66. pyxllib/{util → file/packlib}/zipfile.py +598 -195
  67. pyxllib/file/pdflib.py +426 -0
  68. pyxllib/file/pupil.py +185 -0
  69. pyxllib/file/specialist/__init__.py +685 -0
  70. pyxllib/{basic/_5_dirlib.py → file/specialist/dirlib.py} +364 -93
  71. pyxllib/file/specialist/download.py +193 -0
  72. pyxllib/file/specialist/filelib.py +2829 -0
  73. pyxllib/file/xlsxlib.py +3131 -0
  74. pyxllib/file/xlsyncfile.py +341 -0
  75. pyxllib/prog/__init__.py +5 -0
  76. pyxllib/prog/cachetools.py +64 -0
  77. pyxllib/prog/deprecatedlib.py +233 -0
  78. pyxllib/prog/filelock.py +42 -0
  79. pyxllib/prog/ipyexec.py +253 -0
  80. pyxllib/prog/multiprogs.py +940 -0
  81. pyxllib/prog/newbie.py +451 -0
  82. pyxllib/prog/pupil.py +1197 -0
  83. pyxllib/{sitepackages.py → prog/sitepackages.py} +5 -3
  84. pyxllib/prog/specialist/__init__.py +391 -0
  85. pyxllib/prog/specialist/bc.py +203 -0
  86. pyxllib/prog/specialist/browser.py +497 -0
  87. pyxllib/prog/specialist/common.py +347 -0
  88. pyxllib/prog/specialist/datetime.py +199 -0
  89. pyxllib/prog/specialist/tictoc.py +240 -0
  90. pyxllib/prog/specialist/xllog.py +180 -0
  91. pyxllib/prog/xlosenv.py +108 -0
  92. pyxllib/stdlib/__init__.py +17 -0
  93. pyxllib/{util → stdlib}/tablepyxl/__init__.py +1 -3
  94. pyxllib/{util → stdlib}/tablepyxl/style.py +1 -1
  95. pyxllib/{util → stdlib}/tablepyxl/tablepyxl.py +2 -4
  96. pyxllib/text/__init__.py +8 -0
  97. pyxllib/text/ahocorasick.py +39 -0
  98. pyxllib/text/airscript.js +744 -0
  99. pyxllib/text/charclasslib.py +121 -0
  100. pyxllib/text/jiebalib.py +267 -0
  101. pyxllib/text/jinjalib.py +32 -0
  102. pyxllib/text/jsa_ai_prompt.md +271 -0
  103. pyxllib/text/jscode.py +922 -0
  104. pyxllib/text/latex/__init__.py +158 -0
  105. pyxllib/text/levenshtein.py +303 -0
  106. pyxllib/text/nestenv.py +1215 -0
  107. pyxllib/text/newbie.py +300 -0
  108. pyxllib/text/pupil/__init__.py +8 -0
  109. pyxllib/text/pupil/common.py +1121 -0
  110. pyxllib/text/pupil/xlalign.py +326 -0
  111. pyxllib/text/pycode.py +47 -0
  112. pyxllib/text/specialist/__init__.py +8 -0
  113. pyxllib/text/specialist/common.py +112 -0
  114. pyxllib/text/specialist/ptag.py +186 -0
  115. pyxllib/text/spellchecker.py +172 -0
  116. pyxllib/text/templates/echart_base.html +11 -0
  117. pyxllib/text/templates/highlight_code.html +17 -0
  118. pyxllib/text/templates/latex_editor.html +103 -0
  119. pyxllib/text/vbacode.py +17 -0
  120. pyxllib/text/xmllib.py +747 -0
  121. pyxllib/xl.py +39 -0
  122. pyxllib/xlcv.py +17 -0
  123. pyxllib-0.3.197.dist-info/METADATA +48 -0
  124. pyxllib-0.3.197.dist-info/RECORD +126 -0
  125. {pyxllib-0.0.43.dist-info → pyxllib-0.3.197.dist-info}/WHEEL +4 -5
  126. pyxllib/basic/_1_strlib.py +0 -945
  127. pyxllib/basic/_2_timelib.py +0 -488
  128. pyxllib/basic/_3_pathlib.py +0 -916
  129. pyxllib/basic/_4_loglib.py +0 -419
  130. pyxllib/basic/__init__.py +0 -54
  131. pyxllib/basic/arrow_.py +0 -250
  132. pyxllib/basic/chardet_.py +0 -66
  133. pyxllib/basic/dirlib.py +0 -529
  134. pyxllib/basic/dprint.py +0 -202
  135. pyxllib/basic/extension.py +0 -12
  136. pyxllib/basic/judge.py +0 -31
  137. pyxllib/basic/log.py +0 -204
  138. pyxllib/basic/pathlib_.py +0 -705
  139. pyxllib/basic/pytictoc.py +0 -102
  140. pyxllib/basic/qiniu_.py +0 -61
  141. pyxllib/basic/strlib.py +0 -761
  142. pyxllib/basic/timer.py +0 -132
  143. pyxllib/cv/cv.py +0 -834
  144. pyxllib/cv/cvlib/_1_geo.py +0 -543
  145. pyxllib/cv/cvlib/_2_cvprcs.py +0 -309
  146. pyxllib/cv/cvlib/_2_imgproc.py +0 -594
  147. pyxllib/cv/cvlib/_3_pilprcs.py +0 -80
  148. pyxllib/cv/cvlib/_4_cvimg.py +0 -211
  149. pyxllib/cv/cvlib/__init__.py +0 -10
  150. pyxllib/cv/debugtools.py +0 -82
  151. pyxllib/cv/fitz_.py +0 -300
  152. pyxllib/cv/installer.py +0 -42
  153. pyxllib/debug/_0_installer.py +0 -38
  154. pyxllib/debug/_1_typelib.py +0 -277
  155. pyxllib/debug/_2_chrome.py +0 -198
  156. pyxllib/debug/_3_showdir.py +0 -161
  157. pyxllib/debug/_4_bcompare.py +0 -140
  158. pyxllib/debug/__init__.py +0 -49
  159. pyxllib/debug/bcompare.py +0 -132
  160. pyxllib/debug/chrome.py +0 -198
  161. pyxllib/debug/installer.py +0 -38
  162. pyxllib/debug/showdir.py +0 -158
  163. pyxllib/debug/typelib.py +0 -278
  164. pyxllib/image/__init__.py +0 -12
  165. pyxllib/torch/__init__.py +0 -20
  166. pyxllib/torch/modellib.py +0 -37
  167. pyxllib/torch/trainlib.py +0 -344
  168. pyxllib/util/__init__.py +0 -20
  169. pyxllib/util/aip_.py +0 -141
  170. pyxllib/util/casiadb.py +0 -59
  171. pyxllib/util/excellib.py +0 -495
  172. pyxllib/util/filelib.py +0 -612
  173. pyxllib/util/jsondata.py +0 -27
  174. pyxllib/util/jsondata2.py +0 -92
  175. pyxllib/util/labelmelib.py +0 -139
  176. pyxllib/util/onepy/__init__.py +0 -29
  177. pyxllib/util/onepy/onepy.py +0 -574
  178. pyxllib/util/onepy/onmanager.py +0 -170
  179. pyxllib/util/pyautogui_.py +0 -219
  180. pyxllib/util/textlib.py +0 -1305
  181. pyxllib/util/unorder.py +0 -22
  182. pyxllib/util/xmllib.py +0 -639
  183. pyxllib-0.0.43.dist-info/METADATA +0 -39
  184. pyxllib-0.0.43.dist-info/RECORD +0 -80
  185. pyxllib-0.0.43.dist-info/top_level.txt +0 -1
  186. {pyxllib-0.0.43.dist-info → pyxllib-0.3.197.dist-info/licenses}/LICENSE +0 -0
pyxllib/basic/dprint.py DELETED
@@ -1,202 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/05/30 20:27
6
-
7
-
8
- """
9
- 调试相关功能
10
-
11
- TODO dprint是基于我个人目前的经验实现的,我还是要找个时间系统学习下python正规的日志是怎么做的
12
- 有些功能可能有现成标准库可以实现,不用我自己搞一套
13
- 以及我可能还要扩展高亮、写入文件日志等功能
14
- """
15
-
16
- import inspect
17
- import os
18
-
19
-
20
- def typename(c):
21
- """简化输出的type类型
22
- >>> typename(123)
23
- 'int'
24
- """
25
- return str(type(c))[8:-2]
26
-
27
-
28
- def func_input_message(depth=2) -> dict:
29
- """假设调用了这个函数的函数叫做f,这个函数会获得
30
- 调用f的时候输入的参数信息,返回一个dict,键值对为
31
- fullfilename:完整文件名
32
- filename:文件名
33
- funcname:所在函数名
34
- lineno:代码所在行号
35
- comment:尾巴的注释
36
- depth:深度
37
- funcnames:整个调用过程的函数名,用/隔开,例如...
38
-
39
- argnames:变量名(list),这里的变量名也有可能是一个表达式
40
- types:变量类型(list),如果是表达式,类型指表达式的运算结果类型
41
- argvals:变量值(list)
42
-
43
- 这样以后要加新的键值对也很方便
44
-
45
- :param depth: 需要分析的层级
46
- 0,当前func_input_message函数的参数输入情况
47
- 1,调用func_input_message的函数 f 参数输入情况
48
- 2,调用 f 的函数 g ,g的参数输入情况
49
-
50
- 参考: func_input_message 的具体使用方法可以参考 dformat 函数
51
- 细节:inspect可以获得函数签名,也可以获得一个函数各个参数的输入值,但我想要展现的是原始表达式,
52
- 例如func(a),以func(1+2)调用,inpect只能获得“a=3”,但我想要的是“1+2=3”的效果
53
- """
54
- res = {}
55
- # 1 找出调用函数的代码
56
- ss = inspect.stack()
57
- frameinfo = ss[depth]
58
- arginfo = inspect.getargvalues(ss[depth - 1][0])
59
- if arginfo.varargs:
60
- origin_args = arginfo.locals[arginfo.varargs]
61
- else:
62
- origin_args = list(map(lambda x: arginfo.locals[x], arginfo.args))
63
-
64
- res['fullfilename'] = frameinfo.filename
65
- res['filename'] = os.path.basename(frameinfo.filename)
66
- res['funcname'] = frameinfo.function
67
- res['lineno'] = frameinfo.lineno
68
- res['depth'] = len(ss)
69
- ls_ = list(map(lambda x: x.function, ss))
70
- # ls.reverse()
71
- res['funcnames'] = '/'.join(ls_)
72
-
73
- if frameinfo.code_context:
74
- code_line = frameinfo.code_context[0].strip()
75
- else: # 命令模式无法获得代码,是一个None对象
76
- code_line = ''
77
-
78
- funcname = ss[depth - 1].function # 调用的函数名
79
- # 这一行代码不一定是从“funcname(”开始,所以要用find找到开始位置
80
- code = code_line[code_line.find(funcname + '(') + len(funcname):]
81
-
82
- # 2 先找到函数的()中参数列表,需要以')'作为分隔符分析
83
- # TODO 可以考虑用ast重实现
84
- ls = code.split(')')
85
- logo, i = True, 1
86
- while logo and i <= len(ls):
87
- # 先将'='做特殊处理,防止字典类参数导致的语法错误
88
- s = ')'.join(ls[:i]).replace('=', '+') + ')'
89
- try:
90
- compile(s, '<string>', 'single')
91
- except SyntaxError:
92
- i += 1
93
- else: # 正常情况
94
- logo = False
95
- code = ')'.join(ls[:i])[1:]
96
-
97
- # 3 获得注释
98
- # 这个注释实现的不是很完美,不过影响应该不大,还没有想到比较完美的解决方案
99
- t = ')'.join(ls[i:])
100
- comment = t[t.find('#'):] if '#' in t else ''
101
- res['comment'] = comment
102
-
103
- # 4 获得变量名
104
- ls = code.split(',')
105
- n = len(ls)
106
- argnames = list()
107
- i, j = 0, 1
108
- while j <= n:
109
- s = ','.join(ls[i:j])
110
- try:
111
- compile(s.lstrip(), '<string>', 'single')
112
- except SyntaxError:
113
- j += 1
114
- else: # 没有错误的时候执行
115
- argnames.append(s.strip())
116
- i = j
117
- j = i + 1
118
-
119
- # 5 获得变量值和类型
120
- res['argvals'] = origin_args
121
- res['types'] = list(map(typename, origin_args))
122
-
123
- if not argnames: # 如果在命令行环境下调用,argnames会有空,需要根据argvals长度置空名称
124
- argnames = [''] * len(res['argvals'])
125
- res['argnames'] = argnames
126
-
127
- return res
128
-
129
-
130
- def dformat(*args, depth=2,
131
- delimiter=' ' * 4,
132
- strfunc=repr,
133
- fmt='[{depth:02}]{filename}/{lineno}: {argmsg} {comment}',
134
- subfmt='{name}<{tp}>={val}'):
135
- r"""
136
- :param args: 需要检查的表达式
137
- 这里看似没有调用,其实在func_input_message用inspect会提取到args的信息
138
- :param depth: 处理对象
139
- 默认值2,即处理dformat本身
140
- 2以下值没意义
141
- 2以上的值,可以不传入args参数
142
- :param delimiter: 每个变量值展示之间的分界
143
- :param strfunc: 对每个变量值的文本化方法,常见的有repr、str
144
- :param fmt: 展示格式,除了func_input_message中的关键字,新增
145
- argmsg:所有的「变量名=变量值」,或所有的「变量名<变量类型>=变量值」,或自定义格式,采用delimiter作为分界符
146
- 旧版还用过这种格式: '{filename}/{funcname}/{lineno}: {argmsg} {comment}'
147
- :param subfmt: 自定义每个变量值对的显示形式
148
- name,变量名
149
- val,变量值
150
- tp,变量类型
151
- :return: 返回格式化好的文本字符串
152
- """
153
- res = func_input_message(depth)
154
- ls = [subfmt.format(name=name, val=strfunc(val), tp=tp)
155
- for name, val, tp in zip(res['argnames'], res['argvals'], res['types'])]
156
- res['argmsg'] = delimiter.join(ls)
157
- return fmt.format(**res)
158
-
159
-
160
- def dprint(*args, **kwargs):
161
- r"""
162
- # 故意写的特别复杂,测试在极端情况下是否能正确解析出表达式
163
- >> a, b = 1, 2
164
- >> re.sub(str(dprint(1, b, a, "aa" + "bb)", "a[,ba\nbb""b", [2, 3])), '', '##') # 注释 # 注
165
- [08]<doctest debuglib.dprint[1]>/1: 1<int>=1 b<int>=2 a<int>=1 "aa" + "bb)"<str>='aabb)' "a[,ba\nbb""b"<str>='a[,ba\nbbb' [2, 3]<list>=[2, 3] ##') # 注释 # 注
166
- '##'
167
- """
168
- print(dformat(depth=3, **kwargs))
169
-
170
-
171
- def demo_dprint():
172
- """这里演示dprint常用功能
173
- """
174
- from .pytictoc import TicToc
175
-
176
- # 1 查看程序是否运行到某个位置
177
- dprint()
178
- # [05]dprint.py/169: 意思:这是堆栈的第5层,所运行的位置是 dprint.py文件的第169行
179
-
180
- # 2 查看变量、表达式的 '<类型>' 和 ':值'
181
- a, b, s = 1, 2, 'ab'
182
- dprint(a, b, a ^ b, s * 2)
183
- # [05]dprint.py/174: a<int>=1 b<int>=2 a ^ b<int>=3 s*2<str>='abab'
184
-
185
- # 3 异常警告
186
- b = 0
187
- if b:
188
- c = a / b
189
- else:
190
- c = 0
191
- dprint(a, b, c) # b=0不能作为除数,c默认值暂按0处理
192
- # [05]dprint.py/183: a<int>=1 b<int>=0 c<int>=0 # b=0不能作为除数,c默认值暂按0处理
193
-
194
- # 4 如果想在其他地方使用dprint的格式内容,可以调底层dformat函数实现
195
- with TicToc(dformat(fmt='[{depth:02}]{fullfilename}/{lineno}: {argmsg}')):
196
- for _ in range(10 ** 7):
197
- pass
198
- # [04]D:\slns\pyxllib\pyxllib\debug\dprint.py/187: 0.173 秒.
199
-
200
-
201
- if __name__ == '__main__':
202
- demo_dprint()
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/08/22 15:16
6
-
7
- """
8
- 其他一些有一定通用性,且依赖不复杂的功能
9
-
10
- 本模块在basic中默认不加载,需要使用时可以:
11
- from pyxlib.basic.extension import *
12
- """
pyxllib/basic/judge.py DELETED
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/05/30 20:49
6
-
7
-
8
- import os
9
-
10
-
11
- def is_url(arg):
12
- """输入是一个字符串,且值是一个合法的url"""
13
- from urllib.parse import urlparse
14
- if not isinstance(arg, str): return False
15
- try:
16
- result = urlparse(arg)
17
- return all([result.scheme, result.netloc])
18
- except ValueError:
19
- return False
20
-
21
-
22
- def is_file(arg, exists=True):
23
- """相较于标准库的os.path.isfile,对各种其他错误类型也会判False
24
-
25
- :param exists: arg不仅需要是一个合法的文件名,还要求其实际存在
26
- 设为False,则只判断文件名合法性,不要求其一定要存在
27
- """
28
- if not isinstance(arg, str): return False
29
- if not exists:
30
- raise NotImplementedError
31
- return os.path.isfile(arg)
pyxllib/basic/log.py DELETED
@@ -1,204 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/09/18 22:16
6
-
7
- import traceback
8
- import concurrent.futures
9
-
10
- from .timer import *
11
- from pyxllib.basic.strlib import *
12
- from pyxllib.basic.pathlib_ import *
13
-
14
- XLLOG_CONF_FILE = 'xllog.yaml'
15
-
16
-
17
- def get_xllog():
18
- """ 获得pyxllib库的日志类
19
-
20
- 由于日志类可能要读取yaml配置文件,需要使用Path类,所以实现代码先放在pathlib_.py
21
-
22
- TODO 类似企业微信机器人的机制怎么设?或者如何配置出问题发邮件?
23
- """
24
- import logging
25
-
26
- if 'pyxllib.xllog' in logging.root.manager.loggerDict:
27
- # 1 判断xllog是否已存在,直接返回
28
- pass
29
- elif os.path.isfile(XLLOG_CONF_FILE):
30
- # 2 若不存在,尝试在默认位置是否有自定义配置文件,读取配置文件来创建
31
- import logging.config
32
- data = Path(XLLOG_CONF_FILE).read()
33
- if isinstance(data, dict):
34
- # 推荐使用yaml的字典结构,格式更简洁清晰
35
- logging.config.dictConfig(data)
36
- else:
37
- # 但是普通的conf配置文件也支持
38
- logging.config.fileConfig(XLLOG_CONF_FILE)
39
- else:
40
- # 3 否则生成一个非常简易版的xllog
41
- # TODO 不同级别能设不同的格式(颜色)?
42
- xllog = logging.getLogger('pyxllib.xllog')
43
- xllog.setLevel(logging.DEBUG)
44
- ch = logging.StreamHandler()
45
- ch.setLevel(logging.DEBUG)
46
- ch.setFormatter(logging.Formatter('%(asctime)s %(message)s', datefmt='%H:%M:%S'))
47
- xllog.addHandler(ch)
48
- return logging.getLogger('pyxllib.xllog')
49
-
50
-
51
- def format_exception(e):
52
- return ''.join(traceback.format_exception(etype=type(e), value=e, tb=e.__traceback__))
53
-
54
-
55
- class Iterate:
56
- """ 迭代器类,用来封装一些特定模式的for循环操作
57
-
58
- TODO 双循环,需要内部两两对比的迭代功能
59
- """
60
-
61
- def __init__(self, items):
62
- # 没有总长度倒也能接受,关键是可能要用start、end切片,所以还是先转成tuple更方便操作
63
- self.items = tuple(items)
64
- self.n_items = len(self.items)
65
- self.format_width = math.ceil(math.log10(self.n_items + 1))
66
- self.xllog = get_xllog()
67
-
68
- def _step1_check_number(self, pinterval, func):
69
- if pinterval:
70
- sys.stdout.flush() # 让逻辑在前的标准输出先print出来,但其实这句也不一定能让print及时输出的~~可能会被日志提前抢输出了
71
- self.xllog.info(f"使用 {func} 处理 {self.n_items} 个数据 {shorten(str(self.items), 30)}")
72
-
73
- def _step2_check_range(self, start, end):
74
- if start:
75
- self.xllog.info(f"使用start参数,只处理≥{start}的条目")
76
- else:
77
- start = 0
78
- if end:
79
- # 这里空格是为了对齐,别删
80
- self.xllog.info(f"使用 end 参数,只处理<{end}的条目")
81
- else:
82
- end = len(self.items)
83
- return start, end
84
-
85
- def _step3_executor(self, pinterval, max_workers):
86
- executor = concurrent.futures.ThreadPoolExecutor(max_workers)
87
- if executor._max_workers != 1:
88
- if pinterval:
89
- self.xllog.info(f'多线程执行,当前迭代所用线程数:{executor._max_workers}')
90
- return executor
91
-
92
- def _step4_iter(self, i, pinterval, executor):
93
- if pinterval and (i or pinterval == 1) and i % pinterval == 0:
94
- message = f' {self.items[i]}' if pinterval == 1 else ''
95
- self.xllog.info(f'{i:{self.format_width}d}/{self.n_items}={i / self.n_items:6.2%}{message}')
96
- # 队列中没有新任务时,才放入新任务,这样能确保pinterval的输出能反应实时情况,而不是一下全部进入队列,把for循环跑完了
97
- while executor._work_queue.qsize(): pass
98
-
99
- def _step5_finish(self, pinterval, interrupt, executor):
100
- executor.shutdown()
101
- if not interrupt and pinterval:
102
- self.xllog.info(f'{self.n_items:{self.format_width}d}/{self.n_items}='
103
- f'{self.n_items / self.n_items:6.2%} 完成迭代')
104
- sys.stderr.flush()
105
-
106
- def run(self, func, start=0, end=None, pinterval=None, max_workers=1, interrupt=True):
107
- """
108
- :param func: 对每个item执行的功能
109
- :param start: 跳过<start的数据,只处理>=start编号以上
110
- :param end: 只处理 < end 的数据
111
- :param pinterval: 每隔多少条目输出进度日志,默认不输出进度日志(但是错误日志依然会输出)
112
- TODO 支持按百分比进度显示? 例如每20%,pinterval='20%'
113
- TODO 支持按指定时间间隔显示? 例如每15秒,pinterval='15s'
114
- :param max_workers: 默认线程数,默认1,即串行
115
- :type max_workers: int, None
116
- :param interrupt: 出现错误时是否中断,默认True会终止程序,否则只会输出错误日志
117
- :return:
118
- """
119
-
120
- # 1 统一的参数处理部分
121
- self._step1_check_number(pinterval, func)
122
- start, end = self._step2_check_range(start, end)
123
- error = False
124
- executor = self._step3_executor(pinterval, max_workers)
125
-
126
- # 2 封装的子处理部分
127
- def wrap_func(func, i):
128
- nonlocal error
129
- item = self.items[i]
130
- try:
131
- func(item)
132
- except Exception as e:
133
- error = True
134
- self.xllog.error(f'💔idx={i}运行出错:{item}\n{format_exception(e)}')
135
-
136
- # 3 执行迭代
137
- for i in range(start, end):
138
- self._step4_iter(i, pinterval, executor)
139
- executor.submit(wrap_func, func, i)
140
- if interrupt and error: break
141
- self._step5_finish(pinterval, interrupt and error, executor)
142
-
143
- def run_pair(self, func, start=0, end=None, pinterval=None, max_workers=1, interrupt=True):
144
- """ 对items两两运算
145
- func(x, y) 等同于 func(y, x),不重复运算
146
-
147
- :param start: 这里的start、end特指第一层迭代器i的取值范围
148
-
149
- TODO starti, endi, startj, endj,i和j支持单独设置遍历区间?
150
- """
151
- # 1 统一的参数处理部分
152
- self._step1_check_number(pinterval, func)
153
- start, end = self._step2_check_range(start, end)
154
- error = False
155
- executor = self._step3_executor(pinterval, max_workers)
156
-
157
- # 2 封装的子处理部分
158
- def wrap_func(func, i, j):
159
- nonlocal error
160
- item1, item2 = self.items[i], self.items[j]
161
- try:
162
- func(item1, item2)
163
- except Exception as e:
164
- error = True
165
- self.xllog.error(f'💔idxs=({i},{j})运行出错:{item1},{item2}\n{format_exception(e)}')
166
-
167
- # 3 执行迭代
168
- for i in range(start, end):
169
- self._step4_iter(i, pinterval, executor)
170
- for j in range(i + 1, self.n_items):
171
- executor.submit(wrap_func, func, i, j)
172
- if interrupt and error: break
173
- self._step5_finish(pinterval, interrupt and error, executor)
174
-
175
- def run_pair2(self, func, start=0, end=None, pinterval=None, max_workers=1, interrupt=True):
176
- """ 对items两两运算
177
- func(x, y) 不同于 func(y, x),需要全量运算
178
-
179
- :param start: 这里的start、end特指第一层迭代器i的取值范围
180
- """
181
- # 1 统一的参数处理部分
182
- self._step1_check_number(pinterval, func)
183
- start, end = self._step2_check_range(start, end)
184
- error = False
185
- executor = self._step3_executor(pinterval, max_workers)
186
-
187
- # 2 封装的子处理部分
188
- def wrap_func(func, i, j):
189
- nonlocal error
190
- item1, item2 = self.items[i], self.items[j]
191
- try:
192
- func(item1, item2)
193
- except Exception as e:
194
- error = True
195
- self.xllog.error(f'💔idxs=({i},{j})运行出错:{item1},{item2}\n{format_exception(e)}')
196
-
197
- # 3 执行迭代
198
- for i in range(start, end):
199
- self._step4_iter(i, pinterval, executor)
200
- for j in range(self.n_items):
201
- if j == i: continue
202
- executor.submit(wrap_func, func, i, j)
203
- if interrupt and error: break
204
- self._step5_finish(pinterval, interrupt and error, executor)