kevin-toolbox-dev 1.4.5__py3-none-any.whl → 1.4.6__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.
kevin_toolbox/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.4.5"
1
+ __version__ = "1.4.6"
2
2
 
3
3
 
4
4
  import os
@@ -12,5 +12,5 @@ os.system(
12
12
  os.system(
13
13
  f'python {os.path.split(__file__)[0]}/env_info/check_validity_and_uninstall.py '
14
14
  f'--package_name kevin-toolbox-dev '
15
- f'--expiration_timestamp 1750434037 --verbose 0'
15
+ f'--expiration_timestamp 1753280251 --verbose 0'
16
16
  )
@@ -44,6 +44,12 @@ class Cache_Manager:
44
44
  当设置为 float 时表示占 upper_bound 的比例
45
45
  默认为 0.5
46
46
  strategy: <str/dict/Strategy_Base> 管理策略
47
+ 目前支持以下策略:
48
+ - ":by_initial_time:FIFO" 删除最后一次访问时间最久远的部分
49
+ - ":by_counts:LFU" 删除访问频率最低的部分
50
+ - ":by_last_time:LRU" 删除最后一次访问时间最久远的部分
51
+ - ":by_survival_time:LST" 删除访问频率最低的部分
52
+ 默认使用 LRU 策略
47
53
  cache: <str/dict/Cache_Base> 缓存种类
48
54
  """
49
55
  # 默认参数
@@ -0,0 +1 @@
1
+ from .write_excel_with_matrix import write_excel_with_matrix as write_with_matrix
@@ -0,0 +1,105 @@
1
+ import os
2
+ import openpyxl
3
+ from openpyxl.styles import Alignment, Font, PatternFill
4
+ from kevin_toolbox.patches.for_os import remove
5
+
6
+
7
+ # excel
8
+ def write_excel_with_matrix(matrix, file_path=None, file_obj=None, sheet_name="matrix",
9
+ column_label_ls=None, row_label_ls=None, column_title="", row_title="", main_title=""):
10
+ """
11
+ 将矩阵写入到 excel 文件中
12
+
13
+ 参数:
14
+ file_path: 要写入到哪个文件
15
+ file_obj: <openpyxl.Workbook> 文件对象
16
+ 注意!!以上两个参数指定其一即可,同时指定时候,以后者为准。
17
+ sheet_name: 要写入到哪个sheet页面
18
+ matrix: <np.array or np.matrix> 矩阵
19
+ column_label_ls, row_label_ls: 行列标签
20
+ column_title, row_title: 行列标题
21
+ main_title: 总标题
22
+ """
23
+ assert file_path is not None or file_obj is not None
24
+
25
+ if file_obj is None:
26
+ file_path = os.path.abspath(os.path.expanduser(file_path))
27
+ os.makedirs(os.path.dirname(file_path), exist_ok=True)
28
+ # 判断文件是否存在,不存在则新建,否则读取文件
29
+ if not os.path.isfile(file_path):
30
+ wb = openpyxl.Workbook() # 创建文件对象
31
+ # wb对象创建后,默认含有一个默认的名为 Sheet 的 页面,将其删除
32
+ ws_ = wb.active
33
+ wb.remove(ws_)
34
+ else:
35
+ wb = openpyxl.load_workbook(file_path)
36
+ else:
37
+ assert isinstance(file_obj, openpyxl.Workbook)
38
+ wb = file_obj
39
+ # 判断sheet是否存在,不存在则建立,否则先删除再建立
40
+ if sheet_name in wb.sheetnames:
41
+ ws = wb[sheet_name]
42
+ wb.remove(ws)
43
+ ws = wb.create_sheet(sheet_name)
44
+
45
+ # 开始写
46
+ matrix_r_offset, matrix_c_offset = 1, 1 # 矩阵的起始位置
47
+ r_offset, c_offset = 1, 1 # 目前的写入位置
48
+ for i in [main_title, column_title, column_label_ls]:
49
+ if i:
50
+ matrix_r_offset += 1
51
+ for j in [row_title, row_label_ls]:
52
+ if j:
53
+ matrix_c_offset += 1
54
+ # print(matrix)
55
+ matrix_row_num, matrix_column_num = matrix.shape[0], matrix.shape[1]
56
+ # 标题
57
+ alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
58
+ if main_title:
59
+ ws.merge_cells(start_row=r_offset, start_column=1, end_row=r_offset,
60
+ end_column=matrix_c_offset + matrix_column_num - 1)
61
+ ws.cell(row=r_offset, column=1).value = main_title
62
+ ws.cell(row=r_offset, column=1).alignment = alignment
63
+ ws.cell(row=r_offset, column=1).font = Font(size=10, bold=True, name='微软雅黑', color="000000")
64
+ r_offset += 1
65
+ if column_title:
66
+ ws.merge_cells(start_row=r_offset, start_column=matrix_c_offset, end_row=r_offset,
67
+ end_column=matrix_c_offset + matrix_column_num - 1)
68
+ ws.cell(row=r_offset, column=matrix_c_offset).value = column_title
69
+ ws.cell(row=r_offset, column=matrix_c_offset).alignment = alignment
70
+ ws.cell(row=r_offset, column=matrix_c_offset).font = Font(size=10, bold=True, name='微软雅黑', color="000000")
71
+ r_offset += 1
72
+ if row_title:
73
+ ws.merge_cells(start_row=matrix_r_offset, start_column=1, end_row=matrix_r_offset + matrix_row_num - 1,
74
+ end_column=1)
75
+ ws.cell(row=matrix_r_offset, column=1).value = row_title
76
+ ws.cell(row=matrix_r_offset, column=1).alignment = alignment
77
+ ws.cell(row=matrix_r_offset, column=1).font = Font(size=10, bold=True, name='微软雅黑', color="000000")
78
+ c_offset += 1
79
+ # 标签
80
+ if column_label_ls:
81
+ for i in range(matrix_column_num):
82
+ ws.cell(row=r_offset, column=matrix_c_offset + i).value = column_label_ls[i]
83
+ ws.cell(row=r_offset, column=matrix_c_offset + i).alignment = alignment
84
+ ws.cell(row=r_offset, column=matrix_c_offset + i).fill = PatternFill(patternType="solid",
85
+ start_color="33CCFF")
86
+ r_offset += 1
87
+ if row_label_ls:
88
+ for i in range(matrix_row_num):
89
+ ws.cell(row=matrix_r_offset + i, column=c_offset).value = row_label_ls[i]
90
+ ws.cell(row=matrix_r_offset + i, column=c_offset).alignment = alignment
91
+ ws.cell(row=matrix_r_offset + i, column=c_offset).fill = PatternFill(patternType="solid",
92
+ start_color="33CCFF")
93
+ c_offset += 1
94
+ # 校验,可省略
95
+ if not (c_offset == matrix_c_offset and r_offset == matrix_r_offset):
96
+ print("wrong here")
97
+ for r_ in range(matrix_row_num):
98
+ for c_ in range(matrix_column_num):
99
+ ws.cell(row=matrix_r_offset + r_, column=matrix_c_offset + c_).value = matrix[r_][c_]
100
+
101
+ if file_path is not None:
102
+ remove(file_path, ignore_errors=True)
103
+ wb.save(file_path)
104
+
105
+ return wb
@@ -23,6 +23,7 @@ def read_json(file_path=None, file_obj=None, converters=None, b_use_suggested_co
23
23
  """
24
24
  assert file_path is not None or file_obj is not None
25
25
  if file_path is not None:
26
+ file_path = os.path.abspath(os.path.expanduser(file_path))
26
27
  assert os.path.isfile(file_path), f'file {file_path} not found'
27
28
  file_obj = open(file_path, 'r')
28
29
  elif isinstance(file_obj, (BytesIO,)):
@@ -1 +1,2 @@
1
-
1
+ from .check_version_and_update import check_version_and_update
2
+ from .check_validity_and_uninstall import check_validity_and_uninstall
@@ -1,6 +1,4 @@
1
- import os
2
1
  import subprocess
3
- import argparse
4
2
  import time
5
3
 
6
4
  """
@@ -8,22 +6,44 @@ import time
8
6
  - 若超过指定的有效期,则卸载。
9
7
  """
10
8
 
11
- out_parser = argparse.ArgumentParser(description='check_validity_and_uninstall')
12
- out_parser.add_argument('--package_name', type=str, required=True)
13
- out_parser.add_argument('--expiration_timestamp', type=int, required=False, default=1e10)
14
- out_parser.add_argument('--verbose', type=int, required=False, default=1)
15
- args = out_parser.parse_args().__dict__
16
-
17
- cur_timestamp = time.time()
18
-
19
- if cur_timestamp > args["expiration_timestamp"]:
20
- ex = subprocess.Popen(f'pip uninstall {args["package_name"]} --yes', shell=True, stdout=subprocess.PIPE,
21
- stderr=subprocess.STDOUT)
22
- out, _ = ex.communicate()
23
- res = out.decode().strip()
24
- else:
25
- res = "still within the validity period"
26
-
27
- if args["verbose"]:
28
- # print(args)
29
- print(res)
9
+ DEFAULT_EXPIRATION_TIMESTAMP = 1e10
10
+
11
+
12
+ def check_validity_and_uninstall(package_name, expiration_timestamp=DEFAULT_EXPIRATION_TIMESTAMP):
13
+ """
14
+ 检查当前机器时间是否超过 expiration_timestamp 指定的有效期,若超过则卸载 package_name 对应的库
15
+ """
16
+ cur_timestamp = time.time()
17
+
18
+ b_success_uninstalled = False
19
+ if cur_timestamp > expiration_timestamp:
20
+ ex = subprocess.Popen(f'pip uninstall {package_name} --yes', shell=True, stdout=subprocess.PIPE,
21
+ stderr=subprocess.STDOUT)
22
+ out, _ = ex.communicate()
23
+ msg = out.decode().strip()
24
+ if ex.returncode == 0:
25
+ b_success_uninstalled = True
26
+ else:
27
+ msg = "still within the validity period"
28
+
29
+ res_s = dict(cur_timestamp=cur_timestamp, expiration_timestamp=expiration_timestamp,
30
+ b_success_uninstalled=b_success_uninstalled, msg=msg)
31
+ return res_s
32
+
33
+
34
+ if __name__ == '__main__':
35
+ import argparse
36
+
37
+ out_parser = argparse.ArgumentParser(description='check_validity_and_uninstall')
38
+ out_parser.add_argument('--package_name', type=str, required=True)
39
+ out_parser.add_argument('--expiration_timestamp', type=float, required=False, default=DEFAULT_EXPIRATION_TIMESTAMP)
40
+ out_parser.add_argument('--verbose', type=lambda x: bool(eval(x)), required=False, default=True)
41
+ args = out_parser.parse_args().__dict__
42
+
43
+ b_version = args.pop("verbose")
44
+
45
+ res_s_ = check_validity_and_uninstall(**args)
46
+
47
+ if b_version:
48
+ for k, v in res_s_.items():
49
+ print(f"{k}: {v}")
@@ -1,51 +1,72 @@
1
- import os
2
1
  import subprocess
3
- import argparse
4
- import version
5
-
6
- """
7
- 检查当前版本
8
- - 若在可用版本中,有比当前版本更高的版本,则更新到可以获取到的最新版本。
9
- """
10
-
11
- out_parser = argparse.ArgumentParser(description='check_version_and_update')
12
- out_parser.add_argument('--package_name', type=str, required=True)
13
- out_parser.add_argument('--cur_version', type=str, required=False)
14
- out_parser.add_argument('--available_versions', nargs='+', type=str, required=False)
15
- out_parser.add_argument('--verbose', type=int, required=False, default=1)
16
- args = out_parser.parse_args().__dict__
17
-
18
- # try to read cur_version
19
- if args["cur_version"] is None:
20
- ex = subprocess.Popen(f'pip list | grep "{args["package_name"]} "', shell=True, stdout=subprocess.PIPE)
21
- out, _ = ex.communicate()
22
- out = out.decode().strip()
23
- # breakpoint()
24
- args["cur_version"] = out.split(args["package_name"])[-1].strip()
25
-
26
- # try to read available versions
27
- if args["available_versions"] is None:
28
- ex = subprocess.Popen(f'pip install {args["package_name"]}==?', shell=True, stdout=subprocess.PIPE,
29
- stderr=subprocess.STDOUT)
30
- out, _ = ex.communicate()
31
- out = out.decode().strip()
32
- if "(from versions:" in out:
33
- v_ls = out.split("(from versions:")[-1].rsplit(")", 1)[0].split(",", -1)
34
- v_ls = [i.strip() for i in v_ls]
2
+
3
+ try:
4
+ from kevin_toolbox.env_info import version
5
+ except:
6
+ import version
7
+
8
+
9
+ def check_version_and_update(package_name, cur_version=None, available_versions=None):
10
+ """
11
+ 检查当前版本,并尝试更新
12
+ - 若在 pip 的可用版本中,有比当前版本更高的版本,则更新到可以获取到的最新版本。
13
+ """
14
+ # try to read cur_version
15
+ if cur_version is None:
16
+ ex = subprocess.Popen(f'pip list | grep "{package_name} "', shell=True, stdout=subprocess.PIPE)
17
+ out, _ = ex.communicate()
18
+ out = out.decode().strip()
19
+ # breakpoint()
20
+ cur_version = out.split(package_name)[-1].strip()
21
+
22
+ # try to read available versions
23
+ if available_versions is None:
24
+ ex = subprocess.Popen(f'pip install {package_name}==?', shell=True, stdout=subprocess.PIPE,
25
+ stderr=subprocess.STDOUT)
26
+ out, _ = ex.communicate()
27
+ out = out.decode().strip()
28
+ if "(from versions:" in out:
29
+ v_ls = out.split("(from versions:")[-1].rsplit(")", 1)[0].split(",", -1)
30
+ v_ls = [i.strip() for i in v_ls]
31
+ else:
32
+ v_ls = ["none"]
33
+ available_versions = version.sort_ls(version_ls=v_ls, reverse=True)
34
+
35
+ b_success_updated = False
36
+ new_version = None
37
+ if len(available_versions) > 0 and version.compare(available_versions[0], ">", cur_version):
38
+ ex = subprocess.Popen(
39
+ f'pip install {package_name}=={available_versions[0]} --no-dependencies',
40
+ shell=True, stdout=subprocess.PIPE
41
+ )
42
+ out, _ = ex.communicate()
43
+ msg = out.decode().strip()
44
+ if ex.returncode == 0:
45
+ b_success_updated = True
46
+ new_version = available_versions[0]
35
47
  else:
36
- v_ls = ["none"]
37
- args["available_versions"] = version.sort_ls(version_ls=v_ls, reverse=True)
38
-
39
- if len(args["available_versions"]) > 0 and version.compare(args["available_versions"][0], ">", args["cur_version"]):
40
- ex = subprocess.Popen(
41
- f'pip install {args["package_name"]}=={args["available_versions"][0]} --no-dependencies',
42
- shell=True, stdout=subprocess.PIPE
43
- )
44
- out, _ = ex.communicate()
45
- res = out.decode().strip()
46
- else:
47
- res = "Already the latest version, no need to update"
48
-
49
- if args["verbose"]:
50
- # print(args)
51
- print(res)
48
+ msg = "Already the latest version, no need to update"
49
+
50
+ res_s = dict(version_before_updated=cur_version, version_after_updated=new_version,
51
+ available_versions=available_versions, b_success_updated=b_success_updated, msg=msg)
52
+
53
+ return res_s
54
+
55
+
56
+ if __name__ == '__main__':
57
+ import argparse
58
+
59
+ out_parser = argparse.ArgumentParser(description='check_version_and_update')
60
+ out_parser.add_argument('--package_name', type=str, required=True)
61
+ out_parser.add_argument('--cur_version', type=str, required=False)
62
+ out_parser.add_argument('--available_versions', nargs='+', type=str, required=False)
63
+ out_parser.add_argument('--verbose', type=lambda x: bool(eval(x)), required=False, default=True)
64
+ args = out_parser.parse_args().__dict__
65
+
66
+ b_version = args.pop("verbose")
67
+
68
+ res_s_ = check_version_and_update(**args)
69
+
70
+ if b_version:
71
+ for k, v in res_s_.items():
72
+ print(f"{k}: {v}")
@@ -0,0 +1,52 @@
1
+ import os
2
+ import pytest
3
+ from kevin_toolbox.env_info import check_validity_and_uninstall, check_version_and_update
4
+ from kevin_toolbox.patches.for_test import check_consistency
5
+
6
+
7
+ @pytest.mark.parametrize(
8
+ "package_name, expiration_timestamp, expected_s",
9
+ [
10
+ ("tqdm", 1, {"b_success_uninstalled": True}),
11
+ ("tqdm", 1e10, {"b_success_uninstalled": False}),
12
+ ]
13
+ )
14
+ def test_check_validity_and_uninstall(package_name, expiration_timestamp, expected_s):
15
+ # call by func
16
+ res_s = check_validity_and_uninstall(package_name=package_name, expiration_timestamp=expiration_timestamp)
17
+ print(res_s)
18
+ for k, v in expected_s.items():
19
+ check_consistency(res_s[k], v)
20
+
21
+ # call by script
22
+ os.system(
23
+ f'python {os.path.dirname(os.path.split(__file__)[0])}/check_validity_and_uninstall.py ' +
24
+ (f'--package_name {package_name} ' if package_name is not None else '') +
25
+ (f'--expiration_timestamp {expiration_timestamp} ' if expiration_timestamp is not None else '') +
26
+ f'--verbose 1'
27
+ )
28
+
29
+
30
+ @pytest.mark.parametrize(
31
+ "package_name, cur_version, available_versions, expected_s",
32
+ [
33
+ ("tqdm", None, None, {}),
34
+ ("tqdm", "1.3.1", ["1.1.2", "1.1.3"], {"b_success_updated": False}),
35
+ ]
36
+ )
37
+ def test_check_version_and_update(package_name, cur_version, available_versions, expected_s):
38
+ # call by func
39
+ res_s = check_version_and_update(package_name=package_name, cur_version=cur_version,
40
+ available_versions=available_versions)
41
+ print(res_s)
42
+ for k, v in expected_s.items():
43
+ check_consistency(res_s[k], v)
44
+
45
+ # call by script
46
+ os.system(
47
+ f'python {os.path.dirname(os.path.split(__file__)[0])}/check_version_and_update.py ' +
48
+ (f'--package_name {package_name} ' if package_name is not None else '') +
49
+ (f'--cur_version {cur_version} ' if cur_version is not None else '') +
50
+ (f'--available_versions {available_versions} ' if available_versions is not None else '') +
51
+ f'--verbose 1'
52
+ )
@@ -2,7 +2,7 @@ import os
2
2
  from kevin_toolbox.patches.for_os import walk
3
3
 
4
4
 
5
- def find_files_in_dir(input_dir, suffix_ls, b_relative_path=True, b_ignore_case=True):
5
+ def find_files_in_dir(input_dir, suffix_ls=None, b_relative_path=True, b_ignore_case=True):
6
6
  """
7
7
  找出目录下带有给定后缀的所有文件的生成器
8
8
  主要利用了 for_os.walk 中的过滤规则进行实现
@@ -12,19 +12,24 @@ def find_files_in_dir(input_dir, suffix_ls, b_relative_path=True, b_ignore_case=
12
12
  b_relative_path: <bool> 是否返回相对路径
13
13
  b_ignore_case: <bool> 是否忽略大小写
14
14
  """
15
- suffix_ls = tuple(set(suffix_ls))
16
- suffix_ls = tuple(map(lambda x: x.lower(), suffix_ls)) if b_ignore_case else suffix_ls
17
- for root, dirs, files in walk(top=input_dir, topdown=True,
18
- ignore_s=[{
19
- "func": lambda _, b_is_symlink, path: b_is_symlink or not (
20
- path.lower() if b_ignore_case else path).endswith(suffix_ls),
21
- "scope": ["files", ]
22
- }]):
23
- for file in files:
24
- file_path = os.path.join(root, file)
25
- if b_relative_path:
26
- file_path = os.path.relpath(file_path, start=input_dir)
27
- yield file_path
28
-
29
-
30
-
15
+ if suffix_ls is not None:
16
+ suffix_ls = tuple(set(suffix_ls))
17
+ suffix_ls = tuple(map(lambda x: x.lower(), suffix_ls)) if b_ignore_case else suffix_ls
18
+ for root, dirs, files in walk(top=input_dir, topdown=True,
19
+ ignore_s=[{
20
+ "func": lambda _, b_is_symlink, path: b_is_symlink or not (
21
+ path.lower() if b_ignore_case else path).endswith(suffix_ls),
22
+ "scope": ["files", ]
23
+ }]):
24
+ for file in files:
25
+ file_path = os.path.join(root, file)
26
+ if b_relative_path:
27
+ file_path = os.path.relpath(file_path, start=input_dir)
28
+ yield file_path
29
+ else:
30
+ for root, dirs, files in walk(top=input_dir, topdown=True):
31
+ for file in files:
32
+ file_path = os.path.join(root, file)
33
+ if b_relative_path:
34
+ file_path = os.path.relpath(file_path, start=input_dir)
35
+ yield file_path
@@ -0,0 +1 @@
1
+ from .group_files_by_timestamp import group_files_by_timestamp
@@ -0,0 +1,90 @@
1
+ import os
2
+ from collections import defaultdict
3
+ import warnings
4
+ import time
5
+ from kevin_toolbox.patches.for_os import find_files_in_dir, copy, remove
6
+
7
+ # 获取文件的时间,返回time.struct_time格式
8
+ get_timestamp_method_s = dict(
9
+ c=lambda file_path: time.localtime(max(os.path.getctime(file_path), 0)),
10
+ a=lambda file_path: time.localtime(max(os.path.getatime(file_path), 0)),
11
+ m=lambda file_path: time.localtime(max(os.path.getmtime(file_path), 0))
12
+ )
13
+
14
+
15
+ def group_files_by_timestamp(input_dir, output_dir=None, suffix_ls=None, b_ignore_case=True,
16
+ grouping_rule=("%Y", "%m_%d"), timestamp_type="m", b_keep_source=True, b_verbose=False):
17
+ """
18
+ 将 input_dir 中的文件按照时间戳信息进行分组,输出到 output_dir 中
19
+
20
+ 参数:
21
+ input_dir: 输入目录
22
+ output_dir: 输出目录
23
+ 当设置为 None 时,将进行空跑,不实际复制文件到 output_dir 中
24
+ suffix_ls: <list of path/None> 指定要对带有哪些后缀的文件进行处理
25
+ 默认为 None 表示对所有文件都进行处理
26
+ b_ignore_case: <boolean> 忽略大小写
27
+ 默认为 True
28
+ grouping_rule: <str/list of str>分组规则
29
+ 默认为 ("%Y", "%m_%d"),此时将按照年月日进行分组。
30
+ 比如时间戳为 2016-03-20 11:45:39 的文件将被保存到 <output_dir>/2016/03_20 目录下
31
+ 其他可选样式:
32
+ - "%Y_%m" 精确到月
33
+ - ("%Y", "%m_%d", "%H-%M-%S") 精确到秒
34
+ 依次类推
35
+ timestamp_type: 使用哪个维度的时间戳
36
+ 有以下可选值:
37
+ - "m" 文件的修改时间
38
+ - "a" 文件的最近访问时间
39
+ - "c" 文件的创建时间
40
+ 默认为 "m"。
41
+ b_keep_source: <boolean> 是否保留 input_dir 中的原始文件
42
+ """
43
+ if isinstance(grouping_rule, str):
44
+ grouping_rule = [grouping_rule]
45
+ assert timestamp_type in ['m', 'a', 'c']
46
+ global get_timestamp_method_s
47
+ os.makedirs(output_dir, exist_ok=True)
48
+
49
+ get_timestamp = get_timestamp_method_s[timestamp_type]
50
+ res_s = defaultdict(lambda: dict(src_ls=[], dst_ls=[], b_success_ls=[]))
51
+ for file in find_files_in_dir(input_dir=input_dir, suffix_ls=suffix_ls, b_ignore_case=b_ignore_case,
52
+ b_relative_path=True):
53
+ src = os.path.join(input_dir, file)
54
+ timestamp = get_timestamp(src)
55
+ group_name = tuple(f'{time.strftime(i, timestamp)}' for i in grouping_rule)
56
+ out_folder = os.path.join(output_dir, *group_name)
57
+ dst = os.path.join(out_folder, os.path.basename(file))
58
+ os.makedirs(out_folder, exist_ok=True)
59
+ b_success = False
60
+ try:
61
+ copy(src=src, dst=dst)
62
+ if b_verbose:
63
+ print(f'{file} -> {out_folder}')
64
+ b_success = True
65
+ except:
66
+ warnings.warn(f'failed to copy file {file} to {out_folder}')
67
+ if not b_keep_source:
68
+ remove(path=dst, ignore_errors=True)
69
+ res_s[group_name]['b_success_ls'].append(b_success)
70
+ res_s[group_name]['src_ls'].append(file)
71
+ res_s[group_name]['dst_ls'].append(os.path.relpath(path=dst, start=output_dir))
72
+ return res_s
73
+
74
+
75
+ if __name__ == "__main__":
76
+ res = group_files_by_timestamp(suffix_ls=['.jpg', '.mp4', '.png', '.jpeg', '.mov', '.cr2', ".bmp"],
77
+ grouping_rule=("%Y-%m", "%Y_%m_%d"),
78
+ # "%Y-%m-%d %H:%M:%S" 2016-03-20 11:45:39 #"%a %b" Sat Mar
79
+ input_dir="/home/SENSETIME/xukaiming/Desktop/my_repos/python_projects/kevin_toolbox/kevin_toolbox/developing/photo_organization/test/test_data",
80
+ output_dir="/home/SENSETIME/xukaiming/Desktop/my_repos/python_projects/kevin_toolbox/kevin_toolbox/developing/photo_organization/test/test_data1",
81
+ timestamp_type="m")
82
+ print(res)
83
+
84
+ # timestamp_type = input("分类标准:m for modifytime \n c for createtime\n a for accesstime\n")
85
+ # copy_path_root = os.path.join(output_dir, \
86
+ # 'deal' + str(time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime())))
87
+ # group_by_timestamp(suffix_ls=['.MP4', '.jpg', '.mp4', '.png', '.JPG', '.MOV', '.CR2'],
88
+ # grouping_rule="%Y_%m_%d", # "%Y-%m-%d %H:%M:%S" 2016-03-20 11:45:39 #"%a %b" Sat Mar
89
+ # input_dir=input("please input the root path\n"),
90
+ # output_dir=input("please input the target_path\n"), timestamp_type=timestamp_type)
@@ -0,0 +1,76 @@
1
+ Metadata-Version: 2.1
2
+ Name: kevin-toolbox-dev
3
+ Version: 1.4.6
4
+ Summary: 一个常用的工具代码包集合
5
+ Home-page: https://github.com/cantbeblank96/kevin_toolbox
6
+ Download-URL: https://github.com/username/your-package/archive/refs/tags/v1.0.0.tar.gz
7
+ Author: kevin hsu
8
+ Author-email: xukaiming1996@163.com
9
+ License: MIT
10
+ Keywords: mathematics,pytorch,numpy,machine-learning,algorithm
11
+ Platform: UNKNOWN
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Requires-Python: >=3.6
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: torch (>=1.2.0)
18
+ Requires-Dist: numpy (>=1.19.0)
19
+ Provides-Extra: plot
20
+ Requires-Dist: matplotlib (>=3.0) ; extra == 'plot'
21
+ Provides-Extra: rest
22
+ Requires-Dist: pytest (>=6.2.5) ; extra == 'rest'
23
+ Requires-Dist: line-profiler (>=3.5) ; extra == 'rest'
24
+
25
+ # kevin_toolbox
26
+
27
+ 一个通用的工具代码包集合
28
+
29
+
30
+
31
+ 环境要求
32
+
33
+ ```shell
34
+ numpy>=1.19
35
+ pytorch>=1.2
36
+ ```
37
+
38
+ 安装方法:
39
+
40
+ ```shell
41
+ pip install kevin-toolbox --no-dependencies
42
+ ```
43
+
44
+
45
+
46
+ [项目地址 Repo](https://github.com/cantbeblank96/kevin_toolbox)
47
+
48
+ [使用指南 User_Guide](./notes/User_Guide.md)
49
+
50
+ [免责声明 Disclaimer](./notes/Disclaimer.md)
51
+
52
+ [版本更新记录](./notes/Release_Record.md):
53
+
54
+ - v 1.4.6 (2025-01-24)【new feature】
55
+
56
+ - data_flow.file
57
+ - modify json_.read(),支持输入路径使用 ~ 表示家目录。
58
+ - 【new feature】add excel,该模块用于 excel 表格处理。
59
+ - write_with_matrix():将矩阵写入到 excel 文件中
60
+
61
+ - patches.for_os
62
+ - modify find_files_in_dir(),支持 suffix_ls 设定 None 以表示不进行任何过滤。
63
+ - 【new feature】add organize,该模块用于文件整理。
64
+ - group_files_by_timestamp():将 input_dir 中的文件按照时间戳信息进行分组,输出到 output_dir 中。
65
+ - 添加了对应的测试用例。
66
+ - env_info
67
+ - 【new feature】add check_validity_and_uninstall(),检查当前机器时间是否超过 expiration_timestamp 指定的有效期,若超过则卸载 package_name 对应的库。
68
+ - 【new feature】add check_version_and_update(),检查当前库的版本,并尝试更新。
69
+ - 以上函数均系从同名脚本中抽取出来。
70
+ - 以上修改,均已添加了对应的测试用例。
71
+ - developing
72
+ - 【new feature】add photo_album_organization,该模块包含一系列整理相册相关的脚本。
73
+ - 0_group_by_timestamp.py :按照时间戳分组
74
+ - 1_merge_folders.py :将文件数量较少的目录合并
75
+
76
+
@@ -1,8 +1,8 @@
1
- kevin_toolbox/__init__.py,sha256=FXO6FMIEpptwoM95rn6R9rr5B72w0_y5nCnNKpjKTeI,410
1
+ kevin_toolbox/__init__.py,sha256=J3exMbMRFMTDP3RxpdeO_mXW0RvxbLdqQ_D0yxWUDmE,410
2
2
  kevin_toolbox/computer_science/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  kevin_toolbox/computer_science/algorithm/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
4
4
  kevin_toolbox/computer_science/algorithm/cache_manager/__init__.py,sha256=p2hddkZ1HfYF9-m2Hx-o9IotwQHd4QwDCePy2ADpTDA,41
5
- kevin_toolbox/computer_science/algorithm/cache_manager/cache_manager.py,sha256=e_mesTHjYlSV2VjXfmrA_osJRZhGe3nyS5SX1R5rfOQ,9151
5
+ kevin_toolbox/computer_science/algorithm/cache_manager/cache_manager.py,sha256=yQ6bqOSPcTrq4FLyuxDERz7Yv9ZWsenjb48q6KRStj4,9771
6
6
  kevin_toolbox/computer_science/algorithm/cache_manager/variable.py,sha256=j6yLezcZxf7gNdxwUxP0PPy2zauVpTr6KFMCg66m9lo,835
7
7
  kevin_toolbox/computer_science/algorithm/cache_manager/cache/__init__.py,sha256=Tt8XgrZsHP3J3f6UucGNhGAN8L7HiVjLLO1JzICR2Mc,70
8
8
  kevin_toolbox/computer_science/algorithm/cache_manager/cache/cache_base.py,sha256=Jln4Ey0sUGrzUqpkHaMP0S_z6NUw43iLnwMbmm-8msg,2229
@@ -72,8 +72,10 @@ kevin_toolbox/data_flow/core/reader/file_iterative_reader.py,sha256=l6UMYnvWwqQm
72
72
  kevin_toolbox/data_flow/core/reader/unified_reader.py,sha256=l6JxPoDUOdx2ZIPX2WLXbGU3VZtTd1AeHn5q6L8GWAI,2453
73
73
  kevin_toolbox/data_flow/core/reader/unified_reader_base.py,sha256=4gIADdV8UKpt2yD8dZjQsXFcF75nJ83ooIae3D7bw2s,11783
74
74
  kevin_toolbox/data_flow/file/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
75
+ kevin_toolbox/data_flow/file/excel/__init__.py,sha256=5m_rmklI6n6yk4rSAEW39pxzYTiAPjC4q69v-oz7Zvs,82
76
+ kevin_toolbox/data_flow/file/excel/write_excel_with_matrix.py,sha256=zrY_l0xCBpjqxm_9MoGpEXaZ4V_UwRMRgShessJ1sxA,5121
75
77
  kevin_toolbox/data_flow/file/json_/__init__.py,sha256=VAt8COS2tO3PJRuhSc43i35fEOlArFM_YahdTmEBaHE,85
76
- kevin_toolbox/data_flow/file/json_/read_json.py,sha256=BhAUCcagwPsSMaMeCJyyxDW3h9SGf1Dfvb0nXi6B_T8,2084
78
+ kevin_toolbox/data_flow/file/json_/read_json.py,sha256=RyCeNONMmvVOeX_F3kSSmED_nx4opipLe8OHJzXKZvQ,2151
77
79
  kevin_toolbox/data_flow/file/json_/write_json.py,sha256=uG6UnQ9KVhL_UWndGjvLLHF_UoGtOwVn4ADi1Gb1nRU,2417
78
80
  kevin_toolbox/data_flow/file/json_/converter/__init__.py,sha256=oQMgAgzELLq_f4LIIfz5E6l_E7g4lFsXqfmnJ3tPZTY,401
79
81
  kevin_toolbox/data_flow/file/json_/converter/convert_dict_key_to_number.py,sha256=SuSZj_HCqKZutHAJ5AttABnGBRZplPGQhMxJBt2Wlgc,559
@@ -136,10 +138,11 @@ kevin_toolbox/developing/temperate/iterator_base.py,sha256=FYMJ49ltbBcV92tUThx8Z
136
138
  kevin_toolbox/developing/temperate/my_iterator.py,sha256=dpFq_3wa4W2Y4SZfVl93T8oAEoy3gDOkQUdXB4p-cBQ,1663
137
139
  kevin_toolbox/developing/temperate/my_iterator_base.py,sha256=gLv9zdM987BHRghTfADUTwwQcMOV4WZWx-8-QvlV2uY,1214
138
140
  kevin_toolbox/developing/temperate/sequence_map_base.py,sha256=ha1EIMhn9lBF05s9niHLTuxhRslOx5faOk8UIjhhxUk,217
139
- kevin_toolbox/env_info/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
140
- kevin_toolbox/env_info/check_validity_and_uninstall.py,sha256=GskNfWwj2ak2AszV_0MMs2hBZb2tmRD0POO11UiouLM,879
141
- kevin_toolbox/env_info/check_version_and_update.py,sha256=og9ngoO6VhnlmUIkL0IZCyGXrI8rpZWRoN4t9FYGIkw,1953
141
+ kevin_toolbox/env_info/__init__.py,sha256=8Io5RN5RcbEoMLHY4wfMa4pJxa1w0SMaXBN4v6k5CrM,134
142
+ kevin_toolbox/env_info/check_validity_and_uninstall.py,sha256=FOLeVKRqqiFnAQpx_AmIc8D3UcJigzIx58XDTJgv_qw,1676
143
+ kevin_toolbox/env_info/check_version_and_update.py,sha256=GsL5tqodh7bbcXmWRT1vWy9GFRhqHJmTgEgvJg4GT5E,2739
142
144
  kevin_toolbox/env_info/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
145
+ kevin_toolbox/env_info/test/test_check_.py,sha256=wiIM_UVy_ksdq3la-pbF605Lhl5iW3a-0S_B74QzPT8,2054
143
146
  kevin_toolbox/env_info/test/test_variable_.py,sha256=n9To8UNfBSNey8Xy7relXcbrf0yX8ZoZzfJctd2fHBs,1657
144
147
  kevin_toolbox/env_info/test/test_version.py,sha256=xnF7RAcLSN3gpjIbVxFUV2-lmv0w7gOhdRa4XN0z0Q0,1728
145
148
  kevin_toolbox/env_info/variable_/__init__.py,sha256=qFs8ZZVBjAfj6IuUujYxaEnmXk6HEbtN6GXaIkuQhoM,81
@@ -317,11 +320,13 @@ kevin_toolbox/patches/for_optuna/serialize/for_trial/dump.py,sha256=FT-Z1rzCNUYz
317
320
  kevin_toolbox/patches/for_optuna/serialize/for_trial/load.py,sha256=2fpeeHPKA9bT7CjQ6DVRXOarF6IAA6_f2pXbB1rXcvE,796
318
321
  kevin_toolbox/patches/for_os/__init__.py,sha256=OhGxHkzI-oBek6M07kkrRgTQfY42l1Y2nOIR95JYD-g,219
319
322
  kevin_toolbox/patches/for_os/copy.py,sha256=PWFLu15DpIA4JZxatvphHANNn2H3nC93qTbLLxDl5NU,1509
320
- kevin_toolbox/patches/for_os/find_files_in_dir.py,sha256=KtjUJTMTNivAoWXGYgVkuaXukU1ktEAA-u8peusznmU,1266
323
+ kevin_toolbox/patches/for_os/find_files_in_dir.py,sha256=89bV4g-1-GBHwRr1K1KjJk7UvYM4LCvQmPVCVTZkX-g,1656
321
324
  kevin_toolbox/patches/for_os/pack.py,sha256=A6u4g3dfwXPtlU4gBcThNrktz6dO4DVi2wmQXytqfDI,656
322
325
  kevin_toolbox/patches/for_os/remove.py,sha256=PmwqzVJbyfdqwXn_T1F9d4Oar8CwQ2YFaqcZQkfnrnI,750
323
326
  kevin_toolbox/patches/for_os/unpack.py,sha256=d_fO7nPmExy1VIg7ADIMayCzjBBeFxvJLhIsulIRlzI,1047
324
327
  kevin_toolbox/patches/for_os/walk.py,sha256=LrtEeRUDwzZgu_zGZ-kPsFJd4D-8R8ECHW6WNdEsDSw,8376
328
+ kevin_toolbox/patches/for_os/organize/__init__.py,sha256=GGSUvdHzYK9prCwz4XCm1lp4g4A_o9tuU_l3bNi5MMs,63
329
+ kevin_toolbox/patches/for_os/organize/group_files_by_timestamp.py,sha256=CpGKMJ7GIywTgumo3TyM_SXgaeh0Gtl9xIkm6-YKJE4,5222
325
330
  kevin_toolbox/patches/for_os/path/__init__.py,sha256=M4XaYawTDj-SjwZ_bWS5D38lqzPujxvAtVEvzRLDhtU,108
326
331
  kevin_toolbox/patches/for_os/path/find_illegal_chars.py,sha256=QmqzeaeBY50of28qtvfEmnDW9xeVIfCXi6QVzLzngks,1416
327
332
  kevin_toolbox/patches/for_os/path/replace_illegal_chars.py,sha256=OhxndHEJ8xK-ip-sWYQehTNSho8eNFeKj2iwPHR02os,1672
@@ -349,7 +354,7 @@ kevin_toolbox/patches/for_torch/nn/__init__.py,sha256=aJs3RMqRzQmd8KKDmQW9FxwCqS
349
354
  kevin_toolbox/patches/for_torch/nn/lambda_layer.py,sha256=KUuLiX_Dr4bvRmpAaCW5QTDWDcnMPRnw0jg4NNXTFhM,223
350
355
  kevin_toolbox/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
351
356
  kevin_toolbox/utils/variable.py,sha256=PxUmp9w4CKKcKHjgdVNF_Iaw5gwPPOd4aY_Oe5F9U1M,133
352
- kevin_toolbox_dev-1.4.5.dist-info/METADATA,sha256=-CIxxD1zrM4_RrzEyB7KVLxUsjQfRGqSdUiBI1z_tzM,2818
353
- kevin_toolbox_dev-1.4.5.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
354
- kevin_toolbox_dev-1.4.5.dist-info/top_level.txt,sha256=S5TeRGF-PwlhsaUEPTI-f2vWrpLmh3axpyI6v-Fi75o,14
355
- kevin_toolbox_dev-1.4.5.dist-info/RECORD,,
357
+ kevin_toolbox_dev-1.4.6.dist-info/METADATA,sha256=G-yjDl5MP56GAhXAoPnGcqJPGqpuUiSt4X4B90dsP7c,2578
358
+ kevin_toolbox_dev-1.4.6.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
359
+ kevin_toolbox_dev-1.4.6.dist-info/top_level.txt,sha256=S5TeRGF-PwlhsaUEPTI-f2vWrpLmh3axpyI6v-Fi75o,14
360
+ kevin_toolbox_dev-1.4.6.dist-info/RECORD,,
@@ -1,73 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: kevin-toolbox-dev
3
- Version: 1.4.5
4
- Summary: 一个常用的工具代码包集合
5
- Home-page: https://github.com/cantbeblank96/kevin_toolbox
6
- Download-URL: https://github.com/username/your-package/archive/refs/tags/v1.0.0.tar.gz
7
- Author: kevin hsu
8
- Author-email: xukaiming1996@163.com
9
- License: MIT
10
- Keywords: mathematics,pytorch,numpy,machine-learning,algorithm
11
- Platform: UNKNOWN
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 3
15
- Requires-Python: >=3.6
16
- Description-Content-Type: text/markdown
17
- Requires-Dist: torch (>=1.2.0)
18
- Requires-Dist: numpy (>=1.19.0)
19
- Provides-Extra: plot
20
- Requires-Dist: matplotlib (>=3.0) ; extra == 'plot'
21
- Provides-Extra: rest
22
- Requires-Dist: pytest (>=6.2.5) ; extra == 'rest'
23
- Requires-Dist: line-profiler (>=3.5) ; extra == 'rest'
24
-
25
- # kevin_toolbox
26
-
27
- 一个通用的工具代码包集合
28
-
29
-
30
-
31
- 环境要求
32
-
33
- ```shell
34
- numpy>=1.19
35
- pytorch>=1.2
36
- ```
37
-
38
- 安装方法:
39
-
40
- ```shell
41
- pip install kevin-toolbox --no-dependencies
42
- ```
43
-
44
-
45
-
46
- [项目地址 Repo](https://github.com/cantbeblank96/kevin_toolbox)
47
-
48
- [使用指南 User_Guide](./notes/User_Guide.md)
49
-
50
- [免责声明 Disclaimer](./notes/Disclaimer.md)
51
-
52
- [版本更新记录](./notes/Release_Record.md):
53
-
54
- - v 1.4.5 (2024-12-22)【bug fix】【new feature】
55
- - data_flow.file.json_
56
- - modify write(),支持输入路径使用 ~ 表示家目录。
57
- - env_info
58
- - 【new feature】add variable_,该模块主要包含于处理环境变量相关的函数和类。
59
- - Env_Vars_Parser:解释并替换字符串中${}形式指定的环境变量,支持以下几种方式:
60
- - "${HOME}" 家目录
61
- - "${SYS:<var_name>}" 其他系统环境变量
62
- - "${KVT_XXX<ndl_name>}" 读取配置文件 ~/.kvt_cfg/.xxx.json 中的变量(xxx将被自动转为小写)
63
- - "${/xxx.../xxx.json<ndl_name>}" 读取指定路径下的配置文件 /xxx.../xxx.json 中的变量
64
- - env_vars_parser:类 Env_Vars_Parser 的默认实例
65
- - 添加了对应的测试用例。
66
- - nested_dict_list
67
- - 【new feature】modify get_value() and set_value() for parsed_name input,在字符串name的基础上,进一步支持使用结构化的(root_node, method_ls, node_ls)形式的name作为输入。
68
- - 相较于字符串形式的name,结构化的name因不用解释而效率更高,推荐使用。
69
- - 【new feature】modify serializer.read() and write(),支持通过 nodes_dir 指定节点内容保存在哪个目录下,同时支持在 settings 中为每个处理模式单独指定其使用的 nodes_dir 和 saved_node_name_format。
70
- - 有了该功能,允许多个ndl文件共享多个节点内容,形式更加自由。
71
- - 添加了对应的测试用例。
72
-
73
-