ezKit 1.6.2__py3-none-any.whl → 1.7.1__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.
- ezKit/bottle.py +1949 -1083
- ezKit/utils.py +578 -433
- {ezKit-1.6.2.dist-info → ezKit-1.7.1.dist-info}/METADATA +2 -2
- {ezKit-1.6.2.dist-info → ezKit-1.7.1.dist-info}/RECORD +7 -7
- {ezKit-1.6.2.dist-info → ezKit-1.7.1.dist-info}/WHEEL +1 -1
- {ezKit-1.6.2.dist-info → ezKit-1.7.1.dist-info}/LICENSE +0 -0
- {ezKit-1.6.2.dist-info → ezKit-1.7.1.dist-info}/top_level.txt +0 -0
ezKit/utils.py
CHANGED
@@ -1,17 +1,6 @@
|
|
1
1
|
"""
|
2
2
|
Python Utils
|
3
3
|
"""
|
4
|
-
"""
|
5
|
-
函数
|
6
|
-
|
7
|
-
- 明确 参数 和 返回值 的类型
|
8
|
-
- 必须有返回值
|
9
|
-
- 添加一个 debug 参数, 用于调试
|
10
|
-
- 如果 debug 为 True, 则输出相关信息, 否则一律不输出任何信息
|
11
|
-
- logger.exception(e) if v_true(debug, bool) else next
|
12
|
-
- 必须有说明
|
13
|
-
- 必须用 try ... except ... 包裹
|
14
|
-
"""
|
15
4
|
import csv
|
16
5
|
import datetime
|
17
6
|
import hashlib
|
@@ -25,7 +14,7 @@ from multiprocessing.pool import ThreadPool
|
|
25
14
|
from pathlib import Path
|
26
15
|
from shutil import rmtree
|
27
16
|
from threading import Thread
|
28
|
-
from typing import Callable
|
17
|
+
from typing import Any, Callable, List, Optional, Union
|
29
18
|
from urllib.parse import ParseResult, urlparse
|
30
19
|
from uuid import uuid4
|
31
20
|
|
@@ -43,16 +32,15 @@ NoneType = type(None)
|
|
43
32
|
|
44
33
|
|
45
34
|
def v_true(
|
46
|
-
v_instance:
|
47
|
-
v_type:
|
35
|
+
v_instance: Any,
|
36
|
+
v_type: Any = None,
|
48
37
|
true_list: list | tuple | set | str | None = None,
|
49
38
|
false_list: list | tuple | set | str | None = None,
|
50
39
|
debug: bool = False
|
51
40
|
) -> bool:
|
52
41
|
"""
|
53
|
-
检查变量类型以及变量是否为True
|
54
|
-
|
55
|
-
"""
|
42
|
+
检查变量类型以及变量是否为 True
|
43
|
+
|
56
44
|
常见类型:
|
57
45
|
|
58
46
|
Boolean bool False
|
@@ -63,65 +51,92 @@ def v_true(
|
|
63
51
|
|
64
52
|
函数使用 callable(func) 判断
|
65
53
|
"""
|
54
|
+
|
66
55
|
try:
|
56
|
+
|
67
57
|
if isinstance(v_instance, v_type):
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
58
|
+
|
59
|
+
if all(
|
60
|
+
[
|
61
|
+
true_list is not None,
|
62
|
+
false_list is None,
|
63
|
+
isinstance(true_list, (list, tuple, set, str))
|
64
|
+
]
|
73
65
|
):
|
74
|
-
return
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
66
|
+
return v_instance in true_list
|
67
|
+
|
68
|
+
if all(
|
69
|
+
[
|
70
|
+
true_list is None,
|
71
|
+
false_list is not None,
|
72
|
+
isinstance(false_list, (list, tuple, set, str))
|
73
|
+
]
|
80
74
|
):
|
81
|
-
return
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
isinstance(false_list, list)
|
89
|
-
|
90
|
-
isinstance(false_list, set) or
|
91
|
-
isinstance(false_list, str)
|
75
|
+
return v_instance not in false_list
|
76
|
+
|
77
|
+
if all(
|
78
|
+
[
|
79
|
+
true_list is not None,
|
80
|
+
false_list is not None,
|
81
|
+
isinstance(true_list, (list, tuple, set, str)),
|
82
|
+
isinstance(false_list, (list, tuple, set, str))
|
83
|
+
]
|
92
84
|
):
|
93
|
-
return
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
85
|
+
return (v_instance in true_list) and (v_instance not in false_list)
|
86
|
+
|
87
|
+
return v_instance not in [False, None, 0, 0.0, '', (), [], {*()}, {*[]}, {*{}}, {}]
|
88
|
+
|
89
|
+
return False
|
90
|
+
|
98
91
|
except Exception as e:
|
99
|
-
|
92
|
+
if v_true(debug, bool):
|
93
|
+
logger.exception(e)
|
100
94
|
return False
|
101
95
|
|
102
96
|
|
97
|
+
# --------------------------------------------------------------------------------------------------
|
98
|
+
|
99
|
+
|
103
100
|
def os_environ(
|
104
101
|
name: str,
|
105
|
-
value:
|
102
|
+
value: Any = None,
|
106
103
|
debug: bool = False
|
107
|
-
) ->
|
108
|
-
"""伪全局变量"""
|
104
|
+
) -> Any:
|
109
105
|
"""
|
110
|
-
|
111
|
-
|
106
|
+
系统变量
|
107
|
+
|
108
|
+
伪全局变量
|
109
|
+
Python 没有全局变量, 多个文件无法调用同一个变量.
|
110
|
+
为了解决这个问题, 将变量设置为系统变量, 从而实现多个文件调用同一个变量.
|
112
111
|
"""
|
113
112
|
try:
|
113
|
+
|
114
114
|
# 变量名添加一个前缀, 防止和系统中其它变量名冲突
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
115
|
+
_variable_name = f'PYTHON_VARIABLE_{name}'
|
116
|
+
|
117
|
+
if value is None:
|
118
|
+
|
119
|
+
_data = os.environ.get(_variable_name)
|
120
|
+
|
121
|
+
# 判断是否有数据
|
122
|
+
if _data:
|
123
|
+
try:
|
124
|
+
# 如果环境变量有值, 使用 json.loads() 解析
|
125
|
+
parsed_data = json.loads(_data)
|
126
|
+
return parsed_data
|
127
|
+
except json.JSONDecodeError:
|
128
|
+
return None
|
129
|
+
else:
|
130
|
+
return None
|
131
|
+
|
132
|
+
_data = json.dumps(value)
|
133
|
+
os.environ[_variable_name] = _data
|
134
|
+
|
135
|
+
return value
|
136
|
+
|
123
137
|
except Exception as e:
|
124
|
-
|
138
|
+
if v_true(debug, bool):
|
139
|
+
logger.exception(e)
|
125
140
|
return None
|
126
141
|
|
127
142
|
|
@@ -134,10 +149,13 @@ def mam_of_numbers(
|
|
134
149
|
debug: bool = False
|
135
150
|
) -> tuple[int | float, int | float, int | float] | tuple[None, None, None]:
|
136
151
|
"""
|
152
|
+
(maximum, average, minimum)
|
153
|
+
|
137
154
|
返回一组数字中的 最大值(maximum), 平均值(average), 最小值(minimum)
|
138
155
|
numbers 数字列表 (仅支持 list 和 tuple, 不支 set)
|
139
156
|
dest_type 目标类型 (将数字列表中的数字转换成统一的类型)
|
140
157
|
"""
|
158
|
+
|
141
159
|
try:
|
142
160
|
_numbers = deepcopy(numbers)
|
143
161
|
match True:
|
@@ -150,52 +168,60 @@ def mam_of_numbers(
|
|
150
168
|
_num_min = min(_numbers)
|
151
169
|
return _num_max, _num_avg, _num_min
|
152
170
|
except Exception as e:
|
153
|
-
|
171
|
+
if v_true(debug, bool):
|
172
|
+
logger.exception(e)
|
154
173
|
return None, None, None
|
155
174
|
|
156
175
|
|
176
|
+
# --------------------------------------------------------------------------------------------------
|
177
|
+
|
178
|
+
|
157
179
|
def step_number_for_split_equally(
|
158
180
|
integer: int,
|
159
181
|
split_equally_number: int,
|
160
182
|
debug: bool = False
|
161
183
|
) -> int | None:
|
162
184
|
"""
|
185
|
+
step number for split equally
|
186
|
+
|
163
187
|
平分数字的步长
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
188
|
+
|
189
|
+
integer 数字
|
190
|
+
split_equally_number 平分 integer 的数字
|
191
|
+
|
168
192
|
示例:
|
169
193
|
|
170
194
|
[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
171
195
|
|
172
|
-
分成 2 份 -> [[1, 2, 3, 4, 5], [6, 7, 8, 9]]
|
173
|
-
分成 3 份 -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
174
|
-
分成 4 份 -> [[1, 2, 3], [4, 5], [6, 7], [8, 9]]
|
175
|
-
分成 5 份 -> [[1, 2], [3, 4], [5, 6], [7, 8], [9]]
|
196
|
+
分成 2 份 -> [[1, 2, 3, 4, 5], [6, 7, 8, 9]] -> 返回 5
|
197
|
+
分成 3 份 -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] -> 返回 3
|
198
|
+
分成 4 份 -> [[1, 2, 3], [4, 5], [6, 7], [8, 9]] -> 返回 3
|
199
|
+
分成 5 份 -> [[1, 2], [3, 4], [5, 6], [7, 8], [9]] -> 返回 2
|
176
200
|
"""
|
177
201
|
try:
|
178
202
|
if integer % split_equally_number == 0:
|
179
203
|
return int(integer / split_equally_number)
|
180
|
-
|
181
|
-
return int(integer / split_equally_number) + 1
|
204
|
+
return int(integer / split_equally_number) + 1
|
182
205
|
except Exception as e:
|
183
|
-
|
206
|
+
if v_true(debug, bool):
|
207
|
+
logger.exception(e)
|
184
208
|
return None
|
185
209
|
|
186
210
|
|
211
|
+
# --------------------------------------------------------------------------------------------------
|
212
|
+
|
213
|
+
|
187
214
|
def division(
|
188
215
|
dividend: int | float,
|
189
216
|
divisor: int | float,
|
190
217
|
debug: bool = False
|
191
218
|
) -> float | None:
|
192
|
-
"""
|
193
|
-
除法
|
194
|
-
"""
|
219
|
+
"""Division"""
|
195
220
|
try:
|
196
221
|
return dividend / divisor
|
197
222
|
except Exception as e:
|
198
|
-
|
223
|
+
if v_true(debug, bool):
|
224
|
+
logger.exception(e)
|
199
225
|
return None
|
200
226
|
|
201
227
|
|
@@ -203,13 +229,13 @@ def divisor_1000(
|
|
203
229
|
dividend: int | float,
|
204
230
|
debug: bool = False
|
205
231
|
) -> float | None:
|
206
|
-
"""
|
207
|
-
除法, 除以 1000
|
208
|
-
"""
|
232
|
+
"""Division (divisor: 1000)"""
|
233
|
+
# 除法, 除以 1000
|
209
234
|
try:
|
210
235
|
return dividend / 1000
|
211
236
|
except Exception as e:
|
212
|
-
|
237
|
+
if v_true(debug, bool):
|
238
|
+
logger.exception(e)
|
213
239
|
return None
|
214
240
|
|
215
241
|
|
@@ -217,13 +243,13 @@ def divisor_1024(
|
|
217
243
|
dividend: int | float,
|
218
244
|
debug: bool = False
|
219
245
|
) -> float | None:
|
220
|
-
"""
|
221
|
-
除法, 除以 1024
|
222
|
-
"""
|
246
|
+
"""Division (divisor: 1024)"""
|
247
|
+
# 除法, 除以 1024
|
223
248
|
try:
|
224
249
|
return dividend / 1024
|
225
250
|
except Exception as e:
|
226
|
-
|
251
|
+
if v_true(debug, bool):
|
252
|
+
logger.exception(e)
|
227
253
|
return None
|
228
254
|
|
229
255
|
|
@@ -231,13 +257,12 @@ def divisor_square_1000(
|
|
231
257
|
dividend: int | float,
|
232
258
|
debug: bool = False
|
233
259
|
) -> float | None:
|
234
|
-
"""
|
235
|
-
除法, 除以 1000的次方
|
236
|
-
"""
|
260
|
+
"""Division (divisor: 1000*1000)"""
|
237
261
|
try:
|
238
262
|
return dividend / (1000 * 1000)
|
239
263
|
except Exception as e:
|
240
|
-
|
264
|
+
if v_true(debug, bool):
|
265
|
+
logger.exception(e)
|
241
266
|
return None
|
242
267
|
|
243
268
|
|
@@ -245,13 +270,12 @@ def divisor_square_1024(
|
|
245
270
|
dividend: int | float,
|
246
271
|
debug: bool = False
|
247
272
|
) -> float | None:
|
248
|
-
"""
|
249
|
-
除法, 除以 1024的次方
|
250
|
-
"""
|
273
|
+
"""Division (divisor: 1024*1024)"""
|
251
274
|
try:
|
252
275
|
return dividend / (1024 * 1024)
|
253
276
|
except Exception as e:
|
254
|
-
|
277
|
+
if v_true(debug, bool):
|
278
|
+
logger.exception(e)
|
255
279
|
return None
|
256
280
|
|
257
281
|
|
@@ -262,41 +286,50 @@ def check_file_type(
|
|
262
286
|
file_object: str,
|
263
287
|
file_type: str,
|
264
288
|
debug: bool = False
|
265
|
-
) -> bool
|
289
|
+
) -> bool:
|
266
290
|
"""
|
291
|
+
check file type
|
292
|
+
|
267
293
|
检查文件类型
|
268
|
-
|
269
|
-
|
294
|
+
|
295
|
+
file_object 文件对象
|
296
|
+
file_type 文件类型
|
270
297
|
"""
|
271
298
|
try:
|
299
|
+
|
272
300
|
_file_path = Path(file_object)
|
301
|
+
|
273
302
|
match True:
|
274
303
|
case True if _file_path.exists() is False:
|
275
|
-
|
304
|
+
result = False
|
276
305
|
case True if file_type == 'absolute' and _file_path.is_absolute() is True:
|
277
|
-
|
306
|
+
result = True
|
278
307
|
case True if file_type == 'block_device' and _file_path.is_block_device() is True:
|
279
|
-
|
308
|
+
result = True
|
280
309
|
case True if file_type == 'dir' and _file_path.is_dir() is True:
|
281
|
-
|
310
|
+
result = True
|
282
311
|
case True if file_type == 'fifo' and _file_path.is_fifo() is True:
|
283
|
-
|
312
|
+
result = True
|
284
313
|
case True if file_type == 'file' and _file_path.is_file() is True:
|
285
|
-
|
314
|
+
result = True
|
286
315
|
case True if file_type == 'mount' and _file_path.is_mount() is True:
|
287
|
-
|
316
|
+
result = True
|
288
317
|
case True if file_type == 'relative_to' and _file_path.is_relative_to() is True:
|
289
|
-
|
318
|
+
result = True
|
290
319
|
case True if file_type == 'reserved' and _file_path.is_reserved() is True:
|
291
|
-
|
320
|
+
result = True
|
292
321
|
case True if file_type == 'socket' and _file_path.is_socket() is True:
|
293
|
-
|
322
|
+
result = True
|
294
323
|
case True if file_type == 'symlink' and _file_path.is_symlink() is True:
|
295
|
-
|
324
|
+
result = True
|
296
325
|
case _:
|
297
|
-
|
326
|
+
result = False
|
327
|
+
|
328
|
+
return result
|
329
|
+
|
298
330
|
except Exception as e:
|
299
|
-
|
331
|
+
if v_true(debug, bool):
|
332
|
+
logger.exception(e)
|
300
333
|
return False
|
301
334
|
|
302
335
|
|
@@ -309,14 +342,11 @@ def list_sort(
|
|
309
342
|
debug: bool = False,
|
310
343
|
**kwargs
|
311
344
|
) -> list | None:
|
312
|
-
"""
|
313
|
-
列表排序, 示例: list_sort(['1.2.3.4', '2.3.4.5'], key=inet_aton)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
https://stackoverflow.com/a/4183538
|
318
|
-
https://blog.csdn.net/u013541325/article/details/117530957
|
319
|
-
"""
|
345
|
+
"""list sort"""
|
346
|
+
# 列表排序, 示例: list_sort(['1.2.3.4', '2.3.4.5'], key=inet_aton)
|
347
|
+
# 参考文档:
|
348
|
+
# https://stackoverflow.com/a/4183538
|
349
|
+
# https://blog.csdn.net/u013541325/article/details/117530957
|
320
350
|
try:
|
321
351
|
|
322
352
|
# from ipaddress import ip_address
|
@@ -331,7 +361,8 @@ def list_sort(
|
|
331
361
|
return _data
|
332
362
|
|
333
363
|
except Exception as e:
|
334
|
-
|
364
|
+
if v_true(debug, bool):
|
365
|
+
logger.exception(e)
|
335
366
|
return None
|
336
367
|
|
337
368
|
|
@@ -341,18 +372,15 @@ def list_dict_sorted_by_key(
|
|
341
372
|
debug: bool = False,
|
342
373
|
**kwargs
|
343
374
|
) -> list | None:
|
344
|
-
"""
|
345
|
-
列表字典排序
|
346
|
-
|
347
|
-
"""
|
348
|
-
参考文档:
|
349
|
-
https://stackoverflow.com/a/73050
|
350
|
-
"""
|
375
|
+
"""list dict sorted by key"""
|
376
|
+
# 列表字典排序
|
377
|
+
# 参考文档: https://stackoverflow.com/a/73050
|
351
378
|
try:
|
352
379
|
_data = deepcopy(data)
|
353
380
|
return sorted(_data, key=lambda x: x[key], **kwargs)
|
354
381
|
except Exception as e:
|
355
|
-
|
382
|
+
if v_true(debug, bool):
|
383
|
+
logger.exception(e)
|
356
384
|
return None
|
357
385
|
|
358
386
|
|
@@ -362,74 +390,94 @@ def list_split(
|
|
362
390
|
equally: bool = False,
|
363
391
|
debug: bool = False
|
364
392
|
) -> list | None:
|
365
|
-
"""
|
366
|
-
列表分割
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
393
|
+
"""list split"""
|
394
|
+
# 列表分割
|
395
|
+
#
|
396
|
+
# 默认: 将 list 以 number个元素为一个list 分割
|
397
|
+
#
|
398
|
+
# data = [1, 2, 3, 4, 5, 6, 7]
|
399
|
+
#
|
400
|
+
# list_split(data, 2) -> 将 data 以 2个元素为一个 list 分割
|
401
|
+
# [[1, 2], [3, 4], [5, 6], [7]]
|
402
|
+
#
|
403
|
+
# list_split(data, 3) -> 将 data 以 3个元素为一个 list 分割
|
404
|
+
# [[1, 2, 3], [4, 5, 6], [7]]
|
405
|
+
#
|
406
|
+
# equally 为 True 时, 将 data 平均分成 number 份
|
407
|
+
#
|
408
|
+
# data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
|
409
|
+
#
|
410
|
+
# list_split_equally(data, 5) -> 将 data 平均分成 5 份
|
411
|
+
# [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19]]
|
412
|
+
#
|
413
|
+
# list_split_equally(data, 6) -> 将 data 平均分成 6 份
|
414
|
+
# [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10], [11, 12, 13], [14, 15, 16], [17, 18, 19]]
|
415
|
+
#
|
416
|
+
# list_split_equally(data, 7) -> 将 data 平均分成 7 份
|
417
|
+
# [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17], [18, 19]]
|
372
418
|
|
373
|
-
list_split(data, 2) -> 将 data 以 2个元素为一个 list 分割
|
374
|
-
[[1, 2], [3, 4], [5, 6], [7]]
|
375
|
-
|
376
|
-
list_split(data, 3) -> 将 data 以 3个元素为一个 list 分割
|
377
|
-
[[1, 2, 3], [4, 5, 6], [7]]
|
378
|
-
|
379
|
-
equally 为 True 时, 将 data 平均分成 number 份
|
380
|
-
|
381
|
-
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
|
382
|
-
|
383
|
-
list_split_equally(data, 5) -> 将 data 平均分成 5 份
|
384
|
-
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19]]
|
385
|
-
|
386
|
-
list_split_equally(data, 6) -> 将 data 平均分成 6 份
|
387
|
-
[[1, 2, 3, 4], [5, 6, 7], [8, 9, 10], [11, 12, 13], [14, 15, 16], [17, 18, 19]]
|
388
|
-
|
389
|
-
list_split_equally(data, 7) -> 将 data 平均分成 7 份
|
390
|
-
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17], [18, 19]]
|
391
|
-
"""
|
392
419
|
try:
|
393
420
|
|
394
421
|
# 数据拷贝
|
395
422
|
_data_object = deepcopy(data)
|
423
|
+
|
396
424
|
# 数据长度
|
397
425
|
_data_length = len(_data_object)
|
426
|
+
|
398
427
|
# 数据平分后的结果
|
399
428
|
_data_result = []
|
400
429
|
|
430
|
+
_step_number: Optional[int] = None
|
431
|
+
|
401
432
|
if v_true(debug, bool):
|
402
433
|
logger.info(f"data object: {_data_object}")
|
403
434
|
logger.info(f"data length: {_data_length}")
|
404
435
|
|
405
436
|
if _data_length < number:
|
406
|
-
|
437
|
+
if v_true(debug, bool):
|
438
|
+
logger.error('number must greater than data length')
|
407
439
|
return None
|
408
|
-
|
440
|
+
|
441
|
+
if _data_length == number:
|
442
|
+
|
409
443
|
_data_result = [[i] for i in _data_object]
|
444
|
+
|
410
445
|
else:
|
411
446
|
|
412
447
|
if equally is True:
|
413
448
|
|
414
|
-
# 数据平分时, 每份数据的最大长度
|
415
449
|
_step_number = step_number_for_split_equally(_data_length, number, debug=debug)
|
416
|
-
|
450
|
+
|
451
|
+
if v_true(debug, bool):
|
452
|
+
logger.info(f"step number: {_step_number}")
|
453
|
+
|
417
454
|
if _data_length % number == 0:
|
455
|
+
|
418
456
|
index_number_list = list(range(0, _data_length, number))
|
419
|
-
|
457
|
+
|
458
|
+
if v_true(debug, bool):
|
459
|
+
logger.info(f"index number list: {index_number_list}")
|
460
|
+
|
420
461
|
for index_number in index_number_list:
|
421
|
-
|
462
|
+
|
463
|
+
if v_true(debug, bool):
|
464
|
+
logger.info(f"index: {index_number}, data: {_data_object[index_number:index_number + number]}")
|
465
|
+
|
422
466
|
_data_result.append(deepcopy(_data_object[index_number:index_number + number]))
|
467
|
+
|
423
468
|
else:
|
469
|
+
|
424
470
|
# 前一部分
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
471
|
+
if _step_number is not None:
|
472
|
+
previous_end_number = (_data_length % number) * _step_number
|
473
|
+
previous_index_number_list = list(range(0, previous_end_number, _step_number))
|
474
|
+
for index_number in previous_index_number_list:
|
475
|
+
_data_result.append(deepcopy(_data_object[index_number:index_number + _step_number]))
|
476
|
+
|
477
|
+
# 后一部分
|
478
|
+
next_number_list = list(range(previous_end_number, _data_length, _step_number - 1))
|
479
|
+
for index_number in next_number_list:
|
480
|
+
_data_result.append(deepcopy(_data_object[index_number:index_number + (_step_number - 1)]))
|
433
481
|
|
434
482
|
else:
|
435
483
|
|
@@ -439,7 +487,8 @@ def list_split(
|
|
439
487
|
return _data_result
|
440
488
|
|
441
489
|
except Exception as e:
|
442
|
-
|
490
|
+
if v_true(debug, bool):
|
491
|
+
logger.exception(e)
|
443
492
|
return None
|
444
493
|
|
445
494
|
|
@@ -450,15 +499,25 @@ def list_print_by_step(
|
|
450
499
|
debug: bool = False
|
451
500
|
) -> bool:
|
452
501
|
"""
|
502
|
+
list print by step
|
503
|
+
|
453
504
|
列表按照 步长 和 分隔符 有规律的输出
|
454
505
|
"""
|
455
506
|
try:
|
507
|
+
|
456
508
|
_data_list = list_split(data, number, debug=debug)
|
509
|
+
|
510
|
+
if _data_list is None:
|
511
|
+
return False
|
512
|
+
|
457
513
|
for _item in _data_list:
|
458
514
|
print(*_item, sep=separator)
|
515
|
+
|
459
516
|
return True
|
517
|
+
|
460
518
|
except Exception as e:
|
461
|
-
|
519
|
+
if v_true(debug, bool):
|
520
|
+
logger.exception(e)
|
462
521
|
return False
|
463
522
|
|
464
523
|
|
@@ -467,12 +526,14 @@ def list_remove_list(
|
|
467
526
|
remove: list,
|
468
527
|
debug: bool = False
|
469
528
|
) -> list | None:
|
529
|
+
"""List remove List"""
|
470
530
|
try:
|
471
531
|
_original = deepcopy(original)
|
472
532
|
_remove = deepcopy(remove)
|
473
533
|
return [i for i in _original if i not in _remove]
|
474
534
|
except Exception as e:
|
475
|
-
|
535
|
+
if v_true(debug, bool):
|
536
|
+
logger.exception(e)
|
476
537
|
return None
|
477
538
|
|
478
539
|
|
@@ -480,14 +541,16 @@ def list_merge(
|
|
480
541
|
data: list,
|
481
542
|
debug: bool = False
|
482
543
|
) -> list | None:
|
483
|
-
"""
|
544
|
+
"""list merge"""
|
545
|
+
# 合并 List 中的 List 为一个 List
|
484
546
|
try:
|
485
547
|
_results = []
|
486
548
|
for i in deepcopy(data):
|
487
549
|
_results += i
|
488
550
|
return _results
|
489
551
|
except Exception as e:
|
490
|
-
|
552
|
+
if v_true(debug, bool):
|
553
|
+
logger.exception(e)
|
491
554
|
return None
|
492
555
|
|
493
556
|
|
@@ -497,13 +560,15 @@ def list_to_file(
|
|
497
560
|
encoding: str = 'utf-8-sig',
|
498
561
|
debug: bool = False
|
499
562
|
) -> bool:
|
563
|
+
"""list to file"""
|
500
564
|
try:
|
501
565
|
with open(file, 'w', encoding=encoding) as _file:
|
502
566
|
for line in data:
|
503
567
|
_file.write(f"{line}\n")
|
504
568
|
return True
|
505
569
|
except Exception as e:
|
506
|
-
|
570
|
+
if v_true(debug, bool):
|
571
|
+
logger.exception(e)
|
507
572
|
return False
|
508
573
|
|
509
574
|
def list_to_csvfile(
|
@@ -514,17 +579,19 @@ def list_to_csvfile(
|
|
514
579
|
debug: bool = False,
|
515
580
|
**kwargs
|
516
581
|
) -> bool:
|
582
|
+
"""list to csvfile"""
|
517
583
|
try:
|
518
584
|
with open(file, 'w', encoding=encoding) as _file:
|
519
585
|
# CRLF replaced by LF
|
520
586
|
# https://stackoverflow.com/a/29976091
|
521
587
|
outcsv = csv.writer(_file, lineterminator=os.linesep, **kwargs)
|
522
|
-
if v_true(fields, list):
|
588
|
+
if v_true(fields, list) and fields is not None:
|
523
589
|
outcsv.writerow(fields)
|
524
590
|
outcsv.writerows(data)
|
525
591
|
return True
|
526
592
|
except Exception as e:
|
527
|
-
|
593
|
+
if v_true(debug, bool):
|
594
|
+
logger.exception(e)
|
528
595
|
return False
|
529
596
|
|
530
597
|
def range_zfill(
|
@@ -534,7 +601,8 @@ def range_zfill(
|
|
534
601
|
width: int,
|
535
602
|
debug: bool = False
|
536
603
|
) -> list | None:
|
537
|
-
"""
|
604
|
+
"""range zfill"""
|
605
|
+
# 生成长度相同的字符串的列表
|
538
606
|
# 示例: range_zfill(8, 13, 1, 2) => ['08', '09', '10', '11', '12']
|
539
607
|
# 生成 小时 列表: range_zfill(0, 24, 1, 2)
|
540
608
|
# 生成 分钟和秒 列表: range_zfill(0, 60, 1, 2)
|
@@ -543,7 +611,8 @@ def range_zfill(
|
|
543
611
|
try:
|
544
612
|
return [str(i).zfill(width) for i in range(start, stop, step)]
|
545
613
|
except Exception as e:
|
546
|
-
|
614
|
+
if v_true(debug, bool):
|
615
|
+
logger.exception(e)
|
547
616
|
return None
|
548
617
|
|
549
618
|
|
@@ -555,12 +624,14 @@ def dict_remove_key(
|
|
555
624
|
key: str,
|
556
625
|
debug: bool = False
|
557
626
|
) -> None | dict:
|
627
|
+
"""dict remove key"""
|
558
628
|
try:
|
559
629
|
data_copy: dict = deepcopy(data)
|
560
630
|
data_copy.pop(key)
|
561
631
|
return data_copy
|
562
632
|
except Exception as e:
|
563
|
-
|
633
|
+
if v_true(debug, bool):
|
634
|
+
logger.exception(e)
|
564
635
|
return None
|
565
636
|
|
566
637
|
def dict_to_file(
|
@@ -570,47 +641,52 @@ def dict_to_file(
|
|
570
641
|
debug: bool = False,
|
571
642
|
**kwargs
|
572
643
|
) -> bool:
|
644
|
+
"""dict to file"""
|
573
645
|
try:
|
574
646
|
with open(file, 'w', encoding=encoding) as _file:
|
575
647
|
json.dump(obj=data, fp=_file, indent=4, sort_keys=True, **kwargs)
|
576
648
|
return True
|
577
649
|
except Exception as e:
|
578
|
-
|
650
|
+
if v_true(debug, bool):
|
651
|
+
logger.exception(e)
|
579
652
|
return False
|
580
653
|
|
581
654
|
|
582
655
|
def dict_nested_update(
|
583
656
|
data: dict,
|
584
657
|
key: str,
|
585
|
-
value:
|
658
|
+
value: Any,
|
586
659
|
debug: bool = False
|
587
660
|
) -> bool:
|
588
|
-
"""
|
589
|
-
dictionary nested update
|
590
|
-
https://stackoverflow.com/a/58885744
|
591
|
-
"""
|
661
|
+
"""dict nested update"""
|
662
|
+
# dictionary nested update
|
663
|
+
# https://stackoverflow.com/a/58885744
|
592
664
|
try:
|
593
|
-
|
594
|
-
|
595
|
-
# callable() 判断是非为 function
|
596
|
-
if (key is not None and key == _k) or (callable(key) is True and key() == _k):
|
597
|
-
if callable(value) is True:
|
598
|
-
data[_k] = value()
|
599
|
-
else:
|
600
|
-
data[_k] = value
|
601
|
-
elif isinstance(_v, dict) is True:
|
602
|
-
dict_nested_update(_v, key, value)
|
603
|
-
elif isinstance(_v, list) is True:
|
604
|
-
for _o in _v:
|
605
|
-
if isinstance(_o, dict):
|
606
|
-
dict_nested_update(_o, key, value)
|
607
|
-
else:
|
608
|
-
pass
|
609
|
-
else:
|
665
|
+
|
666
|
+
if not v_true(data, dict, debug=debug):
|
610
667
|
return False
|
668
|
+
|
669
|
+
for _k, _v in data.items():
|
670
|
+
# callable() 判断是非为 function
|
671
|
+
if (key is not None and key == _k) or (callable(key) is True and key == _k):
|
672
|
+
if callable(value) is True:
|
673
|
+
data[_k] = value()
|
674
|
+
else:
|
675
|
+
data[_k] = value
|
676
|
+
elif isinstance(_v, dict) is True:
|
677
|
+
dict_nested_update(_v, key, value)
|
678
|
+
elif isinstance(_v, list) is True:
|
679
|
+
for _o in _v:
|
680
|
+
if isinstance(_o, dict):
|
681
|
+
dict_nested_update(_o, key, value)
|
682
|
+
else:
|
683
|
+
pass
|
684
|
+
|
611
685
|
return True
|
686
|
+
|
612
687
|
except Exception as e:
|
613
|
-
|
688
|
+
if v_true(debug, bool):
|
689
|
+
logger.exception(e)
|
614
690
|
return False
|
615
691
|
|
616
692
|
|
@@ -622,23 +698,32 @@ def filename(
|
|
622
698
|
split: str = '.',
|
623
699
|
debug: bool = False
|
624
700
|
) -> str | None:
|
625
|
-
"""
|
626
|
-
|
627
|
-
https://stackoverflow.com/questions/678236/how-do-i-get-the-filename-without-the-extension-from-a-path-in-python
|
628
|
-
https://stackoverflow.com/questions/4152963/get-name-of-current-script-in-python
|
629
|
-
'''
|
701
|
+
"""filename"""
|
702
|
+
# 获取文件名称
|
703
|
+
# https://stackoverflow.com/questions/678236/how-do-i-get-the-filename-without-the-extension-from-a-path-in-python
|
704
|
+
# https://stackoverflow.com/questions/4152963/get-name-of-current-script-in-python
|
630
705
|
try:
|
706
|
+
|
631
707
|
if v_true(debug, bool):
|
632
708
|
logger.info(f"file: {file}")
|
633
709
|
logger.info(f"split: {split}")
|
710
|
+
|
634
711
|
_basename = str(os.path.basename(file))
|
635
|
-
|
712
|
+
|
713
|
+
if v_true(debug, bool):
|
714
|
+
logger.info(f"basename: {_basename}")
|
715
|
+
|
636
716
|
_index_of_split = _basename.index(split)
|
637
|
-
|
638
|
-
|
717
|
+
|
718
|
+
if v_true(debug, bool):
|
719
|
+
logger.info(f"index of split: {_index_of_split}")
|
720
|
+
logger.info(f"filename: {_basename[:_index_of_split]}")
|
721
|
+
|
639
722
|
return _basename[:_index_of_split]
|
723
|
+
|
640
724
|
except Exception as e:
|
641
|
-
|
725
|
+
if v_true(debug, bool):
|
726
|
+
logger.exception(e)
|
642
727
|
return None
|
643
728
|
|
644
729
|
|
@@ -647,12 +732,11 @@ def filehash(
|
|
647
732
|
sha: str = 'md5',
|
648
733
|
debug: bool = False
|
649
734
|
) -> str | None:
|
650
|
-
"""
|
651
|
-
|
652
|
-
参考文档:
|
653
|
-
|
654
|
-
|
655
|
-
"""
|
735
|
+
"""filehash"""
|
736
|
+
# 获取文件Hash
|
737
|
+
# 参考文档:
|
738
|
+
# https://stackoverflow.com/a/59056837
|
739
|
+
# https://stackoverflow.com/questions/22058048/hashing-a-file-in-python
|
656
740
|
try:
|
657
741
|
with open(file, "rb") as _file:
|
658
742
|
match True:
|
@@ -674,10 +758,10 @@ def filehash(
|
|
674
758
|
file_hash = hashlib.sha3_384()
|
675
759
|
case True if sha == 'sha3_512':
|
676
760
|
file_hash = hashlib.sha3_512()
|
677
|
-
case True if sha == 'shake_128':
|
678
|
-
|
679
|
-
case True if sha == 'shake_256':
|
680
|
-
|
761
|
+
# case True if sha == 'shake_128':
|
762
|
+
# file_hash = hashlib.shake_128()
|
763
|
+
# case True if sha == 'shake_256':
|
764
|
+
# file_hash = hashlib.shake_256()
|
681
765
|
case _:
|
682
766
|
file_hash = hashlib.md5()
|
683
767
|
# 建议设置为和 block size 相同的值, 多数系统默认为 4096, 可使用 stat 命令查看
|
@@ -687,7 +771,8 @@ def filehash(
|
|
687
771
|
file_hash.update(chunk)
|
688
772
|
return file_hash.hexdigest()
|
689
773
|
except Exception as e:
|
690
|
-
|
774
|
+
if v_true(debug, bool):
|
775
|
+
logger.exception(e)
|
691
776
|
return None
|
692
777
|
|
693
778
|
|
@@ -695,11 +780,13 @@ def filesize(
|
|
695
780
|
file: str,
|
696
781
|
debug: bool = False
|
697
782
|
) -> int | None:
|
698
|
-
"""
|
783
|
+
"""filesize"""
|
784
|
+
# 获取文件大小
|
699
785
|
try:
|
700
786
|
return os.path.getsize(file)
|
701
787
|
except Exception as e:
|
702
|
-
|
788
|
+
if v_true(debug, bool):
|
789
|
+
logger.exception(e)
|
703
790
|
return None
|
704
791
|
|
705
792
|
|
@@ -707,7 +794,8 @@ def filesize(
|
|
707
794
|
|
708
795
|
|
709
796
|
def resolve_path() -> str | None:
|
710
|
-
"""
|
797
|
+
"""resolve path"""
|
798
|
+
# 获取当前目录名称
|
711
799
|
return str(Path().resolve())
|
712
800
|
|
713
801
|
|
@@ -720,7 +808,8 @@ def parent_path(
|
|
720
808
|
try:
|
721
809
|
return str(Path(path, **kwargs).parent.resolve()) if v_true(path, str, debug=debug) else None
|
722
810
|
except Exception as e:
|
723
|
-
|
811
|
+
if v_true(debug, bool):
|
812
|
+
logger.exception(e)
|
724
813
|
return None
|
725
814
|
|
726
815
|
|
@@ -731,10 +820,12 @@ def real_path(
|
|
731
820
|
) -> str | None:
|
732
821
|
"""获取真实路径"""
|
733
822
|
try:
|
734
|
-
|
823
|
+
if v_true(debug, bool):
|
824
|
+
logger.info(f"path: {path}")
|
735
825
|
return os.path.realpath(path, **kwargs)
|
736
826
|
except Exception as e:
|
737
|
-
|
827
|
+
if v_true(debug, bool):
|
828
|
+
logger.exception(e)
|
738
829
|
return None
|
739
830
|
|
740
831
|
|
@@ -748,10 +839,8 @@ def retry(
|
|
748
839
|
**kwargs
|
749
840
|
):
|
750
841
|
"""重试"""
|
751
|
-
|
752
|
-
|
753
|
-
callable() 判断类型是非为函数: https://stackoverflow.com/a/624939
|
754
|
-
"""
|
842
|
+
# 函数传递参数: https://stackoverflow.com/a/803632
|
843
|
+
# callable() 判断类型是非为函数: https://stackoverflow.com/a/624939
|
755
844
|
try:
|
756
845
|
_num = 0
|
757
846
|
while True:
|
@@ -764,61 +853,60 @@ def retry(
|
|
764
853
|
try:
|
765
854
|
return func(**kwargs)
|
766
855
|
except Exception as e:
|
767
|
-
|
856
|
+
if v_true(debug, bool):
|
857
|
+
logger.exception(e)
|
768
858
|
logger.success('retrying ...')
|
769
859
|
continue
|
770
860
|
# break
|
771
861
|
except Exception as e:
|
772
|
-
|
862
|
+
if v_true(debug, bool):
|
863
|
+
logger.exception(e)
|
773
864
|
|
774
865
|
|
775
866
|
# --------------------------------------------------------------------------------------------------
|
776
867
|
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
Unix Timestamp
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
datetime.fromisoformat(time.strftime(format, time.gmtime(dt)))
|
821
|
-
"""
|
868
|
+
# 日期时间有两种: UTC datetime (UTC时区日期时间) 和 Local datetime (当前时区日期时间)
|
869
|
+
#
|
870
|
+
# Unix Timestamp 仅为 UTC datetime 的值
|
871
|
+
#
|
872
|
+
# 但是, Local datetime 可以直接转换为 Unix Timestamp, UTC datetime 需要先转换到 UTC TimeZone 再转换为 Unix Timestamp
|
873
|
+
#
|
874
|
+
# 相反, Unix Timestamp 可以直接转换为 UTC datetime, 要获得 Local datetime, 需要再将 UTC datetime 转换为 Local datetime
|
875
|
+
#
|
876
|
+
# https://stackoverflow.com/a/13287083
|
877
|
+
# https://stackoverflow.com/a/466376
|
878
|
+
# https://stackoverflow.com/a/7999977
|
879
|
+
# https://stackoverflow.com/a/3682808
|
880
|
+
# https://stackoverflow.com/a/63920772
|
881
|
+
# https://www.geeksforgeeks.org/how-to-remove-timezone-information-from-datetime-object-in-python/
|
882
|
+
#
|
883
|
+
# pytz all timezones
|
884
|
+
#
|
885
|
+
# https://stackoverflow.com/a/13867319
|
886
|
+
# https://stackoverflow.com/a/15692958
|
887
|
+
#
|
888
|
+
# import pytz
|
889
|
+
# pytz.all_timezones
|
890
|
+
# pytz.common_timezones
|
891
|
+
# pytz.timezone('US/Eastern')
|
892
|
+
#
|
893
|
+
# timezone
|
894
|
+
#
|
895
|
+
# https://stackoverflow.com/a/39079819
|
896
|
+
# https://stackoverflow.com/a/1681600
|
897
|
+
# https://stackoverflow.com/a/4771733
|
898
|
+
# https://stackoverflow.com/a/63920772
|
899
|
+
# https://toutiao.io/posts/sin4x0/preview
|
900
|
+
#
|
901
|
+
# 其它:
|
902
|
+
#
|
903
|
+
# dt.replace(tzinfo=timezone.utc).astimezone(tz=None)
|
904
|
+
#
|
905
|
+
# (dt.replace(tzinfo=timezone.utc).astimezone(tz=None)).strftime(format)
|
906
|
+
# datetime.fromisoformat((dt.replace(tzinfo=timezone.utc).astimezone(tz=None)).strftime(format))
|
907
|
+
# string_to_datetime((dt.replace(tzinfo=timezone.utc).astimezone(tz=None)).strftime(format), format)
|
908
|
+
#
|
909
|
+
# datetime.fromisoformat(time.strftime(format, time.gmtime(dt)))
|
822
910
|
|
823
911
|
|
824
912
|
def date_to_datetime(
|
@@ -830,20 +918,22 @@ def date_to_datetime(
|
|
830
918
|
try:
|
831
919
|
return datetime.datetime.combine(date_object, datetime.datetime.min.time())
|
832
920
|
except Exception as e:
|
833
|
-
|
921
|
+
if v_true(debug, bool):
|
922
|
+
logger.exception(e)
|
834
923
|
return None
|
835
924
|
|
836
925
|
|
837
926
|
def datetime_to_date(
|
838
|
-
|
927
|
+
datetime_instance: datetime.datetime,
|
839
928
|
debug: bool = False
|
840
929
|
) -> datetime.date | None:
|
841
930
|
"""'日期时间'转换为'日期'"""
|
842
931
|
# https://stackoverflow.com/a/3743240
|
843
932
|
try:
|
844
|
-
return
|
933
|
+
return datetime_instance.date()
|
845
934
|
except Exception as e:
|
846
|
-
|
935
|
+
if v_true(debug, bool):
|
936
|
+
logger.exception(e)
|
847
937
|
return None
|
848
938
|
|
849
939
|
|
@@ -861,12 +951,13 @@ def datetime_now(
|
|
861
951
|
try:
|
862
952
|
return datetime.datetime.utcnow() if _utc is True else datetime.datetime.now(**kwargs)
|
863
953
|
except Exception as e:
|
864
|
-
|
954
|
+
if v_true(debug, bool):
|
955
|
+
logger.exception(e)
|
865
956
|
return None
|
866
957
|
|
867
958
|
|
868
959
|
def datetime_offset(
|
869
|
-
|
960
|
+
datetime_instance: datetime.datetime,
|
870
961
|
debug: bool = False,
|
871
962
|
**kwargs
|
872
963
|
) -> datetime.datetime | None:
|
@@ -877,30 +968,31 @@ def datetime_offset(
|
|
877
968
|
"""
|
878
969
|
_utc = kwargs.pop("utc", False)
|
879
970
|
try:
|
880
|
-
if isinstance(
|
881
|
-
return
|
882
|
-
else
|
883
|
-
return datetime.datetime.utcnow() + datetime.timedelta(**kwargs) if _utc is True else datetime.datetime.now() + datetime.timedelta(**kwargs)
|
971
|
+
if isinstance(datetime_instance, datetime.datetime):
|
972
|
+
return datetime_instance + datetime.timedelta(**kwargs)
|
973
|
+
return datetime.datetime.utcnow() + datetime.timedelta(**kwargs) if _utc is True else datetime.datetime.now() + datetime.timedelta(**kwargs)
|
884
974
|
except Exception as e:
|
885
|
-
|
975
|
+
if v_true(debug, bool):
|
976
|
+
logger.exception(e)
|
886
977
|
return None
|
887
978
|
|
888
979
|
|
889
980
|
def datetime_to_string(
|
890
|
-
|
981
|
+
datetime_instance: datetime.datetime,
|
891
982
|
string_format: str = '%Y-%m-%d %H:%M:%S',
|
892
983
|
debug: bool = False
|
893
984
|
) -> str | None:
|
894
985
|
"""'日期时间'转换为'字符串'"""
|
895
986
|
try:
|
896
|
-
return datetime.datetime.strftime(
|
987
|
+
return datetime.datetime.strftime(datetime_instance, string_format) if isinstance(datetime_instance, datetime.datetime) is True else None
|
897
988
|
except Exception as e:
|
898
|
-
|
989
|
+
if v_true(debug, bool):
|
990
|
+
logger.exception(e)
|
899
991
|
return None
|
900
992
|
|
901
993
|
|
902
994
|
def datetime_to_timestamp(
|
903
|
-
|
995
|
+
datetime_instance: datetime.datetime,
|
904
996
|
utc: bool = False,
|
905
997
|
debug: bool = False
|
906
998
|
) -> int | None:
|
@@ -910,17 +1002,17 @@ def datetime_to_timestamp(
|
|
910
1002
|
UTC datetime 需要先替换 timezone 再转换为 Unix Timestamp
|
911
1003
|
"""
|
912
1004
|
try:
|
913
|
-
if isinstance(
|
914
|
-
return int(
|
915
|
-
|
916
|
-
return None
|
1005
|
+
if isinstance(datetime_instance, datetime.datetime):
|
1006
|
+
return int(datetime_instance.replace(tzinfo=datetime.timezone.utc).timestamp()) if utc is True else int(datetime_instance.timestamp())
|
1007
|
+
return None
|
917
1008
|
except Exception as e:
|
918
|
-
|
1009
|
+
if v_true(debug, bool):
|
1010
|
+
logger.exception(e)
|
919
1011
|
return None
|
920
1012
|
|
921
1013
|
|
922
1014
|
def datetime_local_to_timezone(
|
923
|
-
|
1015
|
+
datetime_instance: datetime.datetime,
|
924
1016
|
tz: datetime.timezone = datetime.timezone.utc,
|
925
1017
|
debug: bool = False
|
926
1018
|
) -> datetime.datetime | None:
|
@@ -929,18 +1021,19 @@ def datetime_local_to_timezone(
|
|
929
1021
|
replace(tzinfo=None) 移除结尾的时区信息
|
930
1022
|
"""
|
931
1023
|
try:
|
932
|
-
if isinstance(
|
933
|
-
return (datetime.datetime.fromtimestamp(
|
1024
|
+
if isinstance(datetime_instance, datetime.datetime) is True:
|
1025
|
+
return (datetime.datetime.fromtimestamp(datetime_instance.timestamp(), tz=tz)).replace(tzinfo=None)
|
934
1026
|
else:
|
935
1027
|
return None
|
936
1028
|
except Exception as e:
|
937
|
-
|
1029
|
+
if v_true(debug, bool):
|
1030
|
+
logger.exception(e)
|
938
1031
|
return None
|
939
1032
|
|
940
1033
|
|
941
1034
|
def datetime_utc_to_timezone(
|
942
|
-
|
943
|
-
tz:
|
1035
|
+
datetime_instance: datetime.datetime,
|
1036
|
+
tz: Any = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo,
|
944
1037
|
debug: bool = False
|
945
1038
|
) -> datetime.datetime | None:
|
946
1039
|
"""
|
@@ -948,12 +1041,13 @@ def datetime_utc_to_timezone(
|
|
948
1041
|
replace(tzinfo=None) 移除结尾的时区信息
|
949
1042
|
"""
|
950
1043
|
try:
|
951
|
-
if isinstance(
|
952
|
-
return
|
1044
|
+
if isinstance(datetime_instance, datetime.datetime) is True:
|
1045
|
+
return datetime_instance.replace(tzinfo=datetime.timezone.utc).astimezone(tz).replace(tzinfo=None)
|
953
1046
|
else:
|
954
1047
|
return None
|
955
1048
|
except Exception as e:
|
956
|
-
|
1049
|
+
if v_true(debug, bool):
|
1050
|
+
logger.exception(e)
|
957
1051
|
return None
|
958
1052
|
|
959
1053
|
|
@@ -966,7 +1060,8 @@ def timestamp_to_datetime(
|
|
966
1060
|
try:
|
967
1061
|
return (datetime.datetime.fromtimestamp(timestamp, tz=tz)).replace(tzinfo=None) if v_true(timestamp, int, debug=debug) else None
|
968
1062
|
except Exception as e:
|
969
|
-
|
1063
|
+
if v_true(debug, bool):
|
1064
|
+
logger.exception(e)
|
970
1065
|
return None
|
971
1066
|
|
972
1067
|
|
@@ -975,10 +1070,12 @@ def datetime_string_to_datetime(
|
|
975
1070
|
datetime_format: str = '%Y-%m-%d %H:%M:%S',
|
976
1071
|
debug: bool = False
|
977
1072
|
) -> datetime.datetime | None:
|
1073
|
+
"""datetime string to datetime"""
|
978
1074
|
try:
|
979
1075
|
return datetime.datetime.strptime(datetime_string, datetime_format) if v_true(datetime_string, str, debug=debug) else None
|
980
1076
|
except Exception as e:
|
981
|
-
|
1077
|
+
if v_true(debug, bool):
|
1078
|
+
logger.exception(e)
|
982
1079
|
return None
|
983
1080
|
|
984
1081
|
|
@@ -987,10 +1084,12 @@ def datetime_string_to_timestamp(
|
|
987
1084
|
datetime_format: str = '%Y-%m-%d %H:%M:%S',
|
988
1085
|
debug: bool = False
|
989
1086
|
) -> int | None:
|
1087
|
+
"""datetime string to timestamp"""
|
990
1088
|
try:
|
991
1089
|
return int(time.mktime(time.strptime(datetime_string, datetime_format))) if v_true(datetime_string, str, debug=debug) else None
|
992
1090
|
except Exception as e:
|
993
|
-
|
1091
|
+
if v_true(debug, bool):
|
1092
|
+
logger.exception(e)
|
994
1093
|
return None
|
995
1094
|
|
996
1095
|
|
@@ -998,6 +1097,7 @@ def datetime_object(
|
|
998
1097
|
date_time: datetime.datetime,
|
999
1098
|
debug: bool = False
|
1000
1099
|
) -> dict | None:
|
1100
|
+
"""datetime object"""
|
1001
1101
|
try:
|
1002
1102
|
return {
|
1003
1103
|
'date': date_time.strftime("%Y-%m-%d"),
|
@@ -1008,31 +1108,30 @@ def datetime_object(
|
|
1008
1108
|
'datetime_zero': date_time.strftime('%Y-%m-%d 00:00:00')
|
1009
1109
|
}
|
1010
1110
|
except Exception as e:
|
1011
|
-
|
1111
|
+
if v_true(debug, bool):
|
1112
|
+
logger.exception(e)
|
1012
1113
|
return None
|
1013
1114
|
|
1014
1115
|
|
1015
1116
|
# --------------------------------------------------------------------------------------------------
|
1016
1117
|
|
1017
1118
|
|
1018
|
-
''
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
#
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
print(outputs, type(outputs))
|
1035
|
-
'''
|
1119
|
+
# run_cmd = bash('echo ok', universal_newlines=True, stdout=PIPE)
|
1120
|
+
#
|
1121
|
+
# if run_cmd != None:
|
1122
|
+
# returncode = run_cmd.returncode
|
1123
|
+
# outputs = run_cmd.stdout.splitlines()
|
1124
|
+
# print(returncode, type(returncode))
|
1125
|
+
# print(outputs, type(outputs))
|
1126
|
+
#
|
1127
|
+
# # echo 'echo ok' > /tmp/ok.sh
|
1128
|
+
# run_script = bash('/tmp/ok.sh', file=True, universal_newlines=True, stdout=PIPE)
|
1129
|
+
#
|
1130
|
+
# if run_script != None:
|
1131
|
+
# returncode = run_script.returncode
|
1132
|
+
# outputs = run_script.stdout.splitlines()
|
1133
|
+
# print(returncode, type(returncode))
|
1134
|
+
# print(outputs, type(outputs))
|
1036
1135
|
|
1037
1136
|
|
1038
1137
|
def shell(
|
@@ -1050,18 +1149,17 @@ def shell(
|
|
1050
1149
|
return None
|
1051
1150
|
case True if v_true(sh_shell, str, debug=debug) and v_true(command, str, debug=debug):
|
1052
1151
|
if isfile is True:
|
1053
|
-
if sh_option
|
1054
|
-
return subprocess.run([sh_shell, command], **kwargs)
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
sh_option = '-c'
|
1060
|
-
return subprocess.run([sh_shell, sh_option, command], **kwargs)
|
1152
|
+
if sh_option is None:
|
1153
|
+
return subprocess.run([sh_shell, command], **kwargs, check=False)
|
1154
|
+
return subprocess.run([sh_shell, sh_option, command], **kwargs, check=False)
|
1155
|
+
if sh_option is None:
|
1156
|
+
sh_option = '-c'
|
1157
|
+
return subprocess.run([sh_shell, sh_option, command], **kwargs, check=False)
|
1061
1158
|
case _:
|
1062
1159
|
return None
|
1063
1160
|
except Exception as e:
|
1064
|
-
|
1161
|
+
if v_true(debug, bool):
|
1162
|
+
logger.exception(e)
|
1065
1163
|
return None
|
1066
1164
|
|
1067
1165
|
|
@@ -1072,50 +1170,50 @@ def json_file_parser(
|
|
1072
1170
|
file: str,
|
1073
1171
|
debug: bool = False
|
1074
1172
|
) -> dict | None:
|
1173
|
+
"""JSON File Parser"""
|
1075
1174
|
try:
|
1076
1175
|
if check_file_type(file, 'file', debug=debug):
|
1077
|
-
with open(file) as json_raw:
|
1176
|
+
with open(file, encoding="utf-8") as json_raw:
|
1078
1177
|
json_dict = json.load(json_raw)
|
1079
1178
|
return json_dict
|
1080
|
-
|
1081
|
-
logger.error(f"No such file: {file}")
|
1082
|
-
|
1179
|
+
if v_true(debug, bool):
|
1180
|
+
logger.error(f"No such file: {file}")
|
1181
|
+
return None
|
1083
1182
|
except Exception as e:
|
1084
|
-
|
1183
|
+
if v_true(debug, bool):
|
1184
|
+
logger.exception(e)
|
1085
1185
|
return None
|
1086
1186
|
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
"markdown.preview.fontSize": 14,
|
1105
|
-
"workbench.iconTheme": "vscode-icons"
|
1106
|
-
}
|
1107
|
-
"""
|
1187
|
+
# json_raw = '''
|
1188
|
+
# {
|
1189
|
+
# "markdown.preview.fontSize": 14,
|
1190
|
+
# "editor.minimap.enabled": false,
|
1191
|
+
# "workbench.iconTheme": "vscode-icons",
|
1192
|
+
# "http.proxy": "http://127.0.0.1:1087"
|
1193
|
+
# }
|
1194
|
+
# '''
|
1195
|
+
#
|
1196
|
+
# print(json_sort(json_raw))
|
1197
|
+
#
|
1198
|
+
# {
|
1199
|
+
# "editor.minimap.enabled": false,
|
1200
|
+
# "http.proxy": "http://127.0.0.1:1087",
|
1201
|
+
# "markdown.preview.fontSize": 14,
|
1202
|
+
# "workbench.iconTheme": "vscode-icons"
|
1203
|
+
# }
|
1108
1204
|
|
1109
1205
|
|
1110
1206
|
def json_sort(
|
1111
1207
|
string: str,
|
1112
1208
|
debug: bool = False,
|
1113
1209
|
**kwargs
|
1114
|
-
) ->
|
1210
|
+
) -> str | None:
|
1211
|
+
"""JSON Sort"""
|
1115
1212
|
try:
|
1116
1213
|
return json.dumps(json.loads(string), indent=4, sort_keys=True, **kwargs) if v_true(string, str, debug=debug) else None
|
1117
1214
|
except Exception as e:
|
1118
|
-
|
1215
|
+
if v_true(debug, bool):
|
1216
|
+
logger.exception(e)
|
1119
1217
|
return None
|
1120
1218
|
|
1121
1219
|
|
@@ -1123,45 +1221,47 @@ def json_sort(
|
|
1123
1221
|
|
1124
1222
|
|
1125
1223
|
def delete_files(
|
1126
|
-
files: str
|
1224
|
+
files: Union[str, List],
|
1127
1225
|
debug: bool = False
|
1128
1226
|
) -> bool:
|
1129
1227
|
"""删除文件"""
|
1130
1228
|
try:
|
1131
1229
|
|
1132
|
-
if
|
1230
|
+
if isinstance(files, str) and check_file_type(files, 'file', debug=debug):
|
1133
1231
|
|
1134
1232
|
os.remove(files)
|
1135
|
-
|
1233
|
+
if v_true(debug, bool):
|
1234
|
+
logger.success(f'deleted file: {files}')
|
1136
1235
|
return True
|
1137
1236
|
|
1138
|
-
|
1237
|
+
if v_true(files, list, debug=debug):
|
1139
1238
|
|
1140
1239
|
for _file in files:
|
1141
1240
|
|
1142
1241
|
if v_true(_file, str, debug=debug) and check_file_type(_file, 'file', debug=debug):
|
1143
1242
|
try:
|
1144
1243
|
os.remove(_file)
|
1145
|
-
logger.success('deleted file: {}'
|
1244
|
+
logger.success(f'deleted file: {_file}')
|
1146
1245
|
except Exception as e:
|
1147
|
-
logger.error('error file: {} {}'
|
1246
|
+
logger.error(f'error file: {_file} {e}')
|
1148
1247
|
else:
|
1149
|
-
logger.error('error file: {}'
|
1248
|
+
logger.error(f'error file: {_file}')
|
1150
1249
|
|
1151
1250
|
return True
|
1152
1251
|
|
1153
|
-
|
1252
|
+
if v_true(debug, bool):
|
1253
|
+
logger.error(f'error file: {files}')
|
1154
1254
|
|
1155
|
-
|
1156
|
-
return False
|
1255
|
+
return False
|
1157
1256
|
|
1158
1257
|
except Exception as e:
|
1159
|
-
|
1258
|
+
if v_true(debug, bool):
|
1259
|
+
logger.exception(e)
|
1160
1260
|
return False
|
1161
1261
|
|
1162
1262
|
|
1163
1263
|
def delete_directory(
|
1164
|
-
directory: str
|
1264
|
+
directory: Union[str, List],
|
1165
1265
|
debug: bool = False
|
1166
1266
|
) -> bool:
|
1167
1267
|
"""
|
@@ -1189,10 +1289,13 @@ def delete_directory(
|
|
1189
1289
|
"""
|
1190
1290
|
try:
|
1191
1291
|
|
1192
|
-
if
|
1292
|
+
if isinstance(directory, str) and check_file_type(directory, 'dir', debug=debug):
|
1193
1293
|
|
1194
1294
|
rmtree(directory)
|
1195
|
-
|
1295
|
+
|
1296
|
+
if v_true(debug, bool):
|
1297
|
+
logger.success(f'deleted directory: {directory}')
|
1298
|
+
|
1196
1299
|
return True
|
1197
1300
|
|
1198
1301
|
elif v_true(directory, list, debug=debug):
|
@@ -1202,21 +1305,25 @@ def delete_directory(
|
|
1202
1305
|
if v_true(_dir, str, debug=debug) and check_file_type(_dir, 'dir', debug=debug):
|
1203
1306
|
try:
|
1204
1307
|
rmtree(_dir)
|
1205
|
-
|
1308
|
+
if v_true(debug, bool):
|
1309
|
+
logger.success(f'deleted directory: {_dir}')
|
1206
1310
|
except Exception as e:
|
1207
|
-
|
1311
|
+
if v_true(debug, bool):
|
1312
|
+
logger.error(f'error directory: {_dir} {e}')
|
1208
1313
|
else:
|
1209
|
-
|
1314
|
+
if v_true(debug, bool):
|
1315
|
+
logger.error(f'error directory: {_dir}')
|
1210
1316
|
|
1211
1317
|
return True
|
1212
1318
|
|
1213
1319
|
else:
|
1214
|
-
|
1215
|
-
|
1320
|
+
if v_true(debug, bool):
|
1321
|
+
logger.error(f'error directory: {directory}')
|
1216
1322
|
return False
|
1217
1323
|
|
1218
1324
|
except Exception as e:
|
1219
|
-
|
1325
|
+
if v_true(debug, bool):
|
1326
|
+
logger.exception(e)
|
1220
1327
|
return False
|
1221
1328
|
|
1222
1329
|
|
@@ -1225,7 +1332,7 @@ def delete_directory(
|
|
1225
1332
|
|
1226
1333
|
def process_pool(
|
1227
1334
|
process_func: Callable,
|
1228
|
-
process_data:
|
1335
|
+
process_data: Any = None,
|
1229
1336
|
process_num: int = 2,
|
1230
1337
|
thread: bool = False,
|
1231
1338
|
debug: bool = False,
|
@@ -1234,48 +1341,56 @@ def process_pool(
|
|
1234
1341
|
"""
|
1235
1342
|
多线程(MultiThread) | 多进程(MultiProcess)
|
1236
1343
|
"""
|
1237
|
-
|
1238
|
-
ThreadPool
|
1239
|
-
ThreadPool
|
1240
|
-
|
1241
|
-
https://stackoverflow.com/a/58897266
|
1242
|
-
"""
|
1344
|
+
# ThreadPool 线程池
|
1345
|
+
# ThreadPool 共享内存, Pool 不共享内存
|
1346
|
+
# ThreadPool 可以解决 Pool 在某些情况下产生的 Can't pickle local object 的错误
|
1347
|
+
# https://stackoverflow.com/a/58897266
|
1243
1348
|
try:
|
1244
1349
|
|
1245
1350
|
# 处理数据
|
1246
|
-
|
1351
|
+
if v_true(debug, bool):
|
1352
|
+
logger.info("data split ......")
|
1247
1353
|
if len(process_data) <= process_num:
|
1248
1354
|
process_num = len(process_data)
|
1249
1355
|
_data = process_data
|
1250
1356
|
else:
|
1251
1357
|
_data = list_split(process_data, process_num, equally=True, debug=debug)
|
1252
|
-
|
1358
|
+
|
1359
|
+
if _data is None:
|
1360
|
+
return False
|
1361
|
+
|
1362
|
+
if v_true(debug, bool):
|
1363
|
+
logger.info(f"data: {_data}")
|
1253
1364
|
|
1254
1365
|
# 执行函数
|
1255
1366
|
if v_true(thread, bool):
|
1256
1367
|
# 多线程
|
1257
|
-
|
1368
|
+
if v_true(debug, bool):
|
1369
|
+
logger.info("execute multi thread ......")
|
1258
1370
|
with ThreadPool(process_num, **kwargs) as p:
|
1259
1371
|
return p.map(process_func, _data)
|
1260
1372
|
else:
|
1261
1373
|
# 多进程
|
1262
|
-
|
1374
|
+
if v_true(debug, bool):
|
1375
|
+
logger.info("execute multi process ......")
|
1263
1376
|
with Pool(process_num, **kwargs) as p:
|
1264
1377
|
return p.map(process_func, _data)
|
1265
1378
|
|
1266
1379
|
except Exception as e:
|
1267
|
-
|
1380
|
+
if v_true(debug, bool):
|
1381
|
+
logger.exception(e)
|
1268
1382
|
return False
|
1269
1383
|
|
1270
1384
|
|
1271
1385
|
def new_process(
|
1272
1386
|
process_func: Callable,
|
1273
|
-
process_data:
|
1387
|
+
process_data: Any = None,
|
1274
1388
|
thread: bool = False,
|
1275
1389
|
daemon: bool = True,
|
1276
1390
|
debug: bool = False,
|
1277
1391
|
**kwargs
|
1278
1392
|
) -> Thread | Process | bool:
|
1393
|
+
"""New Process"""
|
1279
1394
|
try:
|
1280
1395
|
if v_true(thread, bool):
|
1281
1396
|
process = Thread(target=process_func, args=process_data, **kwargs)
|
@@ -1285,7 +1400,8 @@ def new_process(
|
|
1285
1400
|
process.start()
|
1286
1401
|
return process
|
1287
1402
|
except Exception as e:
|
1288
|
-
|
1403
|
+
if v_true(debug, bool):
|
1404
|
+
logger.exception(e)
|
1289
1405
|
return False
|
1290
1406
|
|
1291
1407
|
|
@@ -1296,20 +1412,25 @@ def create_empty_file(
|
|
1296
1412
|
file: str | None = None,
|
1297
1413
|
debug: bool = False
|
1298
1414
|
) -> str | None:
|
1415
|
+
"""create empty file"""
|
1299
1416
|
try:
|
1300
1417
|
if file is None:
|
1301
1418
|
# 当前时间戳(纳秒)
|
1302
1419
|
timestamp = time.time_ns()
|
1303
|
-
|
1420
|
+
if v_true(debug, bool):
|
1421
|
+
logger.info(f"timestamp: {timestamp}")
|
1304
1422
|
# 空文件路径
|
1305
1423
|
file = f'/tmp/empty_file_{timestamp}.txt'
|
1306
1424
|
# 创建一个空文件
|
1307
|
-
|
1425
|
+
if v_true(debug, bool):
|
1426
|
+
logger.info(f"file: {file}")
|
1427
|
+
# pylint: disable=R1732,disable=W1514
|
1308
1428
|
open(file, 'w').close()
|
1309
1429
|
# 返回文件路径
|
1310
1430
|
return file
|
1311
1431
|
except Exception as e:
|
1312
|
-
|
1432
|
+
if v_true(debug, bool):
|
1433
|
+
logger.exception(e)
|
1313
1434
|
return None
|
1314
1435
|
|
1315
1436
|
|
@@ -1317,6 +1438,7 @@ def create_empty_file(
|
|
1317
1438
|
|
1318
1439
|
|
1319
1440
|
def uuid4_hex() -> str:
|
1441
|
+
"""UUID"""
|
1320
1442
|
return uuid4().hex
|
1321
1443
|
|
1322
1444
|
|
@@ -1330,7 +1452,8 @@ def increment_version(
|
|
1330
1452
|
version_numbers[-1] = str(int(version_numbers[-1]) + 1)
|
1331
1453
|
return '.'.join(version_numbers)
|
1332
1454
|
except Exception as e:
|
1333
|
-
|
1455
|
+
if v_true(debug, bool):
|
1456
|
+
logger.exception(e)
|
1334
1457
|
return None
|
1335
1458
|
|
1336
1459
|
|
@@ -1346,7 +1469,8 @@ def make_directory(
|
|
1346
1469
|
os.makedirs(directory)
|
1347
1470
|
return True
|
1348
1471
|
except Exception as e:
|
1349
|
-
|
1472
|
+
if v_true(debug, bool):
|
1473
|
+
logger.exception(e)
|
1350
1474
|
return False
|
1351
1475
|
|
1352
1476
|
def change_directory(
|
@@ -1355,17 +1479,27 @@ def change_directory(
|
|
1355
1479
|
) -> bool:
|
1356
1480
|
"""改变目录"""
|
1357
1481
|
try:
|
1358
|
-
|
1359
|
-
|
1482
|
+
|
1483
|
+
if not v_true(directory, str, debug=debug):
|
1484
|
+
return False
|
1485
|
+
|
1486
|
+
if v_true(debug, bool):
|
1487
|
+
logger.info(f"directory: {directory}")
|
1488
|
+
|
1360
1489
|
if check_file_type(directory, 'dir', debug=debug):
|
1361
|
-
|
1490
|
+
if v_true(debug, bool):
|
1491
|
+
logger.info(f"change directory to {directory}")
|
1362
1492
|
os.chdir(directory)
|
1363
1493
|
return True
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1494
|
+
|
1495
|
+
if v_true(debug, bool):
|
1496
|
+
logger.error(f"no such directory: {directory}")
|
1497
|
+
|
1498
|
+
return False
|
1499
|
+
|
1367
1500
|
except Exception as e:
|
1368
|
-
|
1501
|
+
if v_true(debug, bool):
|
1502
|
+
logger.exception(e)
|
1369
1503
|
return False
|
1370
1504
|
|
1371
1505
|
|
@@ -1373,19 +1507,23 @@ def change_directory(
|
|
1373
1507
|
|
1374
1508
|
|
1375
1509
|
def load_toml_file(
|
1376
|
-
file: str
|
1510
|
+
file: str,
|
1377
1511
|
debug: bool = False
|
1378
1512
|
) -> dict | None:
|
1513
|
+
"""Load TOML file"""
|
1514
|
+
info = '解析配置文件'
|
1379
1515
|
try:
|
1380
|
-
|
1381
|
-
|
1516
|
+
if v_true(debug, bool):
|
1517
|
+
logger.info(f'{info}[执行]')
|
1382
1518
|
with open(file, "rb") as _file:
|
1383
1519
|
config = toml_load(_file)
|
1384
|
-
|
1520
|
+
if v_true(debug, bool):
|
1521
|
+
logger.success(f'{info}[成功]')
|
1385
1522
|
return config
|
1386
1523
|
except Exception as e:
|
1387
|
-
|
1388
|
-
|
1524
|
+
if v_true(debug, bool):
|
1525
|
+
logger.error(f'{info}[失败]')
|
1526
|
+
logger.exception(e)
|
1389
1527
|
return None
|
1390
1528
|
|
1391
1529
|
|
@@ -1397,6 +1535,7 @@ def git_clone(
|
|
1397
1535
|
log_prefix: str = '',
|
1398
1536
|
debug: bool = False,
|
1399
1537
|
) -> bool:
|
1538
|
+
"""GIT Clone"""
|
1400
1539
|
try:
|
1401
1540
|
|
1402
1541
|
# 日志前缀
|
@@ -1426,23 +1565,27 @@ def git_clone(
|
|
1426
1565
|
stdout=subprocess.PIPE,
|
1427
1566
|
stderr=subprocess.STDOUT
|
1428
1567
|
)
|
1429
|
-
|
1568
|
+
|
1569
|
+
if result is None:
|
1570
|
+
return False
|
1571
|
+
|
1572
|
+
result_code: int = result.returncode
|
1430
1573
|
result_info = result.stdout.splitlines()
|
1574
|
+
|
1575
|
+
if v_true(debug, bool):
|
1576
|
+
logger.error(f'{log_prefix}unsuccessful')
|
1577
|
+
for i in result_info:
|
1578
|
+
logger.error(f'{log_prefix}{i}')
|
1579
|
+
|
1431
1580
|
if result_code == 0:
|
1432
|
-
logger.success(f'{log_prefix}successful') if v_true(debug, bool) else next
|
1433
|
-
if v_true(debug, bool):
|
1434
|
-
for i in result_info:
|
1435
|
-
logger.success(f'{log_prefix}{i}') if v_true(debug, bool) else next
|
1436
1581
|
return True
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
for i in result_info:
|
1441
|
-
logger.error(f'{log_prefix}{i}') if v_true(debug, bool) else next
|
1442
|
-
return False
|
1582
|
+
|
1583
|
+
return False
|
1584
|
+
|
1443
1585
|
except Exception as e:
|
1444
|
-
|
1445
|
-
|
1586
|
+
if v_true(debug, bool):
|
1587
|
+
logger.error(f'{log_prefix}unsuccessful')
|
1588
|
+
logger.exception(e)
|
1446
1589
|
return False
|
1447
1590
|
|
1448
1591
|
|
@@ -1451,18 +1594,20 @@ def url_parse(
|
|
1451
1594
|
scheme: str = 'http',
|
1452
1595
|
debug: bool = False
|
1453
1596
|
) -> ParseResult:
|
1597
|
+
"""URL Parse"""
|
1454
1598
|
none_result = ParseResult(scheme='', netloc='', path='', params='', query='', fragment='')
|
1455
1599
|
try:
|
1456
|
-
|
1600
|
+
if v_true(debug, bool):
|
1601
|
+
logger.info(f'url: {url}')
|
1457
1602
|
# 如果没有 scheme 的话, 字符串是不解析的. 所以, 如果没有 scheme, 就添加一个 scheme, 默认添加 http
|
1458
1603
|
if v_true(url, str) and (url.find('://') == -1) and v_true(scheme, str):
|
1459
1604
|
url = f'{scheme}://{url}'
|
1460
1605
|
if v_true(url, str):
|
1461
1606
|
return urlparse(url)
|
1462
|
-
|
1463
|
-
return none_result
|
1607
|
+
return none_result
|
1464
1608
|
except Exception as e:
|
1465
|
-
|
1609
|
+
if v_true(debug, bool):
|
1610
|
+
logger.exception(e)
|
1466
1611
|
return none_result
|
1467
1612
|
|
1468
1613
|
# def debug_log(
|