ezKit 1.12.0__py3-none-any.whl → 1.12.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_extensions.py +8 -4
- ezKit/cipher.py +19 -16
- ezKit/database.py +20 -18
- ezKit/dockerhub.py +9 -3
- ezKit/http.py +9 -6
- ezKit/mongo.py +3 -2
- ezKit/qywx.py +47 -20
- ezKit/redis.py +2 -1
- ezKit/sendemail.py +12 -4
- ezKit/token.py +13 -13
- ezKit/utils.py +158 -230
- ezKit/xftp.py +39 -17
- ezKit/zabbix.py +140 -101
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.dist-info}/METADATA +1 -1
- ezkit-1.12.1.dist-info/RECORD +22 -0
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.dist-info}/WHEEL +1 -1
- ezkit-1.12.0.dist-info/RECORD +0 -22
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.dist-info}/licenses/LICENSE +0 -0
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.dist-info}/top_level.txt +0 -0
ezKit/utils.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""Utils"""
|
1
|
+
"""Utils Library"""
|
2
|
+
|
2
3
|
import csv
|
3
4
|
import hashlib
|
4
5
|
import importlib
|
@@ -94,10 +95,7 @@ def check_arguments(data: list) -> bool:
|
|
94
95
|
# --------------------------------------------------------------------------------------------------
|
95
96
|
|
96
97
|
|
97
|
-
def os_environ(
|
98
|
-
name: str,
|
99
|
-
value: Any = None
|
100
|
-
) -> Any:
|
98
|
+
def os_environ(name: str, value: Any = None) -> Any:
|
101
99
|
"""系统变量"""
|
102
100
|
|
103
101
|
# 伪全局变量
|
@@ -111,7 +109,7 @@ def os_environ(
|
|
111
109
|
try:
|
112
110
|
|
113
111
|
# 变量名添加一个前缀, 防止和系统中其它变量名冲突
|
114
|
-
_variable_name = f
|
112
|
+
_variable_name = f"PYTHON_VARIABLE_{name}"
|
115
113
|
|
116
114
|
# 如果 value 的值是 None, 则从系统环境获取变量数据
|
117
115
|
if value is None:
|
@@ -140,10 +138,7 @@ def os_environ(
|
|
140
138
|
# --------------------------------------------------------------------------------------------------
|
141
139
|
|
142
140
|
|
143
|
-
def mam_of_numbers(
|
144
|
-
numbers: list | tuple,
|
145
|
-
dest_type: str | None = None
|
146
|
-
) -> tuple | None:
|
141
|
+
def mam_of_numbers(numbers: list | tuple, dest_type: str | None = None) -> tuple | None:
|
147
142
|
"""返回一组数字中的 最大值(maximum), 平均值(average), 最小值(minimum)"""
|
148
143
|
|
149
144
|
# numbers 数字列表 (仅支持 list 和 tuple, 不支 set)
|
@@ -190,8 +185,7 @@ def mam_of_numbers(
|
|
190
185
|
|
191
186
|
|
192
187
|
def step_number_for_split_equally(
|
193
|
-
integer: int,
|
194
|
-
split_equally_number: int
|
188
|
+
integer: int, split_equally_number: int
|
195
189
|
) -> int | None:
|
196
190
|
"""
|
197
191
|
step number for split equally
|
@@ -222,13 +216,12 @@ def step_number_for_split_equally(
|
|
222
216
|
# --------------------------------------------------------------------------------------------------
|
223
217
|
|
224
218
|
|
225
|
-
def division(
|
226
|
-
dividend: int | float,
|
227
|
-
divisor: int | float
|
228
|
-
) -> float | None:
|
219
|
+
def division(dividend: int | float, divisor: int | float) -> float | None:
|
229
220
|
"""Division"""
|
230
221
|
# 检查参数是否正确
|
231
|
-
if not check_arguments(
|
222
|
+
if not check_arguments(
|
223
|
+
[(dividend, (int, float), "dividend"), (divisor, (int, float), "divisor")]
|
224
|
+
):
|
232
225
|
return None
|
233
226
|
try:
|
234
227
|
return dividend / divisor
|
@@ -246,11 +239,9 @@ def format_float(number: float | int, index: int = 2, limit: int = 3) -> float |
|
|
246
239
|
# 以两位和三位为例, 如果结果为假, 即: 0, 0.0, 0.00 等,保留小数点后的三位, 否则保留小数点后的两位.
|
247
240
|
|
248
241
|
# 检查参数
|
249
|
-
if not check_arguments(
|
250
|
-
(number, (float, int), "number"),
|
251
|
-
|
252
|
-
(limit, int, "limit")
|
253
|
-
]):
|
242
|
+
if not check_arguments(
|
243
|
+
[(number, (float, int), "number"), (index, int, "index"), (limit, int, "limit")]
|
244
|
+
):
|
254
245
|
return False
|
255
246
|
|
256
247
|
try:
|
@@ -264,10 +255,7 @@ def format_float(number: float | int, index: int = 2, limit: int = 3) -> float |
|
|
264
255
|
# --------------------------------------------------------------------------------------------------
|
265
256
|
|
266
257
|
|
267
|
-
def check_file_type(
|
268
|
-
file_object: str,
|
269
|
-
file_type: str
|
270
|
-
) -> bool:
|
258
|
+
def check_file_type(file_object: str, file_type: str) -> bool:
|
271
259
|
"""检查文件类型"""
|
272
260
|
|
273
261
|
# file_object 文件对象
|
@@ -284,25 +272,29 @@ def check_file_type(
|
|
284
272
|
match True:
|
285
273
|
case True if _file_path.exists() is False:
|
286
274
|
result = False
|
287
|
-
case True if file_type ==
|
275
|
+
case True if file_type == "absolute" and _file_path.is_absolute() is True:
|
288
276
|
result = True
|
289
|
-
case True if
|
277
|
+
case True if (
|
278
|
+
file_type == "block_device" and _file_path.is_block_device() is True
|
279
|
+
):
|
290
280
|
result = True
|
291
|
-
case True if file_type ==
|
281
|
+
case True if file_type == "dir" and _file_path.is_dir() is True:
|
292
282
|
result = True
|
293
|
-
case True if file_type ==
|
283
|
+
case True if file_type == "fifo" and _file_path.is_fifo() is True:
|
294
284
|
result = True
|
295
|
-
case True if file_type ==
|
285
|
+
case True if file_type == "file" and _file_path.is_file() is True:
|
296
286
|
result = True
|
297
|
-
case True if file_type ==
|
287
|
+
case True if file_type == "mount" and _file_path.is_mount() is True:
|
298
288
|
result = True
|
299
|
-
case True if
|
289
|
+
# case True if (
|
290
|
+
# file_type == "relative_to" and _file_path.is_relative_to() is True
|
291
|
+
# ):
|
292
|
+
# result = True
|
293
|
+
case True if file_type == "reserved" and _file_path.is_reserved() is True:
|
300
294
|
result = True
|
301
|
-
case True if file_type ==
|
295
|
+
case True if file_type == "socket" and _file_path.is_socket() is True:
|
302
296
|
result = True
|
303
|
-
case True if file_type ==
|
304
|
-
result = True
|
305
|
-
case True if file_type == 'symlink' and _file_path.is_symlink() is True:
|
297
|
+
case True if file_type == "symlink" and _file_path.is_symlink() is True:
|
306
298
|
result = True
|
307
299
|
case _:
|
308
300
|
result = False
|
@@ -317,11 +309,7 @@ def check_file_type(
|
|
317
309
|
# --------------------------------------------------------------------------------------------------
|
318
310
|
|
319
311
|
|
320
|
-
def list_sort(
|
321
|
-
data: list,
|
322
|
-
deduplication: bool = False,
|
323
|
-
**kwargs
|
324
|
-
) -> list | None:
|
312
|
+
def list_sort(data: list, deduplication: bool = False, **kwargs) -> list | None:
|
325
313
|
"""list sort"""
|
326
314
|
# 列表排序, 示例: list_sort(['1.2.3.4', '2.3.4.5'], key=inet_aton)
|
327
315
|
# 参考文档:
|
@@ -345,11 +333,7 @@ def list_sort(
|
|
345
333
|
return None
|
346
334
|
|
347
335
|
|
348
|
-
def list_dict_sorted_by_key(
|
349
|
-
data: list | tuple,
|
350
|
-
key: str,
|
351
|
-
**kwargs
|
352
|
-
) -> list | None:
|
336
|
+
def list_dict_sorted_by_key(data: list | tuple, key: str, **kwargs) -> list | None:
|
353
337
|
"""list dict sorted by key"""
|
354
338
|
# 列表字典排序
|
355
339
|
# 参考文档: https://stackoverflow.com/a/73050
|
@@ -360,11 +344,8 @@ def list_dict_sorted_by_key(
|
|
360
344
|
logger.exception(e)
|
361
345
|
return None
|
362
346
|
|
363
|
-
|
364
|
-
|
365
|
-
number: int,
|
366
|
-
equally: bool = False
|
367
|
-
) -> list | None:
|
347
|
+
|
348
|
+
def list_split(data: list, number: int, equally: bool = False) -> list | None:
|
368
349
|
"""列表分割"""
|
369
350
|
|
370
351
|
# 列表分割
|
@@ -403,22 +384,22 @@ def list_split(
|
|
403
384
|
|
404
385
|
# 将列表按每 n 个元素为一个列表进行分割
|
405
386
|
it = iter(data)
|
406
|
-
return [
|
387
|
+
return [
|
388
|
+
list(islice(it, number)) for _ in range((len(data) + number - 1) // number)
|
389
|
+
]
|
407
390
|
|
408
391
|
except Exception as e:
|
409
392
|
logger.exception(e)
|
410
393
|
return None
|
411
394
|
|
412
395
|
|
413
|
-
def list_print_by_step(
|
414
|
-
data: list,
|
415
|
-
step: int,
|
416
|
-
separator: str = " "
|
417
|
-
) -> bool:
|
396
|
+
def list_print_by_step(data: list, step: int, separator: str = " ") -> bool:
|
418
397
|
"""根据 步长 和 分隔符 有规律的打印列表中的数据"""
|
419
398
|
|
420
399
|
# 检查参数是否正确
|
421
|
-
if not check_arguments(
|
400
|
+
if not check_arguments(
|
401
|
+
[(data, list, "data"), (step, int, "step"), (separator, str, "separator")]
|
402
|
+
):
|
422
403
|
return False
|
423
404
|
|
424
405
|
try:
|
@@ -433,7 +414,7 @@ def list_print_by_step(
|
|
433
414
|
|
434
415
|
# 每行最后一个 或者 所有数据最后一个, 不打印分隔符
|
435
416
|
if ((i % step) == (step - 1)) or ((i + 1) == len(data)):
|
436
|
-
print(v, end=
|
417
|
+
print(v, end="")
|
437
418
|
else:
|
438
419
|
print(v, end=separator)
|
439
420
|
|
@@ -446,10 +427,7 @@ def list_print_by_step(
|
|
446
427
|
return False
|
447
428
|
|
448
429
|
|
449
|
-
def list_remove_list(
|
450
|
-
original: list,
|
451
|
-
remove: list
|
452
|
-
) -> list | None:
|
430
|
+
def list_remove_list(original: list, remove: list) -> list | None:
|
453
431
|
"""List remove List"""
|
454
432
|
try:
|
455
433
|
_original = deepcopy(original)
|
@@ -460,9 +438,7 @@ def list_remove_list(
|
|
460
438
|
return None
|
461
439
|
|
462
440
|
|
463
|
-
def list_merge(
|
464
|
-
data: list
|
465
|
-
) -> list | None:
|
441
|
+
def list_merge(data: list) -> list | None:
|
466
442
|
"""list merge"""
|
467
443
|
# 合并 List 中的 List 为一个 List
|
468
444
|
try:
|
@@ -475,14 +451,10 @@ def list_merge(
|
|
475
451
|
return None
|
476
452
|
|
477
453
|
|
478
|
-
def list_to_file(
|
479
|
-
data: list,
|
480
|
-
file: str,
|
481
|
-
encoding: str = 'utf-8-sig'
|
482
|
-
) -> bool:
|
454
|
+
def list_to_file(data: list, file: str, encoding: str = "utf-8-sig") -> bool:
|
483
455
|
"""list to file"""
|
484
456
|
try:
|
485
|
-
with open(file,
|
457
|
+
with open(file, "w", encoding=encoding) as _file:
|
486
458
|
for line in data:
|
487
459
|
_file.write(f"{line}\n")
|
488
460
|
return True
|
@@ -490,16 +462,17 @@ def list_to_file(
|
|
490
462
|
logger.exception(e)
|
491
463
|
return False
|
492
464
|
|
465
|
+
|
493
466
|
def list_to_csvfile(
|
494
467
|
data: list,
|
495
468
|
file: str,
|
496
469
|
fields: list | None = None,
|
497
|
-
encoding: str =
|
498
|
-
**kwargs
|
470
|
+
encoding: str = "utf-8-sig",
|
471
|
+
**kwargs,
|
499
472
|
) -> bool:
|
500
473
|
"""list to csvfile"""
|
501
474
|
try:
|
502
|
-
with open(file,
|
475
|
+
with open(file, "w", encoding=encoding) as _file:
|
503
476
|
# CRLF replaced by LF
|
504
477
|
# https://stackoverflow.com/a/29976091
|
505
478
|
outcsv = csv.writer(_file, lineterminator=os.linesep, **kwargs)
|
@@ -511,12 +484,8 @@ def list_to_csvfile(
|
|
511
484
|
logger.exception(e)
|
512
485
|
return False
|
513
486
|
|
514
|
-
|
515
|
-
|
516
|
-
stop: int,
|
517
|
-
step: int,
|
518
|
-
width: int
|
519
|
-
) -> list | None:
|
487
|
+
|
488
|
+
def range_zfill(start: int, stop: int, step: int, width: int) -> list | None:
|
520
489
|
"""range zfill"""
|
521
490
|
# 生成长度相同的字符串的列表
|
522
491
|
# 示例: range_zfill(8, 13, 1, 2) => ['08', '09', '10', '11', '12']
|
@@ -534,10 +503,7 @@ def range_zfill(
|
|
534
503
|
# --------------------------------------------------------------------------------------------------
|
535
504
|
|
536
505
|
|
537
|
-
def dict_remove_key(
|
538
|
-
data: dict,
|
539
|
-
key: str
|
540
|
-
) -> dict | None:
|
506
|
+
def dict_remove_key(data: dict, key: str) -> dict | None:
|
541
507
|
"""dict remove key"""
|
542
508
|
try:
|
543
509
|
data_copy: dict = deepcopy(data)
|
@@ -547,15 +513,11 @@ def dict_remove_key(
|
|
547
513
|
logger.exception(e)
|
548
514
|
return None
|
549
515
|
|
550
|
-
|
551
|
-
|
552
|
-
file: str,
|
553
|
-
encoding: str = 'utf-8-sig',
|
554
|
-
**kwargs
|
555
|
-
) -> bool:
|
516
|
+
|
517
|
+
def dict_to_file(data: dict, file: str, encoding: str = "utf-8-sig", **kwargs) -> bool:
|
556
518
|
"""dict to file"""
|
557
519
|
try:
|
558
|
-
with open(file,
|
520
|
+
with open(file, "w", encoding=encoding) as _file:
|
559
521
|
json.dump(obj=data, fp=_file, indent=4, sort_keys=True, **kwargs)
|
560
522
|
return True
|
561
523
|
except Exception as e:
|
@@ -563,11 +525,7 @@ def dict_to_file(
|
|
563
525
|
return False
|
564
526
|
|
565
527
|
|
566
|
-
def dict_nested_update(
|
567
|
-
data: dict,
|
568
|
-
key: str,
|
569
|
-
value: Any
|
570
|
-
) -> bool:
|
528
|
+
def dict_nested_update(data: dict, key: str, value: Any) -> bool:
|
571
529
|
"""dict nested update"""
|
572
530
|
# dictionary nested update
|
573
531
|
# https://stackoverflow.com/a/58885744
|
@@ -602,10 +560,7 @@ def dict_nested_update(
|
|
602
560
|
# --------------------------------------------------------------------------------------------------
|
603
561
|
|
604
562
|
|
605
|
-
def filename(
|
606
|
-
file: str,
|
607
|
-
split: str = '.'
|
608
|
-
) -> str | None:
|
563
|
+
def filename(file: str, split: str = ".") -> str | None:
|
609
564
|
"""filename"""
|
610
565
|
# 获取文件名称
|
611
566
|
# https://stackoverflow.com/questions/678236/how-do-i-get-the-filename-without-the-extension-from-a-path-in-python
|
@@ -619,10 +574,7 @@ def filename(
|
|
619
574
|
return None
|
620
575
|
|
621
576
|
|
622
|
-
def filehash(
|
623
|
-
file: str,
|
624
|
-
sha: str = 'md5'
|
625
|
-
) -> str | None:
|
577
|
+
def filehash(file: str, sha: str = "md5") -> str | None:
|
626
578
|
"""filehash"""
|
627
579
|
# 获取文件Hash
|
628
580
|
# 参考文档:
|
@@ -631,23 +583,23 @@ def filehash(
|
|
631
583
|
try:
|
632
584
|
with open(file, "rb") as _file:
|
633
585
|
match True:
|
634
|
-
case True if sha ==
|
586
|
+
case True if sha == "sha1":
|
635
587
|
file_hash = hashlib.sha1()
|
636
|
-
case True if sha ==
|
588
|
+
case True if sha == "sha224":
|
637
589
|
file_hash = hashlib.sha224()
|
638
|
-
case True if sha ==
|
590
|
+
case True if sha == "sha256":
|
639
591
|
file_hash = hashlib.sha256()
|
640
|
-
case True if sha ==
|
592
|
+
case True if sha == "sha384":
|
641
593
|
file_hash = hashlib.sha384()
|
642
|
-
case True if sha ==
|
594
|
+
case True if sha == "sha512":
|
643
595
|
file_hash = hashlib.sha512()
|
644
|
-
case True if sha ==
|
596
|
+
case True if sha == "sha3_224":
|
645
597
|
file_hash = hashlib.sha3_224()
|
646
|
-
case True if sha ==
|
598
|
+
case True if sha == "sha3_256":
|
647
599
|
file_hash = hashlib.sha3_256()
|
648
|
-
case True if sha ==
|
600
|
+
case True if sha == "sha3_384":
|
649
601
|
file_hash = hashlib.sha3_384()
|
650
|
-
case True if sha ==
|
602
|
+
case True if sha == "sha3_512":
|
651
603
|
file_hash = hashlib.sha3_512()
|
652
604
|
# case True if sha == 'shake_128':
|
653
605
|
# file_hash = hashlib.shake_128()
|
@@ -666,9 +618,7 @@ def filehash(
|
|
666
618
|
return None
|
667
619
|
|
668
620
|
|
669
|
-
def filesize(
|
670
|
-
file: str
|
671
|
-
) -> int | None:
|
621
|
+
def filesize(file: str) -> int | None:
|
672
622
|
"""filesize"""
|
673
623
|
# 获取文件大小
|
674
624
|
try:
|
@@ -701,10 +651,7 @@ def filesize(
|
|
701
651
|
# return None
|
702
652
|
|
703
653
|
|
704
|
-
def realpath(
|
705
|
-
path: str,
|
706
|
-
**kwargs
|
707
|
-
) -> str | None:
|
654
|
+
def realpath(path: str, **kwargs) -> str | None:
|
708
655
|
"""获取对象真实路径"""
|
709
656
|
try:
|
710
657
|
if not isTrue(path, str):
|
@@ -715,10 +662,7 @@ def realpath(
|
|
715
662
|
return None
|
716
663
|
|
717
664
|
|
718
|
-
def current_dir(
|
719
|
-
path: str,
|
720
|
-
**kwargs
|
721
|
-
) -> str | None:
|
665
|
+
def current_dir(path: str, **kwargs) -> str | None:
|
722
666
|
"""获取对象所在目录"""
|
723
667
|
try:
|
724
668
|
if not isTrue(path, str):
|
@@ -729,10 +673,7 @@ def current_dir(
|
|
729
673
|
return None
|
730
674
|
|
731
675
|
|
732
|
-
def parent_dir(
|
733
|
-
path: str,
|
734
|
-
**kwargs
|
735
|
-
) -> str | None:
|
676
|
+
def parent_dir(path: str, **kwargs) -> str | None:
|
736
677
|
"""获取对象所在目录的父目录"""
|
737
678
|
try:
|
738
679
|
if not isTrue(path, str):
|
@@ -759,7 +700,7 @@ def retry(func: Callable, times: int = 3, **kwargs) -> Any:
|
|
759
700
|
except Exception as e:
|
760
701
|
logger.exception(e)
|
761
702
|
if attempt < (times - 1):
|
762
|
-
logger.info(
|
703
|
+
logger.info("retrying ...")
|
763
704
|
else:
|
764
705
|
logger.error("all retries failed")
|
765
706
|
return False
|
@@ -811,9 +752,7 @@ def retry(func: Callable, times: int = 3, **kwargs) -> Any:
|
|
811
752
|
# datetime.fromisoformat(time.strftime(format, time.gmtime(dt)))
|
812
753
|
|
813
754
|
|
814
|
-
def date_to_datetime(
|
815
|
-
date_object: datetime
|
816
|
-
) -> datetime | None:
|
755
|
+
def date_to_datetime(date_object: datetime) -> datetime | None:
|
817
756
|
"""'日期'转换为'日期时间'"""
|
818
757
|
# https://stackoverflow.com/a/1937636
|
819
758
|
try:
|
@@ -823,9 +762,7 @@ def date_to_datetime(
|
|
823
762
|
return None
|
824
763
|
|
825
764
|
|
826
|
-
def datetime_to_date(
|
827
|
-
datetime_instance: datetime
|
828
|
-
) -> date | None:
|
765
|
+
def datetime_to_date(datetime_instance: datetime) -> date | None:
|
829
766
|
"""'日期时间'转换为'日期'"""
|
830
767
|
# https://stackoverflow.com/a/3743240
|
831
768
|
try:
|
@@ -853,8 +790,7 @@ def datetime_now(**kwargs) -> datetime | None:
|
|
853
790
|
|
854
791
|
|
855
792
|
def datetime_offset(
|
856
|
-
datetime_instance: datetime | None = None,
|
857
|
-
**kwargs
|
793
|
+
datetime_instance: datetime | None = None, **kwargs
|
858
794
|
) -> datetime | None:
|
859
795
|
"""
|
860
796
|
获取 '向前或向后特定日期时间' 的日期和时间
|
@@ -877,8 +813,7 @@ def datetime_offset(
|
|
877
813
|
|
878
814
|
|
879
815
|
def datetime_to_string(
|
880
|
-
datetime_instance: datetime,
|
881
|
-
string_format: str = '%Y-%m-%d %H:%M:%S'
|
816
|
+
datetime_instance: datetime, string_format: str = "%Y-%m-%d %H:%M:%S"
|
882
817
|
) -> str | None:
|
883
818
|
"""'日期时间'转换为'字符串'"""
|
884
819
|
try:
|
@@ -890,10 +825,7 @@ def datetime_to_string(
|
|
890
825
|
return None
|
891
826
|
|
892
827
|
|
893
|
-
def datetime_to_timestamp(
|
894
|
-
datetime_instance: datetime,
|
895
|
-
utc: bool = False
|
896
|
-
) -> int | None:
|
828
|
+
def datetime_to_timestamp(datetime_instance: datetime, utc: bool = False) -> int | None:
|
897
829
|
"""
|
898
830
|
Datatime 转换为 Unix Timestamp
|
899
831
|
Local datetime 可以直接转换为 Unix Timestamp
|
@@ -902,15 +834,18 @@ def datetime_to_timestamp(
|
|
902
834
|
try:
|
903
835
|
if not isTrue(datetime_instance, datetime):
|
904
836
|
return None
|
905
|
-
return
|
837
|
+
return (
|
838
|
+
int(datetime_instance.replace(tzinfo=timezone.utc).timestamp())
|
839
|
+
if utc is True
|
840
|
+
else int(datetime_instance.timestamp())
|
841
|
+
)
|
906
842
|
except Exception as e:
|
907
843
|
logger.exception(e)
|
908
844
|
return None
|
909
845
|
|
910
846
|
|
911
847
|
def datetime_local_to_timezone(
|
912
|
-
datetime_instance: datetime,
|
913
|
-
tz: timezone = timezone.utc
|
848
|
+
datetime_instance: datetime, tz: timezone = timezone.utc
|
914
849
|
) -> datetime | None:
|
915
850
|
"""
|
916
851
|
Local datetime to TimeZone datetime(默认转换为 UTC datetime)
|
@@ -919,7 +854,9 @@ def datetime_local_to_timezone(
|
|
919
854
|
try:
|
920
855
|
if not isTrue(datetime_instance, datetime):
|
921
856
|
return None
|
922
|
-
return (datetime.fromtimestamp(datetime_instance.timestamp(), tz=tz)).replace(
|
857
|
+
return (datetime.fromtimestamp(datetime_instance.timestamp(), tz=tz)).replace(
|
858
|
+
tzinfo=None
|
859
|
+
)
|
923
860
|
except Exception as e:
|
924
861
|
logger.exception(e)
|
925
862
|
return None
|
@@ -927,7 +864,7 @@ def datetime_local_to_timezone(
|
|
927
864
|
|
928
865
|
def datetime_utc_to_timezone(
|
929
866
|
datetime_instance: datetime,
|
930
|
-
tz: Any = datetime.now(timezone.utc).astimezone().tzinfo
|
867
|
+
tz: Any = datetime.now(timezone.utc).astimezone().tzinfo,
|
931
868
|
) -> datetime | None:
|
932
869
|
"""
|
933
870
|
UTC datetime to TimeZone datetime(默认转换为 Local datetime)
|
@@ -936,7 +873,11 @@ def datetime_utc_to_timezone(
|
|
936
873
|
try:
|
937
874
|
if not isTrue(datetime_instance, datetime):
|
938
875
|
return None
|
939
|
-
return
|
876
|
+
return (
|
877
|
+
datetime_instance.replace(tzinfo=timezone.utc)
|
878
|
+
.astimezone(tz)
|
879
|
+
.replace(tzinfo=None)
|
880
|
+
)
|
940
881
|
|
941
882
|
except Exception as e:
|
942
883
|
logger.exception(e)
|
@@ -944,8 +885,7 @@ def datetime_utc_to_timezone(
|
|
944
885
|
|
945
886
|
|
946
887
|
def timestamp_to_datetime(
|
947
|
-
timestamp: int,
|
948
|
-
tz: timezone = timezone.utc
|
888
|
+
timestamp: int, tz: timezone = timezone.utc
|
949
889
|
) -> datetime | None:
|
950
890
|
"""Unix Timestamp 转换为 Datatime"""
|
951
891
|
try:
|
@@ -958,8 +898,7 @@ def timestamp_to_datetime(
|
|
958
898
|
|
959
899
|
|
960
900
|
def datetime_string_to_datetime(
|
961
|
-
datetime_string: str,
|
962
|
-
datetime_format: str = '%Y-%m-%d %H:%M:%S'
|
901
|
+
datetime_string: str, datetime_format: str = "%Y-%m-%d %H:%M:%S"
|
963
902
|
) -> datetime | None:
|
964
903
|
"""datetime string to datetime"""
|
965
904
|
try:
|
@@ -972,8 +911,7 @@ def datetime_string_to_datetime(
|
|
972
911
|
|
973
912
|
|
974
913
|
def datetime_string_to_timestamp(
|
975
|
-
datetime_string: str,
|
976
|
-
datetime_format: str = '%Y-%m-%d %H:%M:%S'
|
914
|
+
datetime_string: str, datetime_format: str = "%Y-%m-%d %H:%M:%S"
|
977
915
|
) -> int | None:
|
978
916
|
"""datetime string to timestamp"""
|
979
917
|
try:
|
@@ -985,18 +923,16 @@ def datetime_string_to_timestamp(
|
|
985
923
|
return None
|
986
924
|
|
987
925
|
|
988
|
-
def datetime_object(
|
989
|
-
date_time: datetime
|
990
|
-
) -> dict | None:
|
926
|
+
def datetime_object(date_time: datetime) -> dict | None:
|
991
927
|
"""datetime object"""
|
992
928
|
try:
|
993
929
|
return {
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
930
|
+
"date": date_time.strftime("%Y-%m-%d"),
|
931
|
+
"time": date_time.strftime("%H:%M:%S"),
|
932
|
+
"datetime_now": date_time.strftime("%Y-%m-%d %H:%M:%S"),
|
933
|
+
"datetime_minute": date_time.strftime("%Y-%m-%d %H:%M:00"),
|
934
|
+
"datetime_hour": date_time.strftime("%Y-%m-%d %H:00:00"),
|
935
|
+
"datetime_zero": date_time.strftime("%Y-%m-%d 00:00:00"),
|
1000
936
|
}
|
1001
937
|
except Exception as e:
|
1002
938
|
logger.exception(e)
|
@@ -1011,7 +947,7 @@ def shell(
|
|
1011
947
|
isfile: bool = False,
|
1012
948
|
sh_shell: str = "/bin/bash",
|
1013
949
|
sh_option: str | None = None,
|
1014
|
-
**kwargs
|
950
|
+
**kwargs,
|
1015
951
|
) -> subprocess.CompletedProcess | None:
|
1016
952
|
"""执行 Shell 命令 或 脚本"""
|
1017
953
|
|
@@ -1036,7 +972,11 @@ def shell(
|
|
1036
972
|
|
1037
973
|
# 构造命令
|
1038
974
|
if isfile:
|
1039
|
-
args =
|
975
|
+
args = (
|
976
|
+
[sh_shell, command]
|
977
|
+
if sh_option is None
|
978
|
+
else [sh_shell, sh_option, command]
|
979
|
+
)
|
1040
980
|
else:
|
1041
981
|
sh_option = sh_option or "-c"
|
1042
982
|
args = [sh_shell, sh_option, command]
|
@@ -1053,12 +993,10 @@ def shell(
|
|
1053
993
|
# --------------------------------------------------------------------------------------------------
|
1054
994
|
|
1055
995
|
|
1056
|
-
def json_file_parser(
|
1057
|
-
file: str
|
1058
|
-
) -> dict | None:
|
996
|
+
def json_file_parser(file: str) -> dict | None:
|
1059
997
|
"""JSON File Parser"""
|
1060
998
|
try:
|
1061
|
-
if not check_file_type(file,
|
999
|
+
if not check_file_type(file, "file"):
|
1062
1000
|
logger.error(f"no such file: {file}")
|
1063
1001
|
return None
|
1064
1002
|
with open(file, encoding="utf-8") as json_raw:
|
@@ -1068,6 +1006,7 @@ def json_file_parser(
|
|
1068
1006
|
logger.exception(e)
|
1069
1007
|
return None
|
1070
1008
|
|
1009
|
+
|
1071
1010
|
# json_raw = '''
|
1072
1011
|
# {
|
1073
1012
|
# "markdown.preview.fontSize": 14,
|
@@ -1087,10 +1026,7 @@ def json_file_parser(
|
|
1087
1026
|
# }
|
1088
1027
|
|
1089
1028
|
|
1090
|
-
def json_sort(
|
1091
|
-
string: str,
|
1092
|
-
**kwargs
|
1093
|
-
) -> str | None:
|
1029
|
+
def json_sort(string: str, **kwargs) -> str | None:
|
1094
1030
|
"""JSON Sort"""
|
1095
1031
|
try:
|
1096
1032
|
if not isTrue(string, str):
|
@@ -1104,15 +1040,13 @@ def json_sort(
|
|
1104
1040
|
# --------------------------------------------------------------------------------------------------
|
1105
1041
|
|
1106
1042
|
|
1107
|
-
def delete_files(
|
1108
|
-
files: str | list
|
1109
|
-
) -> bool:
|
1043
|
+
def delete_files(files: str | list) -> bool:
|
1110
1044
|
"""删除文件"""
|
1111
1045
|
try:
|
1112
1046
|
|
1113
|
-
if isinstance(files, str) and check_file_type(files,
|
1047
|
+
if isinstance(files, str) and check_file_type(files, "file"):
|
1114
1048
|
os.remove(files)
|
1115
|
-
logger.success(f
|
1049
|
+
logger.success(f"deleted file: {files}")
|
1116
1050
|
return True
|
1117
1051
|
|
1118
1052
|
if not isTrue(files, list):
|
@@ -1120,14 +1054,14 @@ def delete_files(
|
|
1120
1054
|
|
1121
1055
|
for _file in files:
|
1122
1056
|
|
1123
|
-
if isinstance(_file, str) and check_file_type(_file,
|
1057
|
+
if isinstance(_file, str) and check_file_type(_file, "file"):
|
1124
1058
|
try:
|
1125
1059
|
os.remove(_file)
|
1126
|
-
logger.success(f
|
1060
|
+
logger.success(f"deleted file: {_file}")
|
1127
1061
|
except Exception as e:
|
1128
|
-
logger.error(f
|
1062
|
+
logger.error(f"error file: {_file} {e}")
|
1129
1063
|
else:
|
1130
|
-
logger.error(f
|
1064
|
+
logger.error(f"error file: {_file}")
|
1131
1065
|
|
1132
1066
|
return True
|
1133
1067
|
|
@@ -1164,25 +1098,25 @@ def delete_directory(
|
|
1164
1098
|
"""
|
1165
1099
|
try:
|
1166
1100
|
|
1167
|
-
if isinstance(directory, str) and check_file_type(directory,
|
1101
|
+
if isinstance(directory, str) and check_file_type(directory, "dir"):
|
1168
1102
|
rmtree(directory)
|
1169
|
-
logger.success(f
|
1103
|
+
logger.success(f"deleted directory: {directory}")
|
1170
1104
|
return True
|
1171
1105
|
|
1172
1106
|
if not isTrue(directory, list):
|
1173
|
-
logger.error(f
|
1107
|
+
logger.error(f"error directory: {directory}")
|
1174
1108
|
return False
|
1175
1109
|
|
1176
1110
|
for _dir in directory:
|
1177
1111
|
|
1178
|
-
if isTrue(_dir, str) and check_file_type(_dir,
|
1112
|
+
if isTrue(_dir, str) and check_file_type(_dir, "dir"):
|
1179
1113
|
try:
|
1180
1114
|
rmtree(_dir)
|
1181
|
-
logger.success(f
|
1115
|
+
logger.success(f"deleted directory: {_dir}")
|
1182
1116
|
except Exception as e:
|
1183
|
-
logger.error(f
|
1117
|
+
logger.error(f"error directory: {_dir} {e}")
|
1184
1118
|
else:
|
1185
|
-
logger.error(f
|
1119
|
+
logger.error(f"error directory: {_dir}")
|
1186
1120
|
|
1187
1121
|
return True
|
1188
1122
|
|
@@ -1199,7 +1133,7 @@ def processor(
|
|
1199
1133
|
process_data: list,
|
1200
1134
|
process_num: int = 2,
|
1201
1135
|
thread: bool = False,
|
1202
|
-
**kwargs
|
1136
|
+
**kwargs,
|
1203
1137
|
) -> Any:
|
1204
1138
|
"""使用多线程或多进程对数据进行并行处理"""
|
1205
1139
|
|
@@ -1257,16 +1191,14 @@ def processor(
|
|
1257
1191
|
# --------------------------------------------------------------------------------------------------
|
1258
1192
|
|
1259
1193
|
|
1260
|
-
def create_empty_file(
|
1261
|
-
file: str | None = None
|
1262
|
-
) -> str | None:
|
1194
|
+
def create_empty_file(file: str | None = None) -> str | None:
|
1263
1195
|
"""create empty file"""
|
1264
1196
|
try:
|
1265
1197
|
if file is None:
|
1266
1198
|
# 当前时间戳(纳秒)
|
1267
1199
|
timestamp = time.time_ns()
|
1268
1200
|
# 空文件路径
|
1269
|
-
file = f
|
1201
|
+
file = f"/tmp/none_{timestamp}.txt"
|
1270
1202
|
# 创建一个空文件
|
1271
1203
|
# pylint: disable=R1732
|
1272
1204
|
open(file, "w", encoding="utf-8").close()
|
@@ -1285,14 +1217,12 @@ def uuid4_hex() -> str:
|
|
1285
1217
|
return uuid4().hex
|
1286
1218
|
|
1287
1219
|
|
1288
|
-
def increment_version(
|
1289
|
-
version: str
|
1290
|
-
) -> str | None:
|
1220
|
+
def increment_version(version: str) -> str | None:
|
1291
1221
|
"""版本号递增"""
|
1292
1222
|
try:
|
1293
|
-
version_numbers = version.split(
|
1223
|
+
version_numbers = version.split(".")
|
1294
1224
|
version_numbers[-1] = str(int(version_numbers[-1]) + 1)
|
1295
|
-
return
|
1225
|
+
return ".".join(version_numbers)
|
1296
1226
|
except Exception as e:
|
1297
1227
|
logger.exception(e)
|
1298
1228
|
return None
|
@@ -1301,9 +1231,7 @@ def increment_version(
|
|
1301
1231
|
# --------------------------------------------------------------------------------------------------
|
1302
1232
|
|
1303
1233
|
|
1304
|
-
def make_directory(
|
1305
|
-
directory: str
|
1306
|
-
) -> bool:
|
1234
|
+
def make_directory(directory: str) -> bool:
|
1307
1235
|
"""创建目录"""
|
1308
1236
|
try:
|
1309
1237
|
os.makedirs(directory)
|
@@ -1312,16 +1240,15 @@ def make_directory(
|
|
1312
1240
|
logger.exception(e)
|
1313
1241
|
return False
|
1314
1242
|
|
1315
|
-
|
1316
|
-
|
1317
|
-
) -> bool:
|
1243
|
+
|
1244
|
+
def change_directory(directory: str) -> bool:
|
1318
1245
|
"""改变目录"""
|
1319
1246
|
try:
|
1320
1247
|
|
1321
1248
|
if not isTrue(directory, str):
|
1322
1249
|
return False
|
1323
1250
|
|
1324
|
-
if not check_file_type(directory,
|
1251
|
+
if not check_file_type(directory, "dir"):
|
1325
1252
|
logger.error(f"no such directory: {directory}")
|
1326
1253
|
return False
|
1327
1254
|
|
@@ -1337,19 +1264,17 @@ def change_directory(
|
|
1337
1264
|
# --------------------------------------------------------------------------------------------------
|
1338
1265
|
|
1339
1266
|
|
1340
|
-
def load_toml_file(
|
1341
|
-
file: str
|
1342
|
-
) -> dict | None:
|
1267
|
+
def load_toml_file(file: str) -> dict | None:
|
1343
1268
|
"""Load TOML file"""
|
1344
|
-
info =
|
1269
|
+
info = "解析配置文件"
|
1345
1270
|
try:
|
1346
|
-
logger.info(f
|
1271
|
+
logger.info(f"{info}[执行]")
|
1347
1272
|
with open(file, "rb") as _file:
|
1348
1273
|
config = tomllib.load(_file)
|
1349
|
-
logger.success(f
|
1274
|
+
logger.success(f"{info}[成功]")
|
1350
1275
|
return config
|
1351
1276
|
except Exception as e:
|
1352
|
-
logger.error(f
|
1277
|
+
logger.error(f"{info}[失败]")
|
1353
1278
|
logger.exception(e)
|
1354
1279
|
return None
|
1355
1280
|
|
@@ -1359,12 +1284,12 @@ def git_clone(
|
|
1359
1284
|
local_repository: str,
|
1360
1285
|
timeout: int = 30,
|
1361
1286
|
delete: bool = False,
|
1362
|
-
log_prefix: str =
|
1287
|
+
log_prefix: str = "",
|
1363
1288
|
) -> bool:
|
1364
1289
|
"""GIT Clone"""
|
1365
1290
|
|
1366
1291
|
# 日志前缀
|
1367
|
-
log_prefix = f
|
1292
|
+
log_prefix = f"{log_prefix} [GitClone]"
|
1368
1293
|
|
1369
1294
|
try:
|
1370
1295
|
|
@@ -1385,10 +1310,10 @@ def git_clone(
|
|
1385
1310
|
|
1386
1311
|
# 克隆仓库
|
1387
1312
|
result = shell(
|
1388
|
-
command=f
|
1313
|
+
command=f"timeout -s 9 {timeout} git clone {git_repository} {local_repository}",
|
1389
1314
|
universal_newlines=True,
|
1390
1315
|
stdout=subprocess.PIPE,
|
1391
|
-
stderr=subprocess.STDOUT
|
1316
|
+
stderr=subprocess.STDOUT,
|
1392
1317
|
)
|
1393
1318
|
|
1394
1319
|
if result is None:
|
@@ -1399,19 +1324,19 @@ def git_clone(
|
|
1399
1324
|
|
1400
1325
|
if result_code != 0:
|
1401
1326
|
for i in result_info:
|
1402
|
-
logger.error(f
|
1327
|
+
logger.error(f"{log_prefix}{i}")
|
1403
1328
|
return False
|
1404
1329
|
|
1405
1330
|
return True
|
1406
1331
|
|
1407
1332
|
except Exception as e:
|
1408
|
-
logger.error(f
|
1333
|
+
logger.error(f"{log_prefix} [failed]")
|
1409
1334
|
logger.exception(e)
|
1410
1335
|
return False
|
1411
1336
|
|
1412
1337
|
|
1413
1338
|
def url_parse(
|
1414
|
-
url: str
|
1339
|
+
url: str,
|
1415
1340
|
# scheme: str = "http"
|
1416
1341
|
) -> ParseResult | None:
|
1417
1342
|
"""URL Parse"""
|
@@ -1430,6 +1355,7 @@ def url_parse(
|
|
1430
1355
|
logger.exception(e)
|
1431
1356
|
return None
|
1432
1357
|
|
1358
|
+
|
1433
1359
|
# def debug_log(
|
1434
1360
|
# log: None | str = None,
|
1435
1361
|
# exception: None | Exception = None,
|
@@ -1462,11 +1388,13 @@ def markdown_to_html(markdown_file: str, html_file: str, title: str) -> bool:
|
|
1462
1388
|
|
1463
1389
|
logger.info(f"{info} [开始]")
|
1464
1390
|
|
1465
|
-
if not check_arguments(
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1391
|
+
if not check_arguments(
|
1392
|
+
[
|
1393
|
+
(markdown_file, str, "markdown_to_html -> markdown_file"),
|
1394
|
+
(html_file, str, "markdown_to_html -> html_file"),
|
1395
|
+
(title, str, "markdown_to_html -> title"),
|
1396
|
+
]
|
1397
|
+
):
|
1470
1398
|
return False
|
1471
1399
|
|
1472
1400
|
# 读取 HTML模版 文件
|
@@ -1483,7 +1411,7 @@ def markdown_to_html(markdown_file: str, html_file: str, title: str) -> bool:
|
|
1483
1411
|
# 将 Markdown 转换为 HTML
|
1484
1412
|
logger.info(f"{info} [将 Markdown 转换为 HTML]")
|
1485
1413
|
# pylint: disable=E0606
|
1486
|
-
html_body = markdown.markdown(markdown_content, extensions=[
|
1414
|
+
html_body = markdown.markdown(markdown_content, extensions=["tables"]) # type: ignore
|
1487
1415
|
# pylint: enable=E0606
|
1488
1416
|
|
1489
1417
|
# 构造完整的 HTML
|
@@ -1493,7 +1421,7 @@ def markdown_to_html(markdown_file: str, html_file: str, title: str) -> bool:
|
|
1493
1421
|
|
1494
1422
|
# 保存为 HTML 文件
|
1495
1423
|
logger.info(f"{info} [保存为 HTML 文件: {html_file}]")
|
1496
|
-
with open(html_file, "w", encoding=
|
1424
|
+
with open(html_file, "w", encoding="utf-8") as _:
|
1497
1425
|
_.write(html_content)
|
1498
1426
|
|
1499
1427
|
logger.success(f"{info} [成功]")
|