pythonwrench 0.6.4__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 (52) hide show
  1. pythonwrench/__init__.py +490 -0
  2. pythonwrench/__main__.py +7 -0
  3. pythonwrench/_core.py +192 -0
  4. pythonwrench/abc.py +30 -0
  5. pythonwrench/argparse/__init__.py +81 -0
  6. pythonwrench/argparse/dataclass_.py +284 -0
  7. pythonwrench/argparse/parsers.py +619 -0
  8. pythonwrench/cast.py +247 -0
  9. pythonwrench/checksum.py +427 -0
  10. pythonwrench/collections/__init__.py +104 -0
  11. pythonwrench/collections/collections.py +900 -0
  12. pythonwrench/collections/prop.py +104 -0
  13. pythonwrench/collections/reducers.py +330 -0
  14. pythonwrench/concurrent.py +73 -0
  15. pythonwrench/csv.py +12 -0
  16. pythonwrench/dataclasses.py +117 -0
  17. pythonwrench/datetime.py +17 -0
  18. pythonwrench/difflib.py +39 -0
  19. pythonwrench/disk_cache.py +615 -0
  20. pythonwrench/entrypoints/info.py +44 -0
  21. pythonwrench/entrypoints/safe_rmdir.py +98 -0
  22. pythonwrench/entrypoints/tree.py +113 -0
  23. pythonwrench/enum.py +55 -0
  24. pythonwrench/functools.py +234 -0
  25. pythonwrench/hashlib.py +95 -0
  26. pythonwrench/importlib.py +243 -0
  27. pythonwrench/inspect.py +69 -0
  28. pythonwrench/json.py +12 -0
  29. pythonwrench/jsonl.py +12 -0
  30. pythonwrench/logging.py +252 -0
  31. pythonwrench/math.py +107 -0
  32. pythonwrench/os.py +226 -0
  33. pythonwrench/pickle.py +12 -0
  34. pythonwrench/random.py +60 -0
  35. pythonwrench/re.py +139 -0
  36. pythonwrench/semver.py +406 -0
  37. pythonwrench/serialization/__init__.py +70 -0
  38. pythonwrench/serialization/_core.py +70 -0
  39. pythonwrench/serialization/csv.py +493 -0
  40. pythonwrench/serialization/json.py +178 -0
  41. pythonwrench/serialization/jsonl.py +215 -0
  42. pythonwrench/serialization/pickle.py +186 -0
  43. pythonwrench/time.py +34 -0
  44. pythonwrench/typing/__init__.py +125 -0
  45. pythonwrench/typing/checks.py +551 -0
  46. pythonwrench/typing/classes.py +251 -0
  47. pythonwrench/warnings.py +118 -0
  48. pythonwrench-0.6.4.dist-info/METADATA +242 -0
  49. pythonwrench-0.6.4.dist-info/RECORD +52 -0
  50. pythonwrench-0.6.4.dist-info/WHEEL +4 -0
  51. pythonwrench-0.6.4.dist-info/entry_points.txt +10 -0
  52. pythonwrench-0.6.4.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,490 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """Python library with tools for typing, manipulating collections, and more!"""
5
+
6
+ __name__ = "pythonwrench"
7
+ __author__ = "Étienne Labbé (Labbeti)"
8
+ __author_email__ = "labbeti.pub@gmail.com"
9
+ __license__ = "MIT"
10
+ __maintainer__ = "Étienne Labbé (Labbeti)"
11
+ __status__ = "Development"
12
+ __version__ = "0.6.4"
13
+
14
+
15
+ from typing import TYPE_CHECKING
16
+
17
+ try:
18
+ import lazy_loader as lazy # type: ignore
19
+ except ImportError:
20
+ lazy = None
21
+
22
+
23
+ if TYPE_CHECKING or lazy is None:
24
+ # Re-import for language servers
25
+ from . import abc as abc
26
+ from . import argparse as argparse
27
+ from . import cast as cast
28
+ from . import checksum as checksum
29
+ from . import collections as collections
30
+ from . import concurrent as concurrent
31
+ from . import dataclasses as dataclasses
32
+ from . import datetime as datetime
33
+ from . import difflib as difflib
34
+ from . import disk_cache as disk_cache
35
+ from . import entrypoints as entrypoints
36
+ from . import enum as enum
37
+ from . import functools as functools
38
+ from . import hashlib as hashlib
39
+ from . import importlib as importlib
40
+ from . import inspect as inspect
41
+ from . import logging as logging
42
+ from . import math as math
43
+ from . import os as os
44
+ from . import random as random
45
+ from . import re as re
46
+ from . import semver as semver
47
+ from . import serialization as serialization
48
+ from . import time as time
49
+ from . import warnings as warnings
50
+
51
+ # Global library imports
52
+ from .abc import Singleton
53
+ from .argparse import (
54
+ add_dataclass_fields_to_parser,
55
+ get_parse_fn,
56
+ new_parser_from_dataclass,
57
+ parse_args_using_dataclass,
58
+ parse_to,
59
+ parse_to_bool,
60
+ parse_to_float,
61
+ parse_to_int,
62
+ parse_to_none,
63
+ parse_to_optional_bool,
64
+ parse_to_optional_float,
65
+ parse_to_optional_int,
66
+ parse_to_optional_str,
67
+ parse_to_type,
68
+ register_parser_fn,
69
+ str_to_bool,
70
+ str_to_float,
71
+ str_to_int,
72
+ str_to_none,
73
+ str_to_optional_bool,
74
+ str_to_optional_float,
75
+ str_to_optional_int,
76
+ str_to_optional_str,
77
+ str_to_type,
78
+ )
79
+ from .cast import as_builtin, register_as_builtin_fn
80
+ from .checksum import checksum_any, checksum_object, register_checksum_fn
81
+ from .collections import (
82
+ SizedGenerator,
83
+ all_eq,
84
+ all_ne,
85
+ contained,
86
+ dict_list_to_list_dict,
87
+ dump_dict,
88
+ duplicate_list,
89
+ filter_iterable,
90
+ find,
91
+ flat_dict_of_dict,
92
+ flat_list_of_list,
93
+ flatten,
94
+ intersect,
95
+ intersect_lists,
96
+ is_full,
97
+ is_sorted,
98
+ is_unique,
99
+ list_dict_to_dict_list,
100
+ prod,
101
+ recursive_generator,
102
+ reduce_add,
103
+ reduce_and,
104
+ reduce_matmul,
105
+ reduce_mul,
106
+ reduce_or,
107
+ shuffled,
108
+ sorted_dict,
109
+ sum,
110
+ unflat_dict_of_dict,
111
+ unflat_list_of_list,
112
+ union,
113
+ union_dicts,
114
+ union_lists,
115
+ unzip,
116
+ )
117
+ from .dataclasses import add_dict_methods, dataclassdict, get_defaults_values
118
+ from .datetime import get_now, get_now_iso8601
119
+ from .difflib import find_closest_in_list, sequence_matcher_ratio
120
+ from .disk_cache import disk_cache_call, disk_cache_decorator
121
+ from .enum import StrEnum
122
+ from .functools import (
123
+ Compose,
124
+ compose,
125
+ filter_and_call,
126
+ function_alias,
127
+ identity,
128
+ repeat_fn,
129
+ )
130
+ from .hashlib import hash_file
131
+ from .importlib import (
132
+ ModulePlaceholder,
133
+ Placeholder,
134
+ import_if_available,
135
+ is_available_package,
136
+ is_editable_package,
137
+ reload_editable_packages,
138
+ reload_submodules,
139
+ requires_packages,
140
+ search_submodules,
141
+ )
142
+ from .inspect import get_argnames, get_current_fn_name, get_fullname
143
+ from .logging import (
144
+ VERBOSE_DEBUG,
145
+ VERBOSE_ERROR,
146
+ VERBOSE_INFO,
147
+ VERBOSE_WARNING,
148
+ MkdirFileHandler,
149
+ get_current_file_logger,
150
+ get_ipython_name,
151
+ get_null_logger,
152
+ log_once,
153
+ running_on_interpreter,
154
+ running_on_notebook,
155
+ running_on_terminal,
156
+ setup_logging_level,
157
+ setup_logging_verbose,
158
+ )
159
+ from .math import argmax, argmin, argsort, clamp, clip
160
+ from .os import get_num_cpus_available, safe_rmdir, tree_iter
161
+ from .random import randstr
162
+ from .re import (
163
+ PatternLike,
164
+ PatternListLike,
165
+ compile_patterns,
166
+ filter_with_patterns,
167
+ find_patterns,
168
+ get_key_fn,
169
+ match_patterns,
170
+ sort_with_patterns,
171
+ )
172
+ from .semver import Version
173
+ from .serialization import (
174
+ dump_csv,
175
+ dump_json,
176
+ dump_jsonl,
177
+ dump_pickle,
178
+ dumps_csv,
179
+ dumps_json,
180
+ dumps_jsonl,
181
+ dumps_pickle,
182
+ load_csv,
183
+ load_json,
184
+ load_jsonl,
185
+ load_pickle,
186
+ loads_csv,
187
+ loads_json,
188
+ loads_jsonl,
189
+ loads_pickle,
190
+ read_csv,
191
+ read_json,
192
+ read_jsonl,
193
+ read_pickle,
194
+ save_csv,
195
+ save_json,
196
+ save_jsonl,
197
+ save_pickle,
198
+ )
199
+ from .time import Ticker
200
+ from .typing import (
201
+ BuiltinCollection,
202
+ BuiltinNumber,
203
+ BuiltinScalar,
204
+ Dataclass,
205
+ DataclassInstance,
206
+ EllipsisType,
207
+ ListOrTuple,
208
+ NamedTupleInstance,
209
+ NoneType,
210
+ SupportsAdd,
211
+ SupportsAnd,
212
+ SupportsBool,
213
+ SupportsDiv,
214
+ SupportsGetitem,
215
+ SupportsGetitem2,
216
+ SupportsGetitemIterLen,
217
+ SupportsGetitemIterLen2,
218
+ SupportsGetitemLen,
219
+ SupportsGetitemLen2,
220
+ SupportsIter,
221
+ SupportsIterLen,
222
+ SupportsLen,
223
+ SupportsMatmul,
224
+ SupportsMul,
225
+ SupportsOr,
226
+ T_BuiltinNumber,
227
+ T_BuiltinScalar,
228
+ check_args_types,
229
+ is_builtin_collection,
230
+ is_builtin_number,
231
+ is_builtin_obj,
232
+ is_builtin_scalar,
233
+ is_collection_alias,
234
+ is_dataclass_instance,
235
+ is_dataclass_type,
236
+ is_iterable_bool,
237
+ is_iterable_bytes_or_list,
238
+ is_iterable_float,
239
+ is_iterable_int,
240
+ is_iterable_integral,
241
+ is_iterable_str,
242
+ is_namedtuple_instance,
243
+ is_parameterized,
244
+ is_sequence_str,
245
+ is_special_form,
246
+ is_typed_dict,
247
+ isinstance_generic,
248
+ )
249
+ from .warnings import deprecated_alias, deprecated_function, warn_once
250
+
251
+ else:
252
+ __getattr__, __dir__, __all__ = lazy.attach(
253
+ __name__,
254
+ submodules=[
255
+ "abc",
256
+ "argparse",
257
+ "cast",
258
+ "checksum",
259
+ "collections",
260
+ "concurrent",
261
+ "dataclasses",
262
+ "datetime",
263
+ "difflib",
264
+ "disk_cache",
265
+ "entrypoints",
266
+ "enum",
267
+ "functools",
268
+ "hashlib",
269
+ "importlib",
270
+ "inspect",
271
+ "logging",
272
+ "math",
273
+ "os",
274
+ "random",
275
+ "re",
276
+ "semver",
277
+ "serialization",
278
+ "time",
279
+ "typing",
280
+ "warnings",
281
+ ],
282
+ submod_attrs={
283
+ "argparse": [
284
+ "add_dataclass_fields_to_parser",
285
+ "get_parse_fn",
286
+ "new_parser_from_dataclass",
287
+ "parse_args_using_dataclass",
288
+ "parse_to",
289
+ "parse_to_bool",
290
+ "parse_to_float",
291
+ "parse_to_int",
292
+ "parse_to_none",
293
+ "parse_to_optional_bool",
294
+ "parse_to_optional_float",
295
+ "parse_to_optional_int",
296
+ "parse_to_optional_str",
297
+ "parse_to_type",
298
+ "register_parser_fn",
299
+ "str_to_bool",
300
+ "str_to_float",
301
+ "str_to_int",
302
+ "str_to_none",
303
+ "str_to_optional_bool",
304
+ "str_to_optional_float",
305
+ "str_to_optional_int",
306
+ "str_to_optional_str",
307
+ "str_to_type",
308
+ ],
309
+ "abc": ["Singleton"],
310
+ "cast": ["as_builtin", "register_as_builtin_fn"],
311
+ "checksum": ["checksum_any", "checksum_object", "register_checksum_fn"],
312
+ "collections": [
313
+ "SizedGenerator",
314
+ "all_eq",
315
+ "all_ne",
316
+ "contained",
317
+ "dict_list_to_list_dict",
318
+ "dump_dict",
319
+ "duplicate_list",
320
+ "filter_iterable",
321
+ "find",
322
+ "flat_dict_of_dict",
323
+ "flat_list_of_list",
324
+ "flatten",
325
+ "intersect",
326
+ "intersect_lists",
327
+ "is_full",
328
+ "is_sorted",
329
+ "is_unique",
330
+ "list_dict_to_dict_list",
331
+ "prod",
332
+ "recursive_generator",
333
+ "reduce_add",
334
+ "reduce_and",
335
+ "reduce_matmul",
336
+ "reduce_mul",
337
+ "reduce_or",
338
+ "shuffled",
339
+ "sorted_dict",
340
+ "sum",
341
+ "unflat_dict_of_dict",
342
+ "unflat_list_of_list",
343
+ "union",
344
+ "union_dicts",
345
+ "union_lists",
346
+ "unzip",
347
+ ],
348
+ "serialization": [
349
+ "dump_csv",
350
+ "dump_json",
351
+ "dump_jsonl",
352
+ "dump_pickle",
353
+ "dumps_csv",
354
+ "dumps_json",
355
+ "dumps_jsonl",
356
+ "dumps_pickle",
357
+ "load_csv",
358
+ "load_json",
359
+ "load_jsonl",
360
+ "load_pickle",
361
+ "loads_csv",
362
+ "loads_json",
363
+ "loads_jsonl",
364
+ "loads_pickle",
365
+ "read_csv",
366
+ "read_json",
367
+ "read_jsonl",
368
+ "read_pickle",
369
+ "save_csv",
370
+ "save_json",
371
+ "save_jsonl",
372
+ "save_pickle",
373
+ ],
374
+ "dataclasses": ["add_dict_methods", "dataclassdict", "get_defaults_values"],
375
+ "datetime": ["get_now", "get_now_iso8601"],
376
+ "difflib": ["find_closest_in_list", "sequence_matcher_ratio"],
377
+ "disk_cache": ["disk_cache_call", "disk_cache_decorator"],
378
+ "enum": ["StrEnum"],
379
+ "functools": [
380
+ "Compose",
381
+ "compose",
382
+ "filter_and_call",
383
+ "function_alias",
384
+ "identity",
385
+ "repeat_fn",
386
+ ],
387
+ "hashlib": ["hash_file"],
388
+ "importlib": [
389
+ "import_if_available",
390
+ "ModulePlaceholder",
391
+ "is_available_package",
392
+ "is_editable_package",
393
+ "reload_editable_packages",
394
+ "reload_submodules",
395
+ "requires_packages",
396
+ "search_submodules",
397
+ "Placeholder",
398
+ ],
399
+ "inspect": ["get_argnames", "get_current_fn_name", "get_fullname"],
400
+ "logging": [
401
+ "VERBOSE_DEBUG",
402
+ "VERBOSE_ERROR",
403
+ "VERBOSE_INFO",
404
+ "VERBOSE_WARNING",
405
+ "MkdirFileHandler",
406
+ "get_current_file_logger",
407
+ "get_ipython_name",
408
+ "get_null_logger",
409
+ "log_once",
410
+ "running_on_interpreter",
411
+ "running_on_notebook",
412
+ "running_on_terminal",
413
+ "setup_logging_level",
414
+ "setup_logging_verbose",
415
+ ],
416
+ "math": ["argmax", "argmin", "argsort", "clamp", "clip"],
417
+ "os": ["get_num_cpus_available", "safe_rmdir", "tree_iter"],
418
+ "random": ["randstr"],
419
+ "re": [
420
+ "PatternLike",
421
+ "PatternListLike",
422
+ "compile_patterns",
423
+ "filter_with_patterns",
424
+ "find_patterns",
425
+ "get_key_fn",
426
+ "match_patterns",
427
+ "sort_with_patterns",
428
+ ],
429
+ "semver": ["Version"],
430
+ "time": ["Ticker"],
431
+ "typing": [
432
+ "BuiltinCollection",
433
+ "BuiltinNumber",
434
+ "BuiltinScalar",
435
+ "Dataclass",
436
+ "DataclassInstance",
437
+ "EllipsisType",
438
+ "ListOrTuple",
439
+ "NamedTupleInstance",
440
+ "NoneType",
441
+ "SupportsAdd",
442
+ "SupportsAnd",
443
+ "SupportsBool",
444
+ "SupportsDiv",
445
+ "SupportsGetitem",
446
+ "SupportsGetitem2",
447
+ "SupportsGetitemIterLen",
448
+ "SupportsGetitemIterLen2",
449
+ "SupportsGetitemLen",
450
+ "SupportsGetitemLen2",
451
+ "SupportsIter",
452
+ "SupportsIterLen",
453
+ "SupportsLen",
454
+ "SupportsMatmul",
455
+ "SupportsMul",
456
+ "SupportsOr",
457
+ "T_BuiltinNumber",
458
+ "T_BuiltinScalar",
459
+ "check_args_types",
460
+ "is_builtin_collection",
461
+ "is_builtin_number",
462
+ "is_builtin_obj",
463
+ "is_builtin_scalar",
464
+ "is_collection_alias",
465
+ "is_dataclass_instance",
466
+ "is_dataclass_type",
467
+ "is_iterable_bool",
468
+ "is_iterable_bytes_or_list",
469
+ "is_iterable_float",
470
+ "is_iterable_int",
471
+ "is_iterable_integral",
472
+ "is_iterable_str",
473
+ "is_namedtuple_instance",
474
+ "is_parameterized",
475
+ "is_sequence_str",
476
+ "is_special_form",
477
+ "is_typed_dict",
478
+ "isinstance_generic",
479
+ ],
480
+ "warnings": ["deprecated_alias", "deprecated_function", "warn_once"],
481
+ },
482
+ )
483
+
484
+ Version = __getattr__("Version")
485
+
486
+
487
+ version = __version__
488
+ version_info = Version(__version__)
489
+
490
+ del TYPE_CHECKING, lazy
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from .entrypoints.info import main_info
5
+
6
+ if __name__ == "__main__":
7
+ main_info()
pythonwrench/_core.py ADDED
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from functools import wraps
5
+ from typing import (
6
+ Any,
7
+ Callable,
8
+ Dict,
9
+ Generic,
10
+ Literal,
11
+ Optional,
12
+ Protocol,
13
+ Tuple,
14
+ Union,
15
+ get_args,
16
+ runtime_checkable,
17
+ )
18
+
19
+ from typing_extensions import ParamSpec, TypeVar
20
+
21
+ P = ParamSpec("P")
22
+ T = TypeVar("T", covariant=True)
23
+ U = TypeVar("U", covariant=True)
24
+ T_Output = TypeVar("T_Output", default=Any)
25
+ T_PredicateArg = TypeVar("T_PredicateArg", contravariant=True, default=Any)
26
+ T_Function = TypeVar("T_Function", bound=Callable[..., Any])
27
+
28
+ UnkMode = Literal["identity", "error"]
29
+ ClassOrTuple = Union[type, Tuple[type, ...]]
30
+
31
+
32
+ @runtime_checkable
33
+ class Predicate(Protocol[T_PredicateArg]):
34
+ def __call__(self, /, x: T_PredicateArg) -> bool:
35
+ """Call the instance."""
36
+ ...
37
+
38
+
39
+ def return_none(*args, **kwargs) -> None:
40
+ """Return None function placeholder."""
41
+ return None
42
+
43
+
44
+ def _decorator_factory(
45
+ inner_fn: Optional[T_Function],
46
+ *,
47
+ pre_fn: Optional[Callable[..., Any]] = None,
48
+ post_fn: Optional[Callable[..., Any]] = None,
49
+ ) -> Callable[[T_Function], T_Function]:
50
+ """Decorator for function aliases."""
51
+ if pre_fn is None:
52
+ pre_fn = return_none
53
+ if post_fn is None:
54
+ post_fn = return_none
55
+
56
+ def wrapper_factory(fn: T_Function) -> T_Function:
57
+ """Perform the wrapper factory operation."""
58
+ if inner_fn is None:
59
+ _inner_fn = fn
60
+ else:
61
+ _inner_fn = inner_fn
62
+
63
+ @wraps(_inner_fn)
64
+ def wrapped(*args, **kwargs):
65
+ """Perform the wrapped operation."""
66
+ pre_fn(fn, *args, **kwargs)
67
+ result = _inner_fn(*args, **kwargs)
68
+ post_fn(fn, *args, **kwargs)
69
+ return result
70
+
71
+ return wrapped # type: ignore
72
+
73
+ return wrapper_factory
74
+
75
+
76
+ class _FunctionRegistry(Generic[T_Output]):
77
+ def __init__(self) -> None:
78
+ """Initialize the instance."""
79
+ fns: Dict[
80
+ Callable[..., T_Output],
81
+ Tuple[Optional[ClassOrTuple], Optional[Predicate], int],
82
+ ] = {}
83
+
84
+ super().__init__()
85
+ self.fns = fns
86
+
87
+ def register(
88
+ self,
89
+ fn: Callable[[T], T_Output],
90
+ class_or_tuple: Optional[ClassOrTuple] = None,
91
+ *,
92
+ custom_predicate: Optional[Predicate] = None,
93
+ priority: int = 0,
94
+ ) -> Callable[[T], T_Output]:
95
+ """Perform the register operation."""
96
+ return self.register_decorator(
97
+ class_or_tuple,
98
+ custom_predicate=custom_predicate,
99
+ priority=priority,
100
+ )(fn)
101
+
102
+ def register_decorator(
103
+ self,
104
+ class_or_tuple: Optional[ClassOrTuple] = None,
105
+ *,
106
+ custom_predicate: Optional[Predicate] = None,
107
+ priority: int = 0,
108
+ ) -> Callable:
109
+ """Perform the register decorator operation."""
110
+ if (class_or_tuple is None) == (custom_predicate is None):
111
+ msg = f"Invalid combinaison of arguments: {class_or_tuple=} and {custom_predicate=}. (only one of them must be None)"
112
+ raise ValueError(msg)
113
+
114
+ def _impl(new_fn: Callable[[T], T_Output]) -> Callable[[T], T_Output]:
115
+ """Perform the impl operation."""
116
+ new_value = (class_or_tuple, custom_predicate, priority)
117
+ self.fns = _insert_in_dict(
118
+ self.fns,
119
+ new_fn,
120
+ new_value,
121
+ priority,
122
+ priority_key=2,
123
+ )
124
+ return new_fn
125
+
126
+ return _impl
127
+
128
+ def apply(
129
+ self,
130
+ x: Any,
131
+ *,
132
+ isinstance_fn: Callable[[Any, Union[type, tuple]], bool] = isinstance,
133
+ unk_mode: UnkMode = "error",
134
+ **kwargs,
135
+ ) -> T_Output:
136
+ """Perform the apply operation."""
137
+ for fn, (class_or_tuple, custom_predicate, _) in self.fns.items():
138
+ if custom_predicate is not None:
139
+ predicate = custom_predicate
140
+
141
+ elif class_or_tuple is not None:
142
+
143
+ def target_isinstance_fn_wrap(x: Any) -> bool:
144
+ """Perform the target isinstance fn wrap operation."""
145
+ return isinstance_fn(x, class_or_tuple) # type: ignore
146
+
147
+ predicate = target_isinstance_fn_wrap
148
+ else:
149
+ msg = f"Invalid function registered. (found {class_or_tuple=} and {custom_predicate=})"
150
+ raise TypeError(msg)
151
+
152
+ if predicate(x):
153
+ return fn(x, **kwargs)
154
+
155
+ if unk_mode == "identity":
156
+ return x
157
+ elif unk_mode == "error":
158
+ valid_types = [
159
+ class_or_tuple
160
+ for class_or_tuple, _, _ in self.fns.values()
161
+ if class_or_tuple is not None
162
+ ]
163
+ msg = f"Invalid argument type {type(x)}. (expected one of {tuple(valid_types)})"
164
+ raise TypeError(msg)
165
+ else:
166
+ msg = f"Invalid argument {unk_mode=}. (expected one of {get_args(UnkMode)})"
167
+ raise ValueError(msg)
168
+
169
+
170
+ def _insert_in_dict(
171
+ dic: Dict,
172
+ key: Any,
173
+ value: Any,
174
+ priority: int,
175
+ priority_key: int,
176
+ ) -> Dict:
177
+ """Perform the insert in dict operation."""
178
+ if key in dic:
179
+ return dic
180
+ insert_index = _get_insertion_index(list(dic.values()), priority, priority_key)
181
+ items = list(dic.items())
182
+ items.insert(insert_index, (key, value))
183
+ return dict(items)
184
+
185
+
186
+ def _get_insertion_index(lst: list, priority: int, priority_key: int) -> int:
187
+ """Perform the get insertion index operation."""
188
+ for i, item in enumerate(lst):
189
+ other_priority = item[priority_key]
190
+ if priority >= other_priority:
191
+ return i
192
+ return len(lst)