lkj 0.1.38__py3-none-any.whl → 0.1.40__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.
- lkj/__init__.py +7 -6
- lkj/dicts.py +60 -7
- {lkj-0.1.38.dist-info → lkj-0.1.40.dist-info}/METADATA +1 -1
- {lkj-0.1.38.dist-info → lkj-0.1.40.dist-info}/RECORD +7 -7
- {lkj-0.1.38.dist-info → lkj-0.1.40.dist-info}/LICENSE +0 -0
- {lkj-0.1.38.dist-info → lkj-0.1.40.dist-info}/WHEEL +0 -0
- {lkj-0.1.38.dist-info → lkj-0.1.40.dist-info}/top_level.txt +0 -0
lkj/__init__.py
CHANGED
|
@@ -30,13 +30,14 @@ from lkj.strings import (
|
|
|
30
30
|
truncate_string_with_marker, # Deprecated: Backcompatibility alias
|
|
31
31
|
)
|
|
32
32
|
from lkj.loggers import (
|
|
33
|
-
print_with_timestamp,
|
|
34
|
-
print_progress,
|
|
35
|
-
log_calls,
|
|
36
|
-
clog,
|
|
33
|
+
print_with_timestamp, # Prints with a timestamp and optional refresh.
|
|
34
|
+
print_progress, # an alias often used for print_with_timestamp
|
|
35
|
+
log_calls, # Decorator that adds logging before and after the function's call.
|
|
36
|
+
clog, # Conditional logger
|
|
37
37
|
ErrorInfo,
|
|
38
|
-
return_error_info_on_error,
|
|
39
|
-
wrapped_print,
|
|
38
|
+
return_error_info_on_error, # Decorator that returns traceback and local variables on error.
|
|
39
|
+
wrapped_print, # Prints a string or list ensuring the total line width does not exceed `max_width`.
|
|
40
|
+
CallOnError, # Context manager that calls a function on error (subclass of suppress)
|
|
40
41
|
)
|
|
41
42
|
from lkj.importing import import_object, register_namespace_forwarding
|
|
42
43
|
from lkj.chunking import chunk_iterable, chunker
|
lkj/dicts.py
CHANGED
|
@@ -111,16 +111,10 @@ from typing import Mapping, Callable, TypeVar, Iterable, Tuple
|
|
|
111
111
|
KT = TypeVar("KT") # Key type
|
|
112
112
|
VT = TypeVar("VT") # Value type
|
|
113
113
|
|
|
114
|
+
|
|
114
115
|
# Note: Could have all function parameters (recursive_condition, etc.) also take the
|
|
115
116
|
# enumerated index of the mapping as an argument. That would give us even more
|
|
116
117
|
# flexibility, but it might be overkill and make the interface more complex.
|
|
117
|
-
from typing import Mapping, Callable, TypeVar, Iterable, Tuple
|
|
118
|
-
from collections import defaultdict
|
|
119
|
-
|
|
120
|
-
KT = TypeVar("KT") # Key type
|
|
121
|
-
VT = TypeVar("VT") # Value type
|
|
122
|
-
|
|
123
|
-
|
|
124
118
|
def merge_dicts(
|
|
125
119
|
*mappings: Mapping[KT, VT],
|
|
126
120
|
recursive_condition: Callable[[VT], bool] = lambda v: isinstance(v, Mapping),
|
|
@@ -221,3 +215,62 @@ def merge_dicts(
|
|
|
221
215
|
merged[key] = value
|
|
222
216
|
|
|
223
217
|
return merged
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
import operator
|
|
221
|
+
from typing import Callable, Dict, Any
|
|
222
|
+
|
|
223
|
+
Comparison = Any
|
|
224
|
+
Comparator = Callable[[dict, dict], Comparison]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def compare_dicts(
|
|
228
|
+
dict1,
|
|
229
|
+
dict2,
|
|
230
|
+
*,
|
|
231
|
+
field_comparators: Dict[KT, Comparator] = {},
|
|
232
|
+
default_comparator: Comparator = operator.eq,
|
|
233
|
+
aggregator: Callable[
|
|
234
|
+
[Dict[KT, Comparison]], Any
|
|
235
|
+
] = lambda d: d, # lambda d: np.mean(list(d.values()))
|
|
236
|
+
):
|
|
237
|
+
"""
|
|
238
|
+
Compare two dictionaries field by field using specified comparators or a default comparator.
|
|
239
|
+
|
|
240
|
+
:param dict1: The first dictionary.
|
|
241
|
+
:param dict2: The second dictionary.
|
|
242
|
+
:param field_comparators: A dictionary where keys are field names and values are comparator functions.
|
|
243
|
+
:param default_comparator: A default comparator function to use if no specific comparator is provided for a field.
|
|
244
|
+
:param aggregator: A function to aggregate the comparison results into a final score.
|
|
245
|
+
:return: A final score based on the comparison results.
|
|
246
|
+
|
|
247
|
+
>>> dict1 = {"color": "brown", "animal": "dog"}
|
|
248
|
+
>>> dict2 = {"color": "brown", "animal": "cat"}
|
|
249
|
+
>>> dict3 = {"color": "brown", "animal": "bird"}
|
|
250
|
+
>>> field_comparators = {
|
|
251
|
+
... "color": lambda x, y: 1 if x == y else 0,
|
|
252
|
+
... "animal": lambda x, y: 1 if len(x) == len(y) else 0
|
|
253
|
+
... }
|
|
254
|
+
>>> compare_dicts(dict1, dict2, field_comparators=field_comparators)
|
|
255
|
+
{'color': 1, 'animal': 1}
|
|
256
|
+
>>> compare_dicts(dict1, dict3, field_comparators=field_comparators)
|
|
257
|
+
{'color': 1, 'animal': 0}
|
|
258
|
+
>>> import functools, statistics
|
|
259
|
+
>>> aggregator = lambda d: statistics.mean(d.values())
|
|
260
|
+
>>> my_compare_dicts = functools.partial(
|
|
261
|
+
... compare_dicts, field_comparators=field_comparators, aggregator=aggregator
|
|
262
|
+
... )
|
|
263
|
+
>>> my_compare_dicts(dict1, dict2)
|
|
264
|
+
1
|
|
265
|
+
>>> my_compare_dicts(dict1, dict3)
|
|
266
|
+
0.5
|
|
267
|
+
|
|
268
|
+
"""
|
|
269
|
+
common_keys = [k for k in dict1.keys() if k in dict2.keys()]
|
|
270
|
+
|
|
271
|
+
comparisons = {}
|
|
272
|
+
for key in common_keys:
|
|
273
|
+
comparator = field_comparators.get(key, default_comparator)
|
|
274
|
+
comparisons[key] = comparator(dict1[key], dict2[key])
|
|
275
|
+
|
|
276
|
+
return aggregator(comparisons)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
lkj/__init__.py,sha256=
|
|
1
|
+
lkj/__init__.py,sha256=YEPCVj-0EJOfpapgX3Vw07399w13OkCm39KCmCi5AQg,6806
|
|
2
2
|
lkj/chunking.py,sha256=RpNdx5jEuO4mFg2qoTkD47iL35neBneuZ5xgQ_cBkiM,3755
|
|
3
|
-
lkj/dicts.py,sha256=
|
|
3
|
+
lkj/dicts.py,sha256=nfciX_h7tplR3cbaDYcQvucb7UWzv8vmvp2NDEiQm-4,10227
|
|
4
4
|
lkj/filesys.py,sha256=NbWDuc848h8O42gwX7d9yNJkrWBgzSFnkoEdSRgvBAg,8883
|
|
5
5
|
lkj/funcs.py,sha256=LXJlj3gMMsbD0t2gn2NZZ6mOqmW5bxM-94uGoYgrhzI,8930
|
|
6
6
|
lkj/importing.py,sha256=_BFBmdaKCBnk5broltWDeAPeEKG1dEkS8DhIdv6UhSI,3809
|
|
@@ -8,8 +8,8 @@ lkj/iterables.py,sha256=9jeO36w-IGiZryge7JKgXZOGZAgehUvhwKV3nHPcZWk,2801
|
|
|
8
8
|
lkj/loggers.py,sha256=ImmBdacz89Lvb3dg_xI5jOct_44rSRv0hNI_CVehy60,13706
|
|
9
9
|
lkj/misc.py,sha256=IZf05tkl0cgiMgBwCMH5cLSC59fRXwnemPRo8G0OxQg,1436
|
|
10
10
|
lkj/strings.py,sha256=3YjlxOWUfzWqwu51uq_pv9XZReLqRFvziGtRsdzEtw8,24662
|
|
11
|
-
lkj-0.1.
|
|
12
|
-
lkj-0.1.
|
|
13
|
-
lkj-0.1.
|
|
14
|
-
lkj-0.1.
|
|
15
|
-
lkj-0.1.
|
|
11
|
+
lkj-0.1.40.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
12
|
+
lkj-0.1.40.dist-info/METADATA,sha256=MQn5N_4SfIm7fUZl9zCTtuSTz94PYPenG7EZd8juq14,4684
|
|
13
|
+
lkj-0.1.40.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
14
|
+
lkj-0.1.40.dist-info/top_level.txt,sha256=3DZOUwYmyurJFBXQCvCmEIVm8z2b42O5Sx3RDQyePfg,4
|
|
15
|
+
lkj-0.1.40.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|