halib 0.2.21__py3-none-any.whl → 0.2.27__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.
- halib/exp/core/param_gen.py +19 -38
- halib/exp/perf/perfcalc.py +31 -1
- halib/utils/dict.py +203 -9
- {halib-0.2.21.dist-info → halib-0.2.27.dist-info}/METADATA +4 -2
- {halib-0.2.21.dist-info → halib-0.2.27.dist-info}/RECORD +8 -8
- {halib-0.2.21.dist-info → halib-0.2.27.dist-info}/WHEEL +0 -0
- {halib-0.2.21.dist-info → halib-0.2.27.dist-info}/licenses/LICENSE.txt +0 -0
- {halib-0.2.21.dist-info → halib-0.2.27.dist-info}/top_level.txt +0 -0
halib/exp/core/param_gen.py
CHANGED
|
@@ -4,6 +4,11 @@ import numpy as np
|
|
|
4
4
|
from itertools import product
|
|
5
5
|
from typing import Dict, Any, List, Iterator, Optional
|
|
6
6
|
from ...filetype import yamlfile
|
|
7
|
+
from ...utils.dict import DictUtils
|
|
8
|
+
|
|
9
|
+
# Assuming DictUtils is available in the scope or imported
|
|
10
|
+
# from .dict_utils import DictUtils
|
|
11
|
+
|
|
7
12
|
|
|
8
13
|
class ParamGen:
|
|
9
14
|
"""
|
|
@@ -38,6 +43,7 @@ class ParamGen:
|
|
|
38
43
|
keys (List[str]): List of flattened dot-notation keys being swept.
|
|
39
44
|
values (List[List[Any]]): List of value options for each key.
|
|
40
45
|
"""
|
|
46
|
+
|
|
41
47
|
def __init__(
|
|
42
48
|
self, sweep_cfg: Dict[str, Any], base_cfg: Optional[Dict[str, Any]] = None
|
|
43
49
|
):
|
|
@@ -50,7 +56,12 @@ class ParamGen:
|
|
|
50
56
|
self.base_cfg = base_cfg if base_cfg is not None else {}
|
|
51
57
|
|
|
52
58
|
# Recursively flatten the nested sweep config into dot-notation keys
|
|
53
|
-
|
|
59
|
+
# Refactored to use DictUtils, passing our custom leaf logic
|
|
60
|
+
flat_sweep = DictUtils.flatten(sweep_cfg, is_leaf_predicate=self._is_sweep_leaf)
|
|
61
|
+
|
|
62
|
+
# Expand values (ranges, strings) which DictUtils leaves as-is
|
|
63
|
+
self.param_space = {k: self._expand_val(v) for k, v in flat_sweep.items()}
|
|
64
|
+
|
|
54
65
|
self.keys = list(self.param_space.keys())
|
|
55
66
|
self.values = list(self.param_space.values())
|
|
56
67
|
|
|
@@ -66,13 +77,16 @@ class ParamGen:
|
|
|
66
77
|
|
|
67
78
|
# 2. Deep copy base and update with current params
|
|
68
79
|
new_cfg = copy.deepcopy(self.base_cfg)
|
|
69
|
-
|
|
80
|
+
|
|
81
|
+
# Refactored: Unflatten the specific params, then deep merge
|
|
82
|
+
update_structure = DictUtils.unflatten(flat_params)
|
|
83
|
+
DictUtils.deep_update(new_cfg, update_structure)
|
|
70
84
|
|
|
71
85
|
# 3. Store metadata (Optional)
|
|
72
86
|
# if "_meta" not in new_cfg:
|
|
73
87
|
# new_cfg["_meta"] = {}
|
|
74
88
|
# We unflatten the sweep params here so the log is readable
|
|
75
|
-
# new_cfg["_meta"]["sweep_params"] =
|
|
89
|
+
# new_cfg["_meta"]["sweep_params"] = DictUtils.unflatten(flat_params)
|
|
76
90
|
|
|
77
91
|
yield new_cfg
|
|
78
92
|
|
|
@@ -124,27 +138,8 @@ class ParamGen:
|
|
|
124
138
|
combinations.append(flat_dict)
|
|
125
139
|
return combinations
|
|
126
140
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
nested = {}
|
|
130
|
-
self._apply_updates(nested, flat_dict)
|
|
131
|
-
return nested
|
|
132
|
-
|
|
133
|
-
def _flatten_params(
|
|
134
|
-
self, cfg: Dict[str, Any], parent_key: str = ""
|
|
135
|
-
) -> Dict[str, List[Any]]:
|
|
136
|
-
"""Recursively converts nested dicts into flat dot-notation keys."""
|
|
137
|
-
flat = {}
|
|
138
|
-
for key, val in cfg.items():
|
|
139
|
-
current_key = f"{parent_key}.{key}" if parent_key else key
|
|
140
|
-
|
|
141
|
-
if self._is_sweep_leaf(val):
|
|
142
|
-
flat[current_key] = self._expand_val(val)
|
|
143
|
-
elif isinstance(val, dict):
|
|
144
|
-
flat.update(self._flatten_params(val, current_key))
|
|
145
|
-
else:
|
|
146
|
-
flat[current_key] = [val]
|
|
147
|
-
return flat
|
|
141
|
+
# Note: _unflatten, _flatten_params, and _apply_updates have been removed
|
|
142
|
+
# as they are replaced by DictUtils methods.
|
|
148
143
|
|
|
149
144
|
def _is_sweep_leaf(self, val: Any) -> bool:
|
|
150
145
|
if isinstance(val, list):
|
|
@@ -173,17 +168,3 @@ class ParamGen:
|
|
|
173
168
|
return np.arange(val["start"], val["stop"], step).tolist()
|
|
174
169
|
|
|
175
170
|
return [val]
|
|
176
|
-
|
|
177
|
-
def _apply_updates(
|
|
178
|
-
self, cfg: Dict[str, Any], updates: Dict[str, Any]
|
|
179
|
-
) -> Dict[str, Any]:
|
|
180
|
-
"""Deep merges dot-notation updates into cfg."""
|
|
181
|
-
for key, val in updates.items():
|
|
182
|
-
parts = key.split(".")
|
|
183
|
-
target = cfg
|
|
184
|
-
for part in parts[:-1]:
|
|
185
|
-
if part not in target:
|
|
186
|
-
target[part] = {}
|
|
187
|
-
target = target[part]
|
|
188
|
-
target[parts[-1]] = val
|
|
189
|
-
return cfg
|
halib/exp/perf/perfcalc.py
CHANGED
|
@@ -210,7 +210,37 @@ class PerfCalc(ABC): # Abstract base class for performance calculation
|
|
|
210
210
|
**kwargs,
|
|
211
211
|
) -> Tuple[Union[List[OrderedDict], pd.DataFrame], Optional[str]]:
|
|
212
212
|
"""
|
|
213
|
-
|
|
213
|
+
Orchestrates the calculation of performance metrics and saves the results to a CSV.
|
|
214
|
+
|
|
215
|
+
This method acts as a pipeline:
|
|
216
|
+
1. Calculates metrics (Accuracy, F1, etc.) using `raw_metrics_data`.
|
|
217
|
+
2. Merges in `extra_data` (metadata) to the results.
|
|
218
|
+
3. Saves the combined data to a CSV file.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
raw_metrics_data (Union[List[dict], dict]):
|
|
222
|
+
The input data required for metric calculations.
|
|
223
|
+
Structure: A dictionary where keys are metric names (e.g., 'accuracy')
|
|
224
|
+
and values are inputs (e.g., {'preds': ..., 'target': ...}).
|
|
225
|
+
|
|
226
|
+
extra_data (Optional[Union[List[dict], dict]]):
|
|
227
|
+
Static metadata or context to attach to the result rows.
|
|
228
|
+
These fields are NOT used for calculation but are passed through
|
|
229
|
+
to the final output (DataFrame/CSV).
|
|
230
|
+
|
|
231
|
+
Example:
|
|
232
|
+
If extra_data={'model_version': 'v1.0', 'epoch': 5},
|
|
233
|
+
the output CSV will include columns 'model_version' and 'epoch'.
|
|
234
|
+
|
|
235
|
+
*args, **kwargs:
|
|
236
|
+
Additional arguments passed to `calc_exp_perf_metrics` or `save_results_to_csv`
|
|
237
|
+
(e.g., `outfile`, `return_df`).
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Tuple[Union[List[OrderedDict], pd.DataFrame], Optional[str]]:
|
|
241
|
+
A tuple containing:
|
|
242
|
+
1. The results as a DataFrame (if return_df=True) or a list of dicts.
|
|
243
|
+
2. The path to the saved output file (or None if save failed).
|
|
214
244
|
"""
|
|
215
245
|
metric_names = self.get_metric_backend().metric_names
|
|
216
246
|
|
halib/utils/dict.py
CHANGED
|
@@ -1,9 +1,203 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
from pygments.token import Other
|
|
2
|
+
from typing import Dict, Any, Callable, Optional
|
|
3
|
+
from rich.pretty import pprint
|
|
4
|
+
import json
|
|
5
|
+
import hashlib
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DictUtils:
|
|
9
|
+
"""
|
|
10
|
+
General-purpose dictionary manipulation utilities.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def flatten(
|
|
15
|
+
d: Dict[str, Any],
|
|
16
|
+
parent_key: str = "",
|
|
17
|
+
sep: str = ".",
|
|
18
|
+
is_leaf_predicate: Optional[Callable[[Any], bool]] = None,
|
|
19
|
+
) -> Dict[str, Any]:
|
|
20
|
+
"""
|
|
21
|
+
Recursively flattens a nested dictionary.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
d: The dictionary to flatten.
|
|
25
|
+
parent_key: Prefix for keys (used during recursion).
|
|
26
|
+
sep: Separator for dot-notation keys.
|
|
27
|
+
is_leaf_predicate: Optional function that returns True if a value should
|
|
28
|
+
be treated as a leaf (value) rather than a branch to recurse.
|
|
29
|
+
Useful if you have dicts you don't want flattened.
|
|
30
|
+
"""
|
|
31
|
+
items = []
|
|
32
|
+
for k, v in d.items():
|
|
33
|
+
new_key = f"{parent_key}{sep}{k}" if parent_key else k
|
|
34
|
+
|
|
35
|
+
# Check if we should treat this as a leaf (custom logic)
|
|
36
|
+
if is_leaf_predicate and is_leaf_predicate(v):
|
|
37
|
+
items.append((new_key, v))
|
|
38
|
+
# Standard recursion
|
|
39
|
+
elif isinstance(v, dict):
|
|
40
|
+
items.extend(
|
|
41
|
+
DictUtils.flatten(
|
|
42
|
+
v, new_key, sep=sep, is_leaf_predicate=is_leaf_predicate
|
|
43
|
+
).items()
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
items.append((new_key, v))
|
|
47
|
+
return dict(items)
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def unflatten(flat_dict: Dict[str, Any], sep: str = ".") -> Dict[str, Any]:
|
|
51
|
+
"""
|
|
52
|
+
Converts flat dot-notation keys back to nested dictionaries.
|
|
53
|
+
e.g., {'a.b': 1} -> {'a': {'b': 1}}
|
|
54
|
+
"""
|
|
55
|
+
nested = {}
|
|
56
|
+
for key, value in flat_dict.items():
|
|
57
|
+
DictUtils.deep_set(nested, key, value, sep=sep)
|
|
58
|
+
return nested
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def deep_update(base: Dict[str, Any], update: Dict[str, Any]) -> Dict[str, Any]:
|
|
62
|
+
"""
|
|
63
|
+
Recursively merges 'update' dict into 'base' dict.
|
|
64
|
+
|
|
65
|
+
Unlike the standard `dict.update()`, which replaces nested dictionaries entirely,
|
|
66
|
+
this method enters nested dictionaries and updates them key-by-key. This preserves
|
|
67
|
+
existing keys in 'base' that are not present in 'update'.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
base: The original dictionary to modify.
|
|
71
|
+
update: The dictionary containing new values.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
The modified 'base' dictionary.
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
>>> base = {'model': {'name': 'v1', 'dropout': 0.5}}
|
|
78
|
+
>>> new_vals = {'model': {'name': 'v2'}}
|
|
79
|
+
>>> # Standard update would delete 'dropout'. deep_update keeps it:
|
|
80
|
+
>>> DictUtils.deep_update(base, new_vals)
|
|
81
|
+
{'model': {'name': 'v2', 'dropout': 0.5}}
|
|
82
|
+
"""
|
|
83
|
+
for k, v in update.items():
|
|
84
|
+
if isinstance(v, dict) and k in base and isinstance(base[k], dict):
|
|
85
|
+
DictUtils.deep_update(base[k], v)
|
|
86
|
+
else:
|
|
87
|
+
base[k] = v
|
|
88
|
+
return base
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def deep_set(d: Dict[str, Any], dot_key: str, value: Any, sep: str = ".") -> None:
|
|
92
|
+
"""
|
|
93
|
+
Sets a value in a nested dictionary using a dot-notation key path.
|
|
94
|
+
Automatically creates any missing intermediate dictionaries.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
d: The dictionary to modify.
|
|
98
|
+
dot_key: The path to the value (e.g., "model.backbone.layers").
|
|
99
|
+
value: The value to set.
|
|
100
|
+
sep: The separator used in the key (default is ".").
|
|
101
|
+
|
|
102
|
+
Example:
|
|
103
|
+
>>> cfg = {}
|
|
104
|
+
>>> DictUtils.deep_set(cfg, "a.b.c", 10)
|
|
105
|
+
>>> print(cfg)
|
|
106
|
+
{'a': {'b': {'c': 10}}}
|
|
107
|
+
"""
|
|
108
|
+
parts = dot_key.split(sep)
|
|
109
|
+
target = d
|
|
110
|
+
for part in parts[:-1]:
|
|
111
|
+
if part not in target:
|
|
112
|
+
target[part] = {}
|
|
113
|
+
target = target[part]
|
|
114
|
+
if not isinstance(target, dict):
|
|
115
|
+
# Handle conflict if a path was previously a value (e.g. overwriting a leaf)
|
|
116
|
+
target = {}
|
|
117
|
+
target[parts[-1]] = value
|
|
118
|
+
|
|
119
|
+
@staticmethod
|
|
120
|
+
def get_unique_hash(input_dict, length=12):
|
|
121
|
+
"""
|
|
122
|
+
Returns a unique hash string for a dictionary.
|
|
123
|
+
|
|
124
|
+
:param input_dict: The dictionary params
|
|
125
|
+
:param length: The desired length of the hash string (default 12)
|
|
126
|
+
"""
|
|
127
|
+
assert length >= 12, "Hash length must be at least 12 to ensure uniqueness."
|
|
128
|
+
# 1. Sort keys to ensure {a:1, b:2} == {b:2, a:1}
|
|
129
|
+
config_str = json.dumps(input_dict, sort_keys=True)
|
|
130
|
+
|
|
131
|
+
# 2. Generate full SHA-256 hash (64 chars long)
|
|
132
|
+
full_hash = hashlib.sha256(config_str.encode("utf-8")).hexdigest()
|
|
133
|
+
|
|
134
|
+
# 3. Truncate to desired length
|
|
135
|
+
return full_hash[:length]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_update():
|
|
139
|
+
# --- Setup ---
|
|
140
|
+
base_config = {
|
|
141
|
+
"model": {
|
|
142
|
+
"name": "ResNet50",
|
|
143
|
+
"layers": 50,
|
|
144
|
+
"details": {
|
|
145
|
+
"activation": "relu",
|
|
146
|
+
"dropout": 0.5, # <--- We want to keep this
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
"epochs": 10,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
new_settings = {
|
|
153
|
+
"model": {"details": {"activation": "gelu"}} # <--- We only want to change this
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
b1 = base_config.copy()
|
|
157
|
+
b2 = base_config.copy()
|
|
158
|
+
n1 = new_settings.copy()
|
|
159
|
+
n2 = new_settings.copy()
|
|
160
|
+
|
|
161
|
+
pprint("Base Config:")
|
|
162
|
+
pprint(base_config)
|
|
163
|
+
pprint("New Settings:")
|
|
164
|
+
pprint(new_settings)
|
|
165
|
+
print("*" * 40)
|
|
166
|
+
pprint(
|
|
167
|
+
"Task: Update base_config with new_settings, preserving unspecified nested keys."
|
|
168
|
+
)
|
|
169
|
+
print("*" * 40)
|
|
170
|
+
|
|
171
|
+
# --- Standard Update (The Problem) ---
|
|
172
|
+
pprint("Normal Update Result:")
|
|
173
|
+
b1.update(n1)
|
|
174
|
+
pprint(b1) # type: ignore[return-value]
|
|
175
|
+
|
|
176
|
+
# --- Deep Update (The Solution) ---
|
|
177
|
+
pprint("Deep Update Result:")
|
|
178
|
+
pprint(DictUtils.deep_update(b2, n2))
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_hash():
|
|
182
|
+
# --- Usage ---
|
|
183
|
+
cfg1 = {"learning_rate": 0.01, "batch_size": 32, "optimizer": "adam"}
|
|
184
|
+
cfg1_shuffle = {
|
|
185
|
+
"batch_size": 32,
|
|
186
|
+
"optimizer": "adam",
|
|
187
|
+
"learning_rate": 0.01,
|
|
188
|
+
}
|
|
189
|
+
cfg2 = {"learning_rate": 0.02, "batch_size": 32, "optimizer": "adam"}
|
|
190
|
+
hash1 = DictUtils.get_unique_hash(cfg1)
|
|
191
|
+
hash2 = DictUtils.get_unique_hash(cfg1_shuffle)
|
|
192
|
+
hash3 = DictUtils.get_unique_hash(cfg2)
|
|
193
|
+
pprint(f"Config 1 Hash: {hash1}")
|
|
194
|
+
pprint(f"Config 1_shuffle Hash: {hash2}")
|
|
195
|
+
pprint(f"Config 2 Hash: {hash3}")
|
|
196
|
+
|
|
197
|
+
assert hash1 == hash2, "Hashes should match for identical dicts."
|
|
198
|
+
assert hash1 != hash3, "Hashes should differ for different dicts."
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
if __name__ == "__main__":
|
|
202
|
+
test_update()
|
|
203
|
+
test_hash()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: halib
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.27
|
|
4
4
|
Summary: Small library for common tasks
|
|
5
5
|
Author: Hoang Van Ha
|
|
6
6
|
Author-email: hoangvanhauit@gmail.com
|
|
@@ -56,7 +56,9 @@ Dynamic: summary
|
|
|
56
56
|
|
|
57
57
|
## v0.2.x (Experiment & Core Updates)
|
|
58
58
|
|
|
59
|
-
### **v0.2.
|
|
59
|
+
### **v0.2.27**
|
|
60
|
+
- ✨ **New Feature:** Added `utils.dict.DictUtils` for advanced dictionary manipulations (merging, filtering, transforming).
|
|
61
|
+
|
|
60
62
|
- ✨ **New Feature:** Added `common.common.pprint_stack_trace` to print stack traces with optional custom messages and force stop capability.
|
|
61
63
|
|
|
62
64
|
- 🚀 **Improvement:** `exp.perf.profiler` - allow to export *report dict* as csv files for further analysis
|
|
@@ -23,7 +23,7 @@ halib/exp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
23
23
|
halib/exp/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
halib/exp/core/base_config.py,sha256=Js2oVDt7qwT7eV_sOUWw6XXl569G1bX6ls-VYAx2gWY,5032
|
|
25
25
|
halib/exp/core/base_exp.py,sha256=fknJVmW6ubbapOggbkrbNWgc1ZXcUz_FE3wMyuIGX7M,5180
|
|
26
|
-
halib/exp/core/param_gen.py,sha256=
|
|
26
|
+
halib/exp/core/param_gen.py,sha256=y4elw6bmoBMKRzS7KDLXp0xqC3x27gg0r6wrcTBfidc,6725
|
|
27
27
|
halib/exp/core/wandb_op.py,sha256=powL2QyLBqF-6PUGAOqd60s1npHLLKJxPns3S4hKeNo,4160
|
|
28
28
|
halib/exp/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
halib/exp/data/dataclass_util.py,sha256=OPZzqmug0be4JEq0hJ68pKjnyl0PRYQMVJGhKw1kvyk,1382
|
|
@@ -32,7 +32,7 @@ halib/exp/data/torchloader.py,sha256=oWUplXlGd1IB6CqdRd-mGe-DfMjjZxz9hQ7SWONb-0s
|
|
|
32
32
|
halib/exp/perf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
halib/exp/perf/flop_calc.py,sha256=Kb3Gwqc7QtGALZzfyYXBA_9SioReJpTJdUX84kqj-Aw,6907
|
|
34
34
|
halib/exp/perf/gpu_mon.py,sha256=vD41_ZnmPLKguuq9X44SB_vwd9JrblO4BDzHLXZhhFY,2233
|
|
35
|
-
halib/exp/perf/perfcalc.py,sha256=
|
|
35
|
+
halib/exp/perf/perfcalc.py,sha256=zb0eGt24kPVC2HTq9M095wP6y8TqOicWy52BxAigap0,19834
|
|
36
36
|
halib/exp/perf/perfmetrics.py,sha256=qRiNiCKGUSTLY7gPMVMuVHGAAyeosfGWup2eM4490aw,5485
|
|
37
37
|
halib/exp/perf/perftb.py,sha256=IWElg3OB5dmhfxnY8pMZvkL2y_EnvLmEx3gJlpUR1Fs,31066
|
|
38
38
|
halib/exp/perf/profiler.py,sha256=Nx-Y1V3pCbaEOisY1sDT8s0yGFs3J6TUmutZslseoNI,19201
|
|
@@ -95,15 +95,15 @@ halib/system/filesys.py,sha256=102J2fkQhmH1_-HQVy2FQ4NOU8LTjMWV3hToT_APtq8,4401
|
|
|
95
95
|
halib/system/path.py,sha256=k_pveq41uXEzKPU2KTIdqjUSb4MVM-hCFXHGeO-6x6Q,3694
|
|
96
96
|
halib/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
97
97
|
halib/utils/dataclass_util.py,sha256=rj2IMLlUzbm2OlF5_B2dRTk9njZOaF7tTjYkOsq8uLY,1416
|
|
98
|
-
halib/utils/dict.py,sha256=
|
|
98
|
+
halib/utils/dict.py,sha256=tUmwKNbTLOyGLl5nKYdT8QIoS4pBFfdsZHCJ6NQCgp4,6922
|
|
99
99
|
halib/utils/dict_op.py,sha256=wYE6Iw-_CnCWdMg9tpJ2Y2-e2ESkW9FxmdBkZkbUh80,299
|
|
100
100
|
halib/utils/gpu_mon.py,sha256=vD41_ZnmPLKguuq9X44SB_vwd9JrblO4BDzHLXZhhFY,2233
|
|
101
101
|
halib/utils/list.py,sha256=BM-8sRhYyqF7bh4p7TQtV7P_gnFruUCA6DTUOombaZg,337
|
|
102
102
|
halib/utils/listop.py,sha256=Vpa8_2fI0wySpB2-8sfTBkyi_A4FhoFVVvFiuvW8N64,339
|
|
103
103
|
halib/utils/tele_noti.py,sha256=-4WXZelCA4W9BroapkRyIdUu9cUVrcJJhegnMs_WpGU,5928
|
|
104
104
|
halib/utils/video.py,sha256=zLoj5EHk4SmP9OnoHjO8mLbzPdtq6gQPzTQisOEDdO8,3261
|
|
105
|
-
halib-0.2.
|
|
106
|
-
halib-0.2.
|
|
107
|
-
halib-0.2.
|
|
108
|
-
halib-0.2.
|
|
109
|
-
halib-0.2.
|
|
105
|
+
halib-0.2.27.dist-info/licenses/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
|
|
106
|
+
halib-0.2.27.dist-info/METADATA,sha256=Or9W2uqrbMh_PQd3KCda2KZRuuH4Wi7I4aicUPq2Ks0,7719
|
|
107
|
+
halib-0.2.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
108
|
+
halib-0.2.27.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
|
|
109
|
+
halib-0.2.27.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|