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
@@ -1,419 +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 concurrent.futures
8
- import inspect
9
- import logging
10
- import math
11
- import os
12
- import queue
13
- import sys
14
- import traceback
15
-
16
- # https://pypi.org/project/verboselogs/
17
- # import verboselogs
18
- # verboselogs.install()
19
-
20
- from pyxllib.basic._1_strlib import shorten
21
- from pyxllib.basic._3_pathlib import Path
22
-
23
- XLLOG_CONF_FILE = 'xllog.yaml'
24
-
25
- ____dprint = """
26
- 调试相关功能
27
-
28
- TODO 高亮格式?
29
- """
30
-
31
-
32
- def typename(c):
33
- """简化输出的type类型
34
- >>> typename(123)
35
- 'int'
36
- """
37
- return str(type(c))[8:-2]
38
-
39
-
40
- def func_input_message(depth=2) -> dict:
41
- """假设调用了这个函数的函数叫做f,这个函数会获得
42
- 调用f的时候输入的参数信息,返回一个dict,键值对为
43
- fullfilename:完整文件名
44
- filename:文件名
45
- funcname:所在函数名
46
- lineno:代码所在行号
47
- comment:尾巴的注释
48
- depth:深度
49
- funcnames:整个调用过程的函数名,用/隔开,例如...
50
-
51
- argnames:变量名(list),这里的变量名也有可能是一个表达式
52
- types:变量类型(list),如果是表达式,类型指表达式的运算结果类型
53
- argvals:变量值(list)
54
-
55
- 这样以后要加新的键值对也很方便
56
-
57
- :param depth: 需要分析的层级
58
- 0,当前func_input_message函数的参数输入情况
59
- 1,调用func_input_message的函数 f 参数输入情况
60
- 2,调用 f 的函数 g ,g的参数输入情况
61
-
62
- 参考: func_input_message 的具体使用方法可以参考 dformat 函数
63
- 细节:inspect可以获得函数签名,也可以获得一个函数各个参数的输入值,但我想要展现的是原始表达式,
64
- 例如func(a),以func(1+2)调用,inpect只能获得“a=3”,但我想要的是“1+2=3”的效果
65
- """
66
- res = {}
67
- # 1 找出调用函数的代码
68
- ss = inspect.stack()
69
- frameinfo = ss[depth]
70
- arginfo = inspect.getargvalues(ss[depth - 1][0])
71
- if arginfo.varargs:
72
- origin_args = arginfo.locals[arginfo.varargs]
73
- else:
74
- origin_args = list(map(lambda x: arginfo.locals[x], arginfo.args))
75
-
76
- res['fullfilename'] = frameinfo.filename
77
- res['filename'] = os.path.basename(frameinfo.filename)
78
- res['funcname'] = frameinfo.function
79
- res['lineno'] = frameinfo.lineno
80
- res['depth'] = len(ss)
81
- ls_ = list(map(lambda x: x.function, ss))
82
- # ls.reverse()
83
- res['funcnames'] = '/'.join(ls_)
84
-
85
- if frameinfo.code_context:
86
- code_line = frameinfo.code_context[0].strip()
87
- else: # 命令模式无法获得代码,是一个None对象
88
- code_line = ''
89
-
90
- funcname = ss[depth - 1].function # 调用的函数名
91
- # 这一行代码不一定是从“funcname(”开始,所以要用find找到开始位置
92
- code = code_line[code_line.find(funcname + '(') + len(funcname):]
93
-
94
- # 2 先找到函数的()中参数列表,需要以')'作为分隔符分析
95
- # TODO 可以考虑用ast重实现
96
- ls = code.split(')')
97
- logo, i = True, 1
98
- while logo and i <= len(ls):
99
- # 先将'='做特殊处理,防止字典类参数导致的语法错误
100
- s = ')'.join(ls[:i]).replace('=', '+') + ')'
101
- try:
102
- compile(s, '<string>', 'single')
103
- except SyntaxError:
104
- i += 1
105
- else: # 正常情况
106
- logo = False
107
- code = ')'.join(ls[:i])[1:]
108
-
109
- # 3 获得注释
110
- # 这个注释实现的不是很完美,不过影响应该不大,还没有想到比较完美的解决方案
111
- t = ')'.join(ls[i:])
112
- comment = t[t.find('#'):] if '#' in t else ''
113
- res['comment'] = comment
114
-
115
- # 4 获得变量名
116
- ls = code.split(',')
117
- n = len(ls)
118
- argnames = list()
119
- i, j = 0, 1
120
- while j <= n:
121
- s = ','.join(ls[i:j])
122
- try:
123
- compile(s.lstrip(), '<string>', 'single')
124
- except SyntaxError:
125
- j += 1
126
- else: # 没有错误的时候执行
127
- argnames.append(s.strip())
128
- i = j
129
- j = i + 1
130
-
131
- # 5 获得变量值和类型
132
- res['argvals'] = origin_args
133
- res['types'] = list(map(typename, origin_args))
134
-
135
- if not argnames: # 如果在命令行环境下调用,argnames会有空,需要根据argvals长度置空名称
136
- argnames = [''] * len(res['argvals'])
137
- res['argnames'] = argnames
138
-
139
- return res
140
-
141
-
142
- def dformat(*args, depth=2,
143
- delimiter=' ' * 4,
144
- strfunc=repr,
145
- fmt='[{depth:02}]{filename}/{lineno}: {argmsg} {comment}',
146
- subfmt='{name}<{tp}>={val}'):
147
- r"""
148
- :param args: 需要检查的表达式
149
- 这里看似没有调用,其实在func_input_message用inspect会提取到args的信息
150
- :param depth: 处理对象
151
- 默认值2,即处理dformat本身
152
- 2以下值没意义
153
- 2以上的值,可以不传入args参数
154
- :param delimiter: 每个变量值展示之间的分界
155
- :param strfunc: 对每个变量值的文本化方法,常见的有repr、str
156
- :param fmt: 展示格式,除了func_input_message中的关键字,新增
157
- argmsg:所有的「变量名=变量值」,或所有的「变量名<变量类型>=变量值」,或自定义格式,采用delimiter作为分界符
158
- 旧版还用过这种格式: '{filename}/{funcname}/{lineno}: {argmsg} {comment}'
159
- :param subfmt: 自定义每个变量值对的显示形式
160
- name,变量名
161
- val,变量值
162
- tp,变量类型
163
- :return: 返回格式化好的文本字符串
164
- """
165
- res = func_input_message(depth)
166
- ls = [subfmt.format(name=name, val=strfunc(val), tp=tp)
167
- for name, val, tp in zip(res['argnames'], res['argvals'], res['types'])]
168
- res['argmsg'] = delimiter.join(ls)
169
- return fmt.format(**res)
170
-
171
-
172
- def dprint(*args, **kwargs):
173
- r"""
174
- # 故意写的特别复杂,测试在极端情况下是否能正确解析出表达式
175
- >> a, b = 1, 2
176
- >> re.sub(str(dprint(1, b, a, "aa" + "bb)", "a[,ba\nbb""b", [2, 3])), '', '##') # 注释 # 注
177
- [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] ##') # 注释 # 注
178
- '##'
179
- """
180
- print(dformat(depth=3, **kwargs))
181
-
182
-
183
- def demo_dprint():
184
- """这里演示dprint常用功能
185
- """
186
- from ._2_timelib import TicToc
187
-
188
- # 1 查看程序是否运行到某个位置
189
- dprint()
190
- # [05]dprint.py/169: 意思:这是堆栈的第5层,所运行的位置是 dprint.py文件的第169行
191
-
192
- # 2 查看变量、表达式的 '<类型>' 和 ':值'
193
- a, b, s = 1, 2, 'ab'
194
- dprint(a, b, a ^ b, s * 2)
195
- # [05]dprint.py/174: a<int>=1 b<int>=2 a ^ b<int>=3 s*2<str>='abab'
196
-
197
- # 3 异常警告
198
- b = 0
199
- if b:
200
- c = a / b
201
- else:
202
- c = 0
203
- dprint(a, b, c) # b=0不能作为除数,c默认值暂按0处理
204
- # [05]dprint.py/183: a<int>=1 b<int>=0 c<int>=0 # b=0不能作为除数,c默认值暂按0处理
205
-
206
- # 4 如果想在其他地方使用dprint的格式内容,可以调底层dformat函数实现
207
- with TicToc(dformat(fmt='[{depth:02}]{fullfilename}/{lineno}: {argmsg}')):
208
- for _ in range(10 ** 7):
209
- pass
210
- # [04]D:\slns\pyxllib\pyxllib\debug\dprint.py/187: 0.173 秒.
211
-
212
-
213
- ____xllog = """
214
- """
215
-
216
-
217
- def get_xllog():
218
- """ 获得pyxllib库的日志类
219
-
220
- 由于日志类可能要读取yaml配置文件,需要使用Path类,所以实现代码先放在pathlib_.py
221
-
222
- TODO 类似企业微信机器人的机制怎么设?或者如何配置出问题发邮件?
223
- """
224
- import logging, coloredlogs
225
-
226
- if 'pyxllib.xllog' in logging.root.manager.loggerDict:
227
- # 1 判断xllog是否已存在,直接返回
228
- pass
229
- elif os.path.isfile(XLLOG_CONF_FILE):
230
- # 2 若不存在,尝试在默认位置是否有自定义配置文件,读取配置文件来创建
231
- import logging.config
232
- data = Path(XLLOG_CONF_FILE).read()
233
- if isinstance(data, dict):
234
- # 推荐使用yaml的字典结构,格式更简洁清晰
235
- logging.config.dictConfig(data)
236
- else:
237
- # 但是普通的conf配置文件也支持
238
- logging.config.fileConfig(XLLOG_CONF_FILE)
239
- else:
240
- # 3 否则生成一个非常简易版的xllog
241
- # TODO 不同级别能设不同的格式(颜色)?
242
- xllog = logging.getLogger('pyxllib.xllog')
243
- # xllog.setLevel(logging.DEBUG)
244
- # ch = logging.StreamHandler()
245
- # ch.setLevel(logging.DEBUG)
246
- # ch.setFormatter(logging.Formatter('%(asctime)s %(message)s'))
247
- # xllog.addHandler(ch)
248
- coloredlogs.install(level='DEBUG', logger=xllog, fmt='%(asctime)s %(message)s')
249
- return logging.getLogger('pyxllib.xllog')
250
-
251
-
252
- def format_exception(e):
253
- return ''.join(traceback.format_exception(etype=type(e), value=e, tb=e.__traceback__))
254
-
255
-
256
- ____iterate = """
257
- """
258
-
259
-
260
- class EmptyPoolExecutor:
261
- """伪造一个类似concurrent.futures.ThreadPoolExecutor、ProcessPoolExecutor的接口类
262
- 用来检查多线程、多进程中的错误
263
-
264
- 即并行中不会直接报出每个线程的错误,只能串行执行才好检查
265
- 但是两种版本代码来回修改很麻烦,故设计此类,只需把
266
- concurrent.futures.ThreadPoolExecutor 暂时改为 EmptyPoolExecutor 进行调试即可
267
- """
268
-
269
- def __init__(self, *args, **kwargs):
270
- """参数并不需要实际处理,并没有真正并行,而是串行执行"""
271
- self._work_queue = queue.Queue()
272
-
273
- def submit(self, func, *args, **kwargs):
274
- """执行函数"""
275
- func(*args, **kwargs)
276
-
277
- def shutdown(self):
278
- print('并行执行结束')
279
-
280
-
281
- class Iterate:
282
- """ 迭代器类,用来封装一些特定模式的for循环操作
283
-
284
- TODO 双循环,需要内部两两对比的迭代功能
285
-
286
- 200920周日18:20,最初设计的时候,是提供run_pair、run_pair2的功能的
287
- 不过后来想想,这个其实就是排列组合,在itertools里有combinations, permutations可以代替
288
- 甚至有放回的组合也有combinations_with_replacement,我实在是不需要再这里写这些冗余的功能
289
- 所以就移除了
290
- """
291
-
292
- def __init__(self, items):
293
- # 没有总长度倒也能接受,关键是可能要用start、end切片,所以还是先转成tuple更方便操作
294
- self.items = tuple(items)
295
- self.n_items = len(self.items)
296
- self.format_width = math.ceil(math.log10(self.n_items + 1))
297
- self.xllog = get_xllog()
298
-
299
- def _format_pinterval(self, pinterval=None):
300
- if isinstance(pinterval, str) and pinterval.endswith('%'):
301
- # 百分比的情况,重算出间隔元素数
302
- return int(round(self.n_items * float(pinterval[:-1]) / 100))
303
- else: # 其他格式暂不解析,按原格式处理
304
- return pinterval
305
-
306
- def _step1_check_number(self, pinterval, func):
307
- if pinterval:
308
- sys.stdout.flush() # 让逻辑在前的标准输出先print出来,但其实这句也不一定能让print及时输出的~~可能会被日志提前抢输出了
309
- self.xllog.info(f"使用 {func} 处理 {self.n_items} 个数据 {shorten(str(self.items), 30)}")
310
-
311
- def _step2_check_range(self, start, end):
312
- if start:
313
- self.xllog.info(f"使用start参数,只处理≥{start}的条目")
314
- else:
315
- start = 0
316
- if end:
317
- # 这里空格是为了对齐,别删
318
- self.xllog.info(f"使用 end 参数,只处理<{end}的条目")
319
- else:
320
- end = len(self.items)
321
- return start, end
322
-
323
- def _step3_executor(self, pinterval, max_workers):
324
- if max_workers == 1:
325
- # workers=1,实际上并不用多线程,用一个假的多线程类代替,能大大提速
326
- executor = EmptyPoolExecutor()
327
- # executor = concurrent.futures.ThreadPoolExecutor(max_workers)
328
- else:
329
- executor = concurrent.futures.ThreadPoolExecutor(max_workers)
330
- if pinterval:
331
- self.xllog.info(f'多线程执行,当前迭代所用线程数:{executor._max_workers}')
332
- return executor
333
-
334
- def _step4_iter(self, i, pinterval, executor):
335
- # 队列中没有新任务时,才放入新任务,这样能确保pinterval的输出能反应实时情况,而不是一下全部进入队列,把for循环跑完了
336
- while executor._work_queue.qsize(): pass
337
- if pinterval and (i or pinterval == 1) and i % pinterval == 0:
338
- message = f' {self.items[i]}' if pinterval == 1 else ''
339
- self.xllog.info(f'{i:{self.format_width}d}/{self.n_items}={i / self.n_items:6.2%}{message}')
340
-
341
- def _step5_finish(self, pinterval, interrupt):
342
- if not interrupt and pinterval:
343
- self.xllog.info(f'{self.n_items / self.n_items:6.2%} 完成迭代')
344
- sys.stderr.flush()
345
-
346
- def run(self, func, start=0, end=None, pinterval=None, max_workers=1, interrupt=True):
347
- """
348
- :param func: 对每个item执行的功能
349
- :param start: 跳过<start的数据,只处理>=start编号以上
350
- :param end: 只处理 < end 的数据
351
- :param pinterval: 每隔多少条目输出进度日志,默认不输出进度日志(但是错误日志依然会输出)
352
- 支持按百分比进度显示,例如每20%,pinterval='20%',不过一些底层实现机制原因,会有些许误差
353
- TODO 支持按指定时间间隔显示? 例如每15秒,pinterval='15s' 感觉这种功能太花哨了,没必要搞
354
- :param max_workers: 默认线程数,默认1,即串行
355
- :type max_workers: int, None
356
- :param interrupt: 出现错误时是否中断,默认True会终止程序,否则只会输出错误日志
357
- :return:
358
- """
359
-
360
- # 1 统一的参数处理部分
361
- pinterval = self._format_pinterval(pinterval)
362
- self._step1_check_number(pinterval, func)
363
- start, end = self._step2_check_range(start, end)
364
- error = False
365
- executor = self._step3_executor(pinterval, max_workers)
366
-
367
- # 2 封装的子处理部分
368
- def wrap_func(func, i):
369
- nonlocal error
370
- item = self.items[i]
371
- try:
372
- func(item)
373
- except Exception as e:
374
- error = True
375
- self.xllog.error(f'💔idx={i}运行出错:{item}\n{format_exception(e)}')
376
-
377
- # 3 执行迭代
378
- for i in range(start, end):
379
- self._step4_iter(i, pinterval, executor)
380
- executor.submit(wrap_func, func, i)
381
- if interrupt and error: break
382
- executor.shutdown() # 必须等executor结束,error才是准确的
383
- self._step5_finish(pinterval, interrupt and error)
384
-
385
-
386
- class RunOnlyOnce:
387
- """ 被装饰的函数,不同的参数输入形式,只会被执行一次,
388
-
389
- 重复执行时会从内存直接调用上次相同参数调用下的运行的结果
390
- 可以使用reset成员函数重置,下一次调用该函数时则会重新执行
391
-
392
- 文档:https://www.yuque.com/xlpr/pyxllib/RunOnlyOnce
393
-
394
- 使用好该装饰器,可能让一些动态规划dp、搜索问题变得更简洁,
395
- 以及一些配置文件操作,可以做到只读一遍
396
- """
397
-
398
- def __init__(self, func, distinct_args=True):
399
- """
400
- :param func: 封装的函数
401
- :param distinct_args: 默认不同输入参数形式,都会保存一个结果
402
- 设为False,则不管何种参数形式,函数就真的只会保存第一次运行的结果
403
- """
404
- self.func = func
405
- self.distinct_args = distinct_args
406
- self.results = {}
407
-
408
- def __call__(self, *args, **kwargs):
409
- tag = f'{args}{kwargs}' if self.distinct_args else ''
410
- # TODO 思考更严谨,考虑了值类型的tag标记
411
- # 目前的tag规则,是必要不充分条件。还可以使用id,则是充分不必要条件
412
- # 能找到充要条件来做是最好的,不行的话,也应该用更严谨的充分条件来做
413
- # TODO kwargs的顺序应该是没影响的,要去掉顺序干扰
414
- if tag not in self.results:
415
- self.results[tag] = self.func(*args, **kwargs)
416
- return self.results[tag]
417
-
418
- def reset(self):
419
- self.results = {}
pyxllib/basic/__init__.py DELETED
@@ -1,54 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Data : 2020/08/14 21:52
6
-
7
-
8
- """
9
- 最基础常用的一些功能
10
-
11
- basic中依赖的三方库有直接写到 requirements.txt 中
12
- (其他debug、cv等库的依赖项都是等使用到了才加入)
13
-
14
- 且basic依赖的三方库,都确保是体积小
15
- 能快速pip install
16
- 及pyinstaller -F打包生成的exe也不大的库
17
- """
18
-
19
- # 1 文本处理等一些基础杂项功能
20
- from pyxllib.basic._1_strlib import *
21
- # 2 时间相关工具
22
- from pyxllib.basic._2_timelib import *
23
- # 3 文件、路径工具
24
- from pyxllib.basic._3_pathlib import *
25
- # 4 调试工具,Iterate等一些高级通用功能
26
- from pyxllib.basic._4_loglib import *
27
- # 5 目录工具
28
- from pyxllib.basic._5_dirlib import *
29
-
30
- ____other = """
31
- """
32
-
33
-
34
- class SingletonForEveryInitArgs(type):
35
- """Python单例模式(Singleton)的N种实现 - 知乎: https://zhuanlan.zhihu.com/p/37534850
36
-
37
- 注意!注意!注意!重要的事说三遍!
38
- 我的单例类不是传统意义上的单例类。
39
- 传统意义的单例类,不管用怎样不同的初始化参数创建对象,永远都只有最初的那个对象类。
40
- 但是我的单例类,为每种不同的参数创建形式,都构造了一个对象。
41
- """
42
- _instances = {}
43
-
44
- def __call__(cls, *args, **kwargs):
45
- tag = f'{cls}{args}{kwargs}' # id加上所有参数的影响来控制单例类
46
- # 其实转字符串来判断是不太严谨的,有些类型字符串后的显示效果是一模一样的
47
- # dprint(tag)
48
- if tag not in cls._instances:
49
- cls._instances[tag] = super(SingletonForEveryInitArgs, cls).__call__(*args, **kwargs)
50
- return cls._instances[tag]
51
-
52
-
53
- if __name__ == '__main__':
54
- pass