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/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: any,
47
- v_type: any = None,
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
- if true_list is not None and false_list is None and (
69
- isinstance(true_list, list) or
70
- isinstance(true_list, tuple) or
71
- isinstance(true_list, set) or
72
- isinstance(true_list, str)
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 True if v_instance in true_list else False
75
- elif true_list is None and false_list is not None and (
76
- isinstance(false_list, list) or
77
- isinstance(false_list, tuple) or
78
- isinstance(false_list, set) or
79
- isinstance(false_list, str)
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 True if v_instance not in false_list else False
82
- elif true_list is not None and false_list is not None and (
83
- isinstance(true_list, list) or
84
- isinstance(true_list, tuple) or
85
- isinstance(true_list, set) or
86
- isinstance(true_list, str)
87
- ) and (
88
- isinstance(false_list, list) or
89
- isinstance(false_list, tuple) or
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 True if (v_instance in true_list) and (v_instance not in false_list) else False
94
- else:
95
- return True if v_instance not in [False, None, 0, 0.0, '', (), [], {*()}, {*[]}, {*{}}, {}] else False
96
- else:
97
- return False
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
- logger.exception(e) if v_true(debug, bool) else next
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: any = None,
102
+ value: Any = None,
106
103
  debug: bool = False
107
- ) -> any:
108
- """伪全局变量"""
104
+ ) -> Any:
109
105
  """
110
- Python 没有全局变量, 多个文件无法调用同一个变量
111
- 为了解决这个问题, 将变量设置为系统变量, 从而实现多个文件调用同一个变量
106
+ 系统变量
107
+
108
+ 伪全局变量
109
+ Python 没有全局变量, 多个文件无法调用同一个变量.
110
+ 为了解决这个问题, 将变量设置为系统变量, 从而实现多个文件调用同一个变量.
112
111
  """
113
112
  try:
113
+
114
114
  # 变量名添加一个前缀, 防止和系统中其它变量名冲突
115
- variable_name = f'PYTHON_VARIABLE_{name}'
116
- if value == None:
117
- data = os.environ.get(variable_name)
118
- return json.loads(data)
119
- else:
120
- data = json.dumps(value)
121
- os.environ[variable_name] = data
122
- return value
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- integer 数字
165
- split_equally_number 平分 integer 的数字
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]] -> 返回 5
173
- 分成 3 份 -> [[1, 2, 3], [4, 5, 6], [7, 8, 9]] -> 返回 3
174
- 分成 4 份 -> [[1, 2, 3], [4, 5], [6, 7], [8, 9]] -> 返回 3
175
- 分成 5 份 -> [[1, 2], [3, 4], [5, 6], [7, 8], [9]] -> 返回 2
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
- else:
181
- return int(integer / split_equally_number) + 1
204
+ return int(integer / split_equally_number) + 1
182
205
  except Exception as e:
183
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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 | None:
289
+ ) -> bool:
266
290
  """
291
+ check file type
292
+
267
293
  检查文件类型
268
- file_object 文件对象
269
- file_type 文件类型
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
- return False
304
+ result = False
276
305
  case True if file_type == 'absolute' and _file_path.is_absolute() is True:
277
- return True
306
+ result = True
278
307
  case True if file_type == 'block_device' and _file_path.is_block_device() is True:
279
- return True
308
+ result = True
280
309
  case True if file_type == 'dir' and _file_path.is_dir() is True:
281
- return True
310
+ result = True
282
311
  case True if file_type == 'fifo' and _file_path.is_fifo() is True:
283
- return True
312
+ result = True
284
313
  case True if file_type == 'file' and _file_path.is_file() is True:
285
- return True
314
+ result = True
286
315
  case True if file_type == 'mount' and _file_path.is_mount() is True:
287
- return True
316
+ result = True
288
317
  case True if file_type == 'relative_to' and _file_path.is_relative_to() is True:
289
- return True
318
+ result = True
290
319
  case True if file_type == 'reserved' and _file_path.is_reserved() is True:
291
- return True
320
+ result = True
292
321
  case True if file_type == 'socket' and _file_path.is_socket() is True:
293
- return True
322
+ result = True
294
323
  case True if file_type == 'symlink' and _file_path.is_symlink() is True:
295
- return True
324
+ result = True
296
325
  case _:
297
- return False
326
+ result = False
327
+
328
+ return result
329
+
298
330
  except Exception as e:
299
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- 默认: 将 list 以 number个元素为一个list 分割
370
-
371
- data = [1, 2, 3, 4, 5, 6, 7]
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
- logger.error('number must greater than data length') if v_true(debug, bool) else next
437
+ if v_true(debug, bool):
438
+ logger.error('number must greater than data length')
407
439
  return None
408
- elif _data_length == number:
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
- logger.info(f"step number: {_step_number}") if v_true(debug, bool) else next
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
- logger.info(f"index number list: {index_number_list}") if v_true(debug, bool) else next
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
- logger.info(f"index: {index_number}, data: {_data_object[index_number:index_number + number]}") if v_true(debug, bool) else next
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
- previous_end_number = (_data_length % number) * _step_number
426
- previous_index_number_list = list(range(0, previous_end_number, _step_number))
427
- for index_number in previous_index_number_list:
428
- _data_result.append(deepcopy(_data_object[index_number:index_number + _step_number]))
429
- # 后一部分
430
- next_number_list = list(range(previous_end_number, _data_length, _step_number - 1))
431
- for index_number in next_number_list:
432
- _data_result.append(deepcopy(_data_object[index_number:index_number + (_step_number - 1)]))
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- """合并 List 中的 List 为一个 List"""
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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: any,
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
- if v_true(data, dict, debug=debug):
594
- for _k, _v in data.items():
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.info(f"basename: {_basename}") if v_true(debug, bool) else next
712
+
713
+ if v_true(debug, bool):
714
+ logger.info(f"basename: {_basename}")
715
+
636
716
  _index_of_split = _basename.index(split)
637
- logger.info(f"index of split: {_index_of_split}") if v_true(debug, bool) else next
638
- logger.info(f"filename: {_basename[:_index_of_split]}") if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- """获取文件Hash"""
651
- """
652
- 参考文档:
653
- https://stackoverflow.com/a/59056837
654
- https://stackoverflow.com/questions/22058048/hashing-a-file-in-python
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
- file_hash = hashlib.shake_128()
679
- case True if sha == 'shake_256':
680
- file_hash = hashlib.shake_256()
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.info(f"path: {path}") if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- 函数传递参数: https://stackoverflow.com/a/803632
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
862
+ if v_true(debug, bool):
863
+ logger.exception(e)
773
864
 
774
865
 
775
866
  # --------------------------------------------------------------------------------------------------
776
867
 
777
-
778
- """
779
- 日期时间有两种: UTC datetime (UTC时区日期时间) 和 Local datetime (当前时区日期时间)
780
-
781
- Unix Timestamp 仅为 UTC datetime 的值
782
-
783
- 但是, Local datetime 可以直接转换为 Unix Timestamp, UTC datetime 需要先转换到 UTC TimeZone 再转换为 Unix Timestamp
784
-
785
- 相反, Unix Timestamp 可以直接转换为 UTC datetime, 要获得 Local datetime, 需要再将 UTC datetime 转换为 Local datetime
786
-
787
- https://stackoverflow.com/a/13287083
788
- https://stackoverflow.com/a/466376
789
- https://stackoverflow.com/a/7999977
790
- https://stackoverflow.com/a/3682808
791
- https://stackoverflow.com/a/63920772
792
- https://www.geeksforgeeks.org/how-to-remove-timezone-information-from-datetime-object-in-python/
793
-
794
- pytz all timezones
795
-
796
- https://stackoverflow.com/a/13867319
797
- https://stackoverflow.com/a/15692958
798
-
799
- import pytz
800
- pytz.all_timezones
801
- pytz.common_timezones
802
- pytz.timezone('US/Eastern')
803
-
804
- timezone
805
-
806
- https://stackoverflow.com/a/39079819
807
- https://stackoverflow.com/a/1681600
808
- https://stackoverflow.com/a/4771733
809
- https://stackoverflow.com/a/63920772
810
- https://toutiao.io/posts/sin4x0/preview
811
-
812
- 其它:
813
-
814
- dt.replace(tzinfo=timezone.utc).astimezone(tz=None)
815
-
816
- (dt.replace(tzinfo=timezone.utc).astimezone(tz=None)).strftime(format)
817
- datetime.fromisoformat((dt.replace(tzinfo=timezone.utc).astimezone(tz=None)).strftime(format))
818
- string_to_datetime((dt.replace(tzinfo=timezone.utc).astimezone(tz=None)).strftime(format), format)
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
- logger.exception(e) if v_true(debug, bool) else next
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
- datetime_object: datetime.datetime,
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 datetime_object.date()
933
+ return datetime_instance.date()
845
934
  except Exception as e:
846
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
954
+ if v_true(debug, bool):
955
+ logger.exception(e)
865
956
  return None
866
957
 
867
958
 
868
959
  def datetime_offset(
869
- datetime_object: datetime.datetime,
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(datetime_object, datetime.datetime):
881
- return datetime_object + datetime.timedelta(**kwargs)
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
- logger.exception(e) if v_true(debug, bool) else next
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
- datetime_object: datetime.datetime,
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(datetime_object, string_format) if isinstance(datetime_object, datetime.datetime) is True else None
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
- logger.exception(e) if v_true(debug, bool) else next
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
- datetime_object: datetime.datetime,
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(datetime_object, datetime.datetime):
914
- return int(datetime_object.replace(tzinfo=datetime.timezone.utc).timestamp()) if utc is True else int(datetime_object.timestamp())
915
- else:
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
- logger.exception(e) if v_true(debug, bool) else next
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
- datetime_object: datetime.datetime,
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(datetime_object, datetime.datetime) is True:
933
- return (datetime.datetime.fromtimestamp(datetime_object.timestamp(), tz=tz)).replace(tzinfo=None)
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
- logger.exception(e) if v_true(debug, bool) else next
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
- datetime_object: datetime.datetime,
943
- tz: datetime.timezone = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo,
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(datetime_object, datetime.datetime) is True:
952
- return datetime_object.replace(tzinfo=datetime.timezone.utc).astimezone(tz).replace(tzinfo=None)
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- run_cmd = bash('echo ok', universal_newlines=True, stdout=PIPE)
1020
-
1021
- if run_cmd != None:
1022
- returncode = run_cmd.returncode
1023
- outputs = run_cmd.stdout.splitlines()
1024
- print(returncode, type(returncode))
1025
- print(outputs, type(outputs))
1026
-
1027
- # echo 'echo ok' > /tmp/ok.sh
1028
- run_script = bash('/tmp/ok.sh', file=True, universal_newlines=True, stdout=PIPE)
1029
-
1030
- if run_script != None:
1031
- returncode = run_script.returncode
1032
- outputs = run_script.stdout.splitlines()
1033
- print(returncode, type(returncode))
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 == None:
1054
- return subprocess.run([sh_shell, command], **kwargs)
1055
- else:
1056
- return subprocess.run([sh_shell, sh_option, command], **kwargs)
1057
- else:
1058
- if sh_option == None:
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
- logger.exception(e) if v_true(debug, bool) else next
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
- else:
1081
- logger.error(f"No such file: {file}") if v_true(debug, bool) else next
1082
- return None
1179
+ if v_true(debug, bool):
1180
+ logger.error(f"No such file: {file}")
1181
+ return None
1083
1182
  except Exception as e:
1084
- logger.exception(e) if v_true(debug, bool) else next
1183
+ if v_true(debug, bool):
1184
+ logger.exception(e)
1085
1185
  return None
1086
1186
 
1087
-
1088
- """
1089
- json_raw = '''
1090
- {
1091
- "markdown.preview.fontSize": 14,
1092
- "editor.minimap.enabled": false,
1093
- "workbench.iconTheme": "vscode-icons",
1094
- "http.proxy": "http://127.0.0.1:1087"
1095
-
1096
- }
1097
- '''
1098
-
1099
- print(json_sort(json_raw))
1100
-
1101
- {
1102
- "editor.minimap.enabled": false,
1103
- "http.proxy": "http://127.0.0.1:1087",
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
- ) -> dict | None:
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
- logger.exception(e) if v_true(debug, bool) else next
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 | list,
1224
+ files: Union[str, List],
1127
1225
  debug: bool = False
1128
1226
  ) -> bool:
1129
1227
  """删除文件"""
1130
1228
  try:
1131
1229
 
1132
- if v_true(files, str, debug=debug) and check_file_type(files, 'file', debug=debug):
1230
+ if isinstance(files, str) and check_file_type(files, 'file', debug=debug):
1133
1231
 
1134
1232
  os.remove(files)
1135
- logger.success('deleted file: {}'.format(files)) if v_true(debug, bool) else next
1233
+ if v_true(debug, bool):
1234
+ logger.success(f'deleted file: {files}')
1136
1235
  return True
1137
1236
 
1138
- elif v_true(files, list, debug=debug):
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: {}'.format(_file))
1244
+ logger.success(f'deleted file: {_file}')
1146
1245
  except Exception as e:
1147
- logger.error('error file: {} {}'.format(_file, e))
1246
+ logger.error(f'error file: {_file} {e}')
1148
1247
  else:
1149
- logger.error('error file: {}'.format(_file))
1248
+ logger.error(f'error file: {_file}')
1150
1249
 
1151
1250
  return True
1152
1251
 
1153
- else:
1252
+ if v_true(debug, bool):
1253
+ logger.error(f'error file: {files}')
1154
1254
 
1155
- logger.error('error file: {}'.format(files)) if v_true(debug, bool) else next
1156
- return False
1255
+ return False
1157
1256
 
1158
1257
  except Exception as e:
1159
- logger.exception(e) if v_true(debug, bool) else next
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 | list,
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 v_true(directory, str, debug=debug) and check_file_type(directory, 'dir', debug=debug):
1292
+ if isinstance(directory, str) and check_file_type(directory, 'dir', debug=debug):
1193
1293
 
1194
1294
  rmtree(directory)
1195
- logger.success('deleted directory: {}'.format(directory)) if v_true(debug, bool) else next
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
- logger.success('deleted directory: {}'.format(_dir)) if v_true(debug, bool) else next
1308
+ if v_true(debug, bool):
1309
+ logger.success(f'deleted directory: {_dir}')
1206
1310
  except Exception as e:
1207
- logger.error('error directory: {} {}'.format(_dir, e)) if v_true(debug, bool) else next
1311
+ if v_true(debug, bool):
1312
+ logger.error(f'error directory: {_dir} {e}')
1208
1313
  else:
1209
- logger.error('error directory: {}'.format(_dir)) if v_true(debug, bool) else next
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
- logger.error('error directory: {}'.format(directory)) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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: any = None,
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 共享内存, Pool 不共享内存
1240
- ThreadPool 可以解决 Pool 在某些情况下产生的 Can't pickle local object 的错误
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
- logger.info(f"data split ......") if v_true(debug, bool) else next
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
- logger.info(f"data: {_data}") if v_true(debug, bool) else next
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
- logger.info(f"execute multi thread ......") if v_true(debug, bool) else next
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
- logger.info(f"execute multi process ......") if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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: any = None,
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.info(f"timestamp: {timestamp}") if v_true(debug, bool) else next
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
- logger.info(f"file: {file}") if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.exception(e) if v_true(debug, bool) else next
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
- directory = str(directory) if v_true(directory, str, debug=debug) else next
1359
- logger.info(f"directory: {directory}") if v_true(debug, bool) else next
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
- logger.info(f"change directory to {directory}") if v_true(debug, bool) else next
1490
+ if v_true(debug, bool):
1491
+ logger.info(f"change directory to {directory}")
1362
1492
  os.chdir(directory)
1363
1493
  return True
1364
- else:
1365
- logger.error(f"no such directory: {directory}") if v_true(debug, bool) else next
1366
- return False
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
- logger.exception(e) if v_true(debug, bool) else next
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 = None,
1510
+ file: str,
1377
1511
  debug: bool = False
1378
1512
  ) -> dict | None:
1513
+ """Load TOML file"""
1514
+ info = '解析配置文件'
1379
1515
  try:
1380
- info = '解析配置文件'
1381
- logger.info(f'{info}[执行]') if v_true(debug, bool) else next
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
- logger.success(f'{info}[成功]') if v_true(debug, bool) else next
1520
+ if v_true(debug, bool):
1521
+ logger.success(f'{info}[成功]')
1385
1522
  return config
1386
1523
  except Exception as e:
1387
- logger.error(f'{info}[失败]') if v_true(debug, bool) else next
1388
- logger.exception(e) if v_true(debug, bool) else next
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
- result_code = result.returncode
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
- else:
1438
- logger.error(f'{log_prefix}unsuccessful') if v_true(debug, bool) else next
1439
- if v_true(debug, bool):
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
- logger.error(f'{log_prefix}unsuccessful') if v_true(debug, bool) else next
1445
- logger.exception(e) if v_true(debug, bool) else next
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
- logger.info(f'url: {url}') if v_true(debug, bool) else next
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
- else:
1463
- return none_result
1607
+ return none_result
1464
1608
  except Exception as e:
1465
- logger.exception(e) if v_true(debug, bool) else next
1609
+ if v_true(debug, bool):
1610
+ logger.exception(e)
1466
1611
  return none_result
1467
1612
 
1468
1613
  # def debug_log(