lkj 0.1.38__tar.gz → 0.1.40__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lkj
3
- Version: 0.1.38
3
+ Version: 0.1.40
4
4
  Summary: A dump of homeless useful utils
5
5
  Home-page: https://github.com/thorwhalen/lkj
6
6
  Author: Thor Whalen
@@ -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
@@ -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
1
  Metadata-Version: 2.1
2
2
  Name: lkj
3
- Version: 0.1.38
3
+ Version: 0.1.40
4
4
  Summary: A dump of homeless useful utils
5
5
  Home-page: https://github.com/thorwhalen/lkj
6
6
  Author: Thor Whalen
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = lkj
3
- version = 0.1.38
3
+ version = 0.1.40
4
4
  url = https://github.com/thorwhalen/lkj
5
5
  platforms = any
6
6
  description_file = README.md
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes