kevin-toolbox-dev 1.4.9__py3-none-any.whl → 1.4.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. kevin_toolbox/__init__.py +2 -2
  2. kevin_toolbox/computer_science/algorithm/cache_manager/__init__.py +1 -0
  3. kevin_toolbox/computer_science/algorithm/cache_manager/cache/cache_base.py +10 -0
  4. kevin_toolbox/computer_science/algorithm/cache_manager/cache/memo_cache.py +17 -0
  5. kevin_toolbox/computer_science/algorithm/cache_manager/cache_manager.py +24 -74
  6. kevin_toolbox/computer_science/algorithm/cache_manager/cache_manager_wto_strategy.py +157 -0
  7. kevin_toolbox/computer_science/algorithm/for_seq/__init__.py +1 -0
  8. kevin_toolbox/computer_science/algorithm/for_seq/sample_subset_most_evenly.py +52 -0
  9. kevin_toolbox/computer_science/algorithm/redirector/__init__.py +1 -0
  10. kevin_toolbox/computer_science/algorithm/redirector/redirectable_sequence_fetcher.py +258 -0
  11. kevin_toolbox/computer_science/algorithm/sampler/__init__.py +1 -0
  12. kevin_toolbox/computer_science/algorithm/sampler/reservoir_sampler.py +116 -0
  13. kevin_toolbox/computer_science/algorithm/statistician/accumulator_base.py +1 -1
  14. kevin_toolbox/data_flow/file/kevin_notation/kevin_notation_reader.py +18 -7
  15. kevin_toolbox/data_flow/file/kevin_notation/kevin_notation_writer.py +8 -1
  16. kevin_toolbox/data_flow/file/kevin_notation/test/test_data/data_0.py +2 -1
  17. kevin_toolbox/data_flow/file/kevin_notation/test/test_kevin_notation.py +1 -4
  18. kevin_toolbox/data_flow/file/kevin_notation/test/test_kevin_notation_debug.py +16 -4
  19. kevin_toolbox/data_flow/file/markdown/table/get_format.py +3 -0
  20. kevin_toolbox/nested_dict_list/get_nodes.py +9 -0
  21. kevin_toolbox/nested_dict_list/value_parser/replace_identical_with_reference.py +2 -4
  22. kevin_toolbox/patches/for_logging/build_logger.py +3 -1
  23. kevin_toolbox_dev-1.4.11.dist-info/METADATA +67 -0
  24. {kevin_toolbox_dev-1.4.9.dist-info → kevin_toolbox_dev-1.4.11.dist-info}/RECORD +26 -20
  25. kevin_toolbox_dev-1.4.9.dist-info/METADATA +0 -75
  26. {kevin_toolbox_dev-1.4.9.dist-info → kevin_toolbox_dev-1.4.11.dist-info}/WHEEL +0 -0
  27. {kevin_toolbox_dev-1.4.9.dist-info → kevin_toolbox_dev-1.4.11.dist-info}/top_level.txt +0 -0
kevin_toolbox/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.4.9"
1
+ __version__ = "1.4.11"
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 1758638079 --verbose 0'
15
+ f'--expiration_timestamp 1760340881 --verbose 0'
16
16
  )
@@ -1 +1,2 @@
1
+ from .cache_manager_wto_strategy import Cache_Manager_wto_Strategy
1
2
  from .cache_manager import Cache_Manager
@@ -12,6 +12,7 @@ class Cache_Base(ABC):
12
12
  - 判断是否命中 has()
13
13
  - 获取缓存已占空间 len()
14
14
  - 清空所有内容 clear()
15
+ - 加载和保存状态 load_state_dict(), state_dict()
15
16
  等方法。
16
17
 
17
18
  对外提供:
@@ -21,6 +22,7 @@ class Cache_Base(ABC):
21
22
  - 判断是否命中 has()
22
23
  - 获取缓存已占空间 len()
23
24
  - 清空所有内容 clear()
25
+ - 加载和保存状态 load_state_dict(), state_dict()
24
26
  等接口。
25
27
  """
26
28
 
@@ -69,6 +71,14 @@ class Cache_Base(ABC):
69
71
  def clear(self):
70
72
  pass
71
73
 
74
+ @abstractmethod
75
+ def load_state_dict(self, state_dict):
76
+ pass
77
+
78
+ @abstractmethod
79
+ def state_dict(self, b_deepcopy=True):
80
+ pass
81
+
72
82
  def __getitem__(self, key):
73
83
  # self[key]
74
84
  return self.read(key=key)
@@ -30,6 +30,23 @@ class Memo_Cache(Cache_Base):
30
30
  def clear(self):
31
31
  self.cache_s.clear()
32
32
 
33
+ def load_state_dict(self, state_dict):
34
+ """
35
+ 加载状态
36
+ """
37
+ self.clear()
38
+ self.cache_s.update(state_dict["cache_s"])
39
+
40
+ def state_dict(self, b_deepcopy=True):
41
+ """
42
+ 获取状态
43
+ """
44
+ temp = {"cache_s": self.cache_s}
45
+ if b_deepcopy:
46
+ import kevin_toolbox.nested_dict_list as ndl
47
+ temp = ndl.copy_(var=temp, b_deepcopy=True, b_keep_internal_references=True)
48
+ return temp
49
+
33
50
 
34
51
  # 添加其他别名
35
52
  for name in [":in_memory:Memo", ":in_memory:MC", ":in_memory:memory"]:
@@ -2,9 +2,10 @@ import time
2
2
  from .strategy import Strategy_Base
3
3
  from .cache import Cache_Base
4
4
  from .variable import CACHE_STRATEGY_REGISTRY, CACHE_BUILDER_REGISTRY
5
+ from .cache_manager_wto_strategy import Cache_Manager_wto_Strategy
5
6
 
6
7
 
7
- class Cache_Manager:
8
+ class Cache_Manager(Cache_Manager_wto_Strategy):
8
9
  """
9
10
  缓存管理器
10
11
 
@@ -14,6 +15,7 @@ class Cache_Manager:
14
15
  - 删除并返回条目 pop(key)
15
16
  - 判断是否有该条目 has()
16
17
  - 清空所有内容 clear()
18
+ - 加载和保存状态 load_state_dict(), state_dict()
17
19
 
18
20
  并支持以下用法:
19
21
  通过 len(.) 获取缓存大小,通过 in 操作符判断是否有某个条目
@@ -95,29 +97,7 @@ class Cache_Manager:
95
97
  self.cache = cache # type:Cache_Base
96
98
  self.metadata_s = dict() # 保存条目的相关信息
97
99
 
98
- def add(self, key, value, b_allow_overwrite=True):
99
- """
100
- 以 key 为查询键,将 value 添加到缓存中
101
-
102
- 参数:
103
- key:
104
- value:
105
- b_allow_overwrite: <boolean> 是否允许覆写缓存中已有的条目
106
- 默认为 True
107
- """
108
- # 判断是否需要进行覆写
109
- if self.cache.has(key=key):
110
- if id(value) != id(self.cache.read(key=key)):
111
- if b_allow_overwrite:
112
- self.__remove_of_cache(key=key)
113
- else:
114
- raise KeyError(f'key: {key} already exists, modification of existing entries is prohibited')
115
- else:
116
- return
117
- # 记录到缓存
118
- self.__write_of_cache(key=key, value=value)
119
-
120
- def __write_of_cache(self, key, value):
100
+ def _write_of_cache(self, key, value):
121
101
  """
122
102
  向缓存中新增不存在的条目
123
103
  """
@@ -143,9 +123,9 @@ class Cache_Manager:
143
123
  assert len(suggest_keys) == len(self.cache) - self.paras["refactor_size"], \
144
124
  f'expect {len(self.cache) - self.paras["refactor_size"]} deletion suggestions, but got {len(suggest_keys)}'
145
125
  for key in suggest_keys:
146
- self.__remove_of_cache(key=key)
126
+ self._remove_of_cache(key=key)
147
127
 
148
- def __remove_of_cache(self, key):
128
+ def _remove_of_cache(self, key):
149
129
  """
150
130
  从缓存中删除存在的条目
151
131
  """
@@ -154,43 +134,7 @@ class Cache_Manager:
154
134
  # 通知策略管理器
155
135
  self.strategy.notified_by_remove_of_cache(key=key, metadata=metadata)
156
136
 
157
- def get(self, key, b_add_if_not_found=False, default_factory=None, **kwargs):
158
- """
159
- 获取 key 对应的值
160
-
161
- 参数:
162
- key: <hashable>
163
- default: 默认值
164
- 当 key 在缓存中不存在时返回
165
- default_factory: <callable> 用于产生默认值的函数
166
- 当 key 在缓存中不存在时返回该函数的结果
167
- 使用该参数相对于 default 能延迟默认值的产生(如果不需要用到默认值就不生成),提高效率
168
- 注意!!上面两个参数同时指定时,将以前者为准。
169
- b_add_if_not_found: <boolean> 当 key 在缓存中不存在时,是否添加到缓存中
170
- 默认为 False
171
- """
172
- if self.cache.has(key=key):
173
- value = self.__read_of_cache(key=key)
174
- elif "default" in kwargs or callable(default_factory):
175
- value = kwargs["default"] if "default" in kwargs else default_factory()
176
- if b_add_if_not_found:
177
- self.__write_of_cache(key=key, value=value)
178
- else:
179
- raise KeyError(key)
180
- return value
181
-
182
- def pop(self, key):
183
- """
184
- 从缓存中删除 key 对应的条目,并返回该条目的值
185
- """
186
- if self.cache.has(key=key):
187
- value = self.__read_of_cache(key=key)
188
- self.__remove_of_cache(key=key)
189
- else:
190
- raise KeyError(key)
191
- return value
192
-
193
- def __read_of_cache(self, key):
137
+ def _read_of_cache(self, key):
194
138
  """
195
139
  读取缓存中 已经存在的 条目
196
140
  """
@@ -205,20 +149,26 @@ class Cache_Manager:
205
149
 
206
150
  return value
207
151
 
208
- def has(self, key):
209
- """
210
- 判断 key 是否在缓存中
211
- 注意!!不会更新 metadata
212
- """
213
- return self.cache.has(key=key)
214
-
215
152
  def clear(self):
216
153
  self.cache.clear()
217
154
  self.metadata_s.clear()
218
155
  self.strategy.notified_by_clear_of_cache()
219
156
 
220
- def __len__(self):
221
- return len(self.cache)
157
+ # ---------------------- 用于保存和加载状态 ---------------------- #
158
+ def load_state_dict(self, state_dict):
159
+ """
160
+ 加载状态
161
+ """
162
+ self.clear()
163
+ self.cache.load_state_dict(state_dict=state_dict["cache"])
164
+ self.metadata_s.update(state_dict["metadata_s"])
222
165
 
223
- def __contains__(self, key):
224
- return self.has(key)
166
+ def state_dict(self, b_deepcopy=True):
167
+ """
168
+ 获取状态
169
+ """
170
+ temp = {"cache": self.cache.state_dict(b_deepcopy=False), "metadata_s": self.metadata_s}
171
+ if b_deepcopy:
172
+ import kevin_toolbox.nested_dict_list as ndl
173
+ temp = ndl.copy_(var=temp, b_deepcopy=True, b_keep_internal_references=True)
174
+ return temp
@@ -0,0 +1,157 @@
1
+ from .cache import Cache_Base
2
+ from .variable import CACHE_BUILDER_REGISTRY
3
+
4
+
5
+ class Cache_Manager_wto_Strategy:
6
+ """
7
+ 不绑定任何策略的缓存管理器
8
+
9
+ 提供以下接口:
10
+ - 添加条目 add(key, value, b_allow_overwrite)
11
+ - 获取条目 get(key, b_add_if_not_found, default_factory, default)
12
+ - 删除并返回条目 pop(key)
13
+ - 判断是否有该条目 has()
14
+ - 清空所有内容 clear()
15
+ - 加载和保存状态 load_state_dict(), state_dict()
16
+
17
+ 并支持以下用法:
18
+ 通过 len(.) 获取缓存大小,通过 in 操作符判断是否有某个条目
19
+ """
20
+
21
+ def __init__(self, **kwargs):
22
+ """
23
+ 参数:
24
+ cache: <str/dict/Cache_Base> 缓存种类
25
+ """
26
+ # 默认参数
27
+ paras = {
28
+ "cache": ":in_memory:Memo",
29
+ }
30
+
31
+ # 获取参数
32
+ paras.update(kwargs)
33
+
34
+ # 校验参数
35
+ # cache
36
+ assert isinstance(paras["cache"], (str, dict, Cache_Base)), \
37
+ "cache must be a string, dict of paras or a Cache_Base object"
38
+ if isinstance(paras["cache"], str):
39
+ cache = CACHE_BUILDER_REGISTRY.get(name=paras["cache"])()
40
+ elif isinstance(paras["cache"], dict):
41
+ cache = CACHE_BUILDER_REGISTRY.get(name=paras["cache"]["name"])(**paras["cache"].get("paras", dict()))
42
+ else:
43
+ cache = paras["cache"]
44
+
45
+ self.paras = paras
46
+ self.cache = cache # type:Cache_Base
47
+
48
+ def _write_of_cache(self, key, value):
49
+ """
50
+ 向缓存中新增不存在的条目
51
+ """
52
+ #
53
+ self.cache.write(key=key, value=value)
54
+
55
+ def _remove_of_cache(self, key):
56
+ """
57
+ 从缓存中删除存在的条目
58
+ """
59
+ self.cache.remove(key=key)
60
+
61
+ def _read_of_cache(self, key):
62
+ """
63
+ 读取缓存中 已经存在的 条目
64
+ """
65
+ return self.cache.read(key=key)
66
+
67
+ def add(self, key, value, b_allow_overwrite=True):
68
+ """
69
+ 以 key 为查询键,将 value 添加到缓存中
70
+
71
+ 参数:
72
+ key:
73
+ value:
74
+ b_allow_overwrite: <boolean> 是否允许覆写缓存中已有的条目
75
+ 默认为 True
76
+ """
77
+ # 判断是否需要进行覆写
78
+ if self.cache.has(key=key):
79
+ if id(value) != id(self.cache.read(key=key)):
80
+ if b_allow_overwrite:
81
+ self._remove_of_cache(key=key)
82
+ else:
83
+ raise KeyError(f'key: {key} already exists, modification of existing entries is prohibited')
84
+ else:
85
+ return
86
+ # 记录到缓存
87
+ self._write_of_cache(key=key, value=value)
88
+
89
+ def get(self, key, b_add_if_not_found=False, default_factory=None, **kwargs):
90
+ """
91
+ 获取 key 对应的值
92
+
93
+ 参数:
94
+ key: <hashable>
95
+ default: 默认值
96
+ 当 key 在缓存中不存在时返回
97
+ default_factory: <callable> 用于产生默认值的函数
98
+ 当 key 在缓存中不存在时返回该函数的结果
99
+ 使用该参数相对于 default 能延迟默认值的产生(如果不需要用到默认值就不生成),提高效率
100
+ 注意!!上面两个参数同时指定时,将以前者为准。
101
+ b_add_if_not_found: <boolean> 当 key 在缓存中不存在时,是否添加到缓存中
102
+ 默认为 False
103
+ """
104
+ if self.cache.has(key=key):
105
+ value = self._read_of_cache(key=key)
106
+ elif "default" in kwargs or callable(default_factory):
107
+ value = kwargs["default"] if "default" in kwargs else default_factory()
108
+ if b_add_if_not_found:
109
+ self._write_of_cache(key=key, value=value)
110
+ else:
111
+ raise KeyError(key)
112
+ return value
113
+
114
+ def pop(self, key):
115
+ """
116
+ 从缓存中删除 key 对应的条目,并返回该条目的值
117
+ """
118
+ if self.cache.has(key=key):
119
+ value = self._read_of_cache(key=key)
120
+ self._remove_of_cache(key=key)
121
+ else:
122
+ raise KeyError(key)
123
+ return value
124
+
125
+ def has(self, key):
126
+ """
127
+ 判断 key 是否在缓存中
128
+ 注意!!不会更新 metadata
129
+ """
130
+ return self.cache.has(key=key)
131
+
132
+ def clear(self):
133
+ self.cache.clear()
134
+
135
+ # ---------------------- 用于保存和加载状态 ---------------------- #
136
+ def load_state_dict(self, state_dict):
137
+ """
138
+ 加载状态
139
+ """
140
+ self.clear()
141
+ self.cache.load_state_dict(state_dict=state_dict["cache"])
142
+
143
+ def state_dict(self, b_deepcopy=True):
144
+ """
145
+ 获取状态
146
+ """
147
+ temp = {"cache": self.cache.state_dict(b_deepcopy=False)}
148
+ if b_deepcopy:
149
+ import kevin_toolbox.nested_dict_list as ndl
150
+ temp = ndl.copy_(var=temp, b_deepcopy=True, b_keep_internal_references=True)
151
+ return temp
152
+
153
+ def __len__(self):
154
+ return len(self.cache)
155
+
156
+ def __contains__(self, key):
157
+ return self.has(key)
@@ -1,3 +1,4 @@
1
1
  from .get_subsets import get_subsets
2
2
  from .flatten_list import flatten_list
3
3
  from .chunk_generator import chunk_generator
4
+ from .sample_subset_most_evenly import sample_subset_most_evenly
@@ -0,0 +1,52 @@
1
+ import math
2
+ from kevin_toolbox.patches.for_numpy.random import get_rng
3
+
4
+
5
+ def sample_subset_most_evenly(inputs, ratio=None, nums=None, seed=None, rng=None, b_shuffle_the_tail=True):
6
+ """
7
+ 对列表按给定比例or数量进行采样,并返回一个新的列表,并保证列表中每个元素在新列表中的占比尽量相近
8
+ 说明:
9
+ 根据 ratio/nums 的值,将输入列表重复复制并可能随机打乱尾部元素以保证每个元素都有等概率被选取,
10
+ 生成一个新列表,其长度约为 len(inputs) * ratio nums。
11
+ 以 ratio 为例:
12
+ - 当 ratio 为整数时,返回原列表重复多次的结果;
13
+ - 当 ratio 为非整数时,除了重复复制整数倍部分外,
14
+ 还会从打乱后的列表中随机选取部分元素以达到目标长度。
15
+
16
+ 参数:
17
+ inputs: <iterable> 输入列表或其他可迭代对象
18
+ ratio: <float> 采样比例,
19
+ 采样后新列表长度约为 len(inputs) * ratio
20
+ nums: <int> 采样数量。
21
+ b_shuffle_the_tail: <boolean> 是否对尾部进行随机打乱
22
+ 默认为 True
23
+ seed: <int, optional> 随机种子,用于生成确定性随机数
24
+ 默认为 None
25
+ rng: <Random, optional> 随机数生成器实例
26
+ 仅在b_shuffle_the_tail=True时,以上两个参数起效,且仅需指定一个即可。
27
+
28
+ """
29
+ if nums is None:
30
+ assert ratio is not None
31
+ nums = math.ceil(len(inputs) * ratio)
32
+ assert nums >= 0
33
+ if len(inputs) == 0 or nums == 0:
34
+ return []
35
+
36
+ inputs = list(inputs)
37
+ temp = inputs.copy()
38
+ if b_shuffle_the_tail:
39
+ rng = get_rng(seed=seed, rng=rng)
40
+ rng.shuffle(temp)
41
+
42
+ outputs = [] + inputs * math.floor(nums / len(inputs)) + temp[:nums % len(inputs)]
43
+ return outputs
44
+
45
+
46
+ if __name__ == '__main__':
47
+ print(sample_subset_most_evenly(range(5), ratio=8 / 5, seed=114, b_shuffle_the_tail=False))
48
+ print(sample_subset_most_evenly(range(5), ratio=8 / 5, seed=114, b_shuffle_the_tail=True))
49
+
50
+ #
51
+ print(sample_subset_most_evenly(range(5), nums=8, seed=114, b_shuffle_the_tail=False))
52
+ print(sample_subset_most_evenly(range(5), nums=8, seed=114, b_shuffle_the_tail=True))
@@ -0,0 +1 @@
1
+ from .redirectable_sequence_fetcher import Redirectable_Sequence_Fetcher