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
pythonwrench/cast.py ADDED
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ from argparse import Namespace
5
+ from collections import Counter
6
+ from datetime import date
7
+ from enum import Enum
8
+ from functools import partial
9
+ from pathlib import Path
10
+ from re import Pattern
11
+ from typing import (
12
+ Any,
13
+ Callable,
14
+ Dict,
15
+ Hashable,
16
+ Iterable,
17
+ Mapping,
18
+ Optional,
19
+ TypeVar,
20
+ overload,
21
+ )
22
+
23
+ from pythonwrench._core import ClassOrTuple, Predicate, _FunctionRegistry
24
+ from pythonwrench.functools import identity
25
+ from pythonwrench.typing import (
26
+ DataclassInstance,
27
+ NamedTupleInstance,
28
+ T_BuiltinScalar,
29
+ is_builtin_scalar,
30
+ )
31
+
32
+ __all__ = ["register_as_builtin_fn", "as_builtin"]
33
+
34
+ T = TypeVar("T")
35
+ K = TypeVar("K", bound=Hashable)
36
+ V = TypeVar("V")
37
+
38
+ _AS_BUILTIN_REGISTRY = _FunctionRegistry[Any]()
39
+
40
+
41
+ @overload
42
+ def register_as_builtin_fn(
43
+ class_or_tuple: ClassOrTuple,
44
+ *,
45
+ custom_predicate: None = None,
46
+ priority: int = 0,
47
+ ) -> Callable:
48
+ """Perform the register as builtin fn operation."""
49
+ ...
50
+
51
+
52
+ @overload
53
+ def register_as_builtin_fn(
54
+ class_or_tuple: None = None,
55
+ *,
56
+ custom_predicate: Predicate,
57
+ priority: int = 0,
58
+ ) -> Callable:
59
+ """Perform the register as builtin fn operation."""
60
+ ...
61
+
62
+
63
+ def register_as_builtin_fn(
64
+ class_or_tuple: Optional[ClassOrTuple] = None,
65
+ *,
66
+ custom_predicate: Optional[Predicate] = None,
67
+ priority: int = 0,
68
+ ) -> Callable:
69
+ """Decorator to add an as_builtin function.
70
+
71
+ Example
72
+ -------
73
+ >>> import numpy as np
74
+ >>> @register_as_builtin_fn(np.ndarray)
75
+ >>> def my_checksum_for_numpy(x: np.ndarray):
76
+ >>> return x.tolist()
77
+ >>> pw.as_builtin([np.array([1, 2]), [3, 4]])
78
+ ... [[1, 2], [3, 4]]
79
+ """
80
+ return _AS_BUILTIN_REGISTRY.register_decorator(
81
+ class_or_tuple,
82
+ custom_predicate=custom_predicate,
83
+ priority=priority,
84
+ )
85
+
86
+
87
+ _AS_BUILTIN_REGISTRY.register(
88
+ identity,
89
+ custom_predicate=partial(is_builtin_scalar, strict=True),
90
+ )
91
+
92
+
93
+ @register_as_builtin_fn(Counter)
94
+ def _counter_to_builtin(x: Counter, **kwargs) -> Dict[Any, int]:
95
+ """Perform the counter to builtin operation."""
96
+ return dict(x)
97
+
98
+
99
+ @register_as_builtin_fn(date)
100
+ def _date_to_builtin(x: date, **kwargs) -> str:
101
+ """Perform the date to builtin operation."""
102
+ return str(x)
103
+
104
+
105
+ @register_as_builtin_fn(Path)
106
+ def _path_to_builtin(x: Path, **kwargs) -> str:
107
+ """Perform the path to builtin operation."""
108
+ return str(x)
109
+
110
+
111
+ @register_as_builtin_fn(Enum)
112
+ def _enum_to_builtin(x: Enum, **kwargs) -> str:
113
+ """Perform the enum to builtin operation."""
114
+ return x.name
115
+
116
+
117
+ @register_as_builtin_fn(Pattern)
118
+ def _pattern_to_builtin(x: Pattern, **kwargs) -> str:
119
+ """Perform the pattern to builtin operation."""
120
+ return x.pattern
121
+
122
+
123
+ @register_as_builtin_fn(Namespace)
124
+ def _namespace_to_builtin(x: Namespace, **kwargs) -> Any:
125
+ """Perform the namespace to builtin operation."""
126
+ return as_builtin(x.__dict__, **kwargs)
127
+
128
+
129
+ @register_as_builtin_fn(DataclassInstance)
130
+ def _dataclass_to_builtin(x: DataclassInstance, **kwargs) -> Any:
131
+ # IMPORTANT note : we do not use dataclasses.asdict() because it also converts attributes like Counter, but not do dicts
132
+ """Perform the dataclass to builtin operation."""
133
+ field_names = x.__dataclass_fields__.keys()
134
+ xdict = {name: as_builtin(getattr(x, name), **kwargs) for name in field_names}
135
+ return xdict
136
+
137
+
138
+ @register_as_builtin_fn(NamedTupleInstance)
139
+ def _namedtuple_to_builtin(x: NamedTupleInstance, **kwargs) -> Any:
140
+ """Perform the namedtuple to builtin operation."""
141
+ return as_builtin(x._asdict(), **kwargs)
142
+
143
+
144
+ @register_as_builtin_fn(Mapping, priority=-100)
145
+ def _mapping_to_builtin(x: Mapping, **kwargs) -> Any:
146
+ """Perform the mapping to builtin operation."""
147
+ return {as_builtin(k, **kwargs): as_builtin(v, **kwargs) for k, v in x.items()}
148
+
149
+
150
+ @register_as_builtin_fn(Iterable, priority=-200)
151
+ def _iterable_to_builtin(x: Iterable, **kwargs) -> Any:
152
+ """Perform the iterable to builtin operation."""
153
+ return [as_builtin(xi, **kwargs) for xi in x]
154
+
155
+
156
+ @overload
157
+ def as_builtin(x: Counter, **kwargs) -> Dict[Any, int]:
158
+ """Perform the as builtin operation."""
159
+ ...
160
+
161
+
162
+ @overload
163
+ def as_builtin(x: date, **kwargs) -> str:
164
+ """Perform the as builtin operation."""
165
+ ...
166
+
167
+
168
+ @overload
169
+ def as_builtin(x: Enum, **kwargs) -> str:
170
+ """Perform the as builtin operation."""
171
+ ...
172
+
173
+
174
+ @overload
175
+ def as_builtin(x: Path, **kwargs) -> str:
176
+ """Perform the as builtin operation."""
177
+ ...
178
+
179
+
180
+ @overload
181
+ def as_builtin(x: Pattern, **kwargs) -> str:
182
+ """Perform the as builtin operation."""
183
+ ...
184
+
185
+
186
+ @overload
187
+ def as_builtin(x: Namespace, **kwargs) -> Dict[str, Any]:
188
+ """Perform the as builtin operation."""
189
+ ...
190
+
191
+
192
+ @overload
193
+ def as_builtin(x: Mapping[K, V], **kwargs) -> Dict[K, V]:
194
+ """Perform the as builtin operation."""
195
+ ...
196
+
197
+
198
+ @overload
199
+ def as_builtin(x: DataclassInstance, **kwargs) -> Dict[str, Any]:
200
+ """Perform the as builtin operation."""
201
+ ...
202
+
203
+
204
+ @overload
205
+ def as_builtin(x: NamedTupleInstance, **kwargs) -> Dict[str, Any]:
206
+ """Perform the as builtin operation."""
207
+ ...
208
+
209
+
210
+ @overload
211
+ def as_builtin(x: T_BuiltinScalar, **kwargs) -> T_BuiltinScalar:
212
+ """Perform the as builtin operation."""
213
+ ...
214
+
215
+
216
+ @overload
217
+ def as_builtin(x: Any, **kwargs) -> Any:
218
+ """Perform the as builtin operation."""
219
+ ...
220
+
221
+
222
+ def as_builtin(x: Any, **kwargs) -> Any:
223
+ """Convert an object to a sanitized python builtin equivalent recursively.
224
+
225
+ This function can be used to sanitize data before saving to a JSON, YAML or CSV file.
226
+
227
+ Additional objects to convert can be added dynamically with `pythonwrench.register_as_builtin_fn` function decorator.
228
+
229
+ Here is the list of default objects converted to built-in:
230
+ - tuple -> list
231
+ - collections.Counter -> dict
232
+ - datetime.date -> str
233
+ - argparse.Namespace -> dict
234
+ - re.Pattern -> str
235
+ - pathlib.Path -> str
236
+ - enum.Enum -> str
237
+ - Mapping -> dict
238
+ - Iterable -> list
239
+ - Dataclass -> dict
240
+ - NamedTuple -> dict
241
+
242
+ Note: By default, tuple objects are converted to list.
243
+
244
+ Args:
245
+ x: Object to convert to built-in equivalent.
246
+ """
247
+ return _AS_BUILTIN_REGISTRY.apply(x, **kwargs)
@@ -0,0 +1,427 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import functools
5
+ import re
6
+ import struct
7
+ import zlib
8
+ from dataclasses import asdict
9
+ from datetime import date, datetime
10
+ from enum import Enum
11
+ from functools import lru_cache
12
+ from pathlib import Path
13
+ from types import FunctionType, MethodType
14
+ from typing import (
15
+ Any,
16
+ Callable,
17
+ Dict,
18
+ Generator,
19
+ Iterable,
20
+ Mapping,
21
+ Optional,
22
+ TypeVar,
23
+ Union,
24
+ get_args,
25
+ get_origin,
26
+ overload,
27
+ )
28
+
29
+ from pythonwrench._core import ClassOrTuple, Predicate, _FunctionRegistry
30
+ from pythonwrench.functools import function_alias
31
+ from pythonwrench.inspect import get_fullname
32
+ from pythonwrench.typing import (
33
+ DataclassInstance,
34
+ EllipsisType,
35
+ NamedTupleInstance,
36
+ NoneType,
37
+ is_collection_alias,
38
+ is_parameterized,
39
+ is_special_form,
40
+ )
41
+
42
+ T = TypeVar("T")
43
+
44
+
45
+ _CHECKSUM_REGISTRY = _FunctionRegistry[int]()
46
+ _CHECKSUM_PROTOCOLS = False
47
+
48
+
49
+ @overload
50
+ def register_checksum_fn(
51
+ class_or_tuple: ClassOrTuple,
52
+ *,
53
+ custom_predicate: None = None,
54
+ priority: int = 0,
55
+ ) -> Callable:
56
+ """Perform the register checksum fn operation."""
57
+ ...
58
+
59
+
60
+ @overload
61
+ def register_checksum_fn(
62
+ class_or_tuple: None = None,
63
+ *,
64
+ custom_predicate: Predicate,
65
+ priority: int = 0,
66
+ ) -> Callable:
67
+ """Perform the register checksum fn operation."""
68
+ ...
69
+
70
+
71
+ def register_checksum_fn(
72
+ class_or_tuple: Optional[ClassOrTuple] = None,
73
+ *,
74
+ custom_predicate: Optional[Predicate] = None,
75
+ priority: int = 0,
76
+ ) -> Callable:
77
+ """Decorator to add a checksum function.
78
+
79
+ Example
80
+ -------
81
+ >>> import numpy as np
82
+ >>> @register_checksum_fn(np.ndarray)
83
+ >>> def my_checksum_for_numpy(x: np.ndarray):
84
+ >>> return int(x.sum())
85
+ >>> pw.checksum_any(np.array([1, 2])) # calls my_checksum_for_numpy internally, even if array in nested inside a list, dict, etc.
86
+ """
87
+ return _CHECKSUM_REGISTRY.register_decorator(
88
+ class_or_tuple,
89
+ custom_predicate=custom_predicate,
90
+ priority=priority,
91
+ )
92
+
93
+
94
+ def checksum_any(
95
+ x: Any,
96
+ *,
97
+ isinstance_fn: Callable[[Any, Union[type, tuple]], bool] = isinstance,
98
+ **kwargs,
99
+ ) -> int:
100
+ """Compute checksum integer value from an arbitrary object.
101
+
102
+ Supports most builtin types. Checksum can be used to compare objects.
103
+ Not meant for security/cryptography.
104
+ """
105
+ return _CHECKSUM_REGISTRY.apply(x, isinstance_fn=isinstance_fn, **kwargs)
106
+
107
+
108
+ @function_alias(checksum_any)
109
+ def checksum_object(*args, **kwargs):
110
+ """Return a checksum for object."""
111
+ ...
112
+
113
+
114
+ # Terminate functions
115
+ @register_checksum_fn(bool)
116
+ def checksum_bool(x: bool, **kwargs) -> int:
117
+ """Return a checksum for bool."""
118
+ xint = int(x)
119
+ return _terminate_checksum(
120
+ xint,
121
+ get_fullname(x),
122
+ **kwargs,
123
+ )
124
+
125
+
126
+ @register_checksum_fn(float)
127
+ def checksum_float(x: float, **kwargs) -> int:
128
+ """Return a checksum for float."""
129
+ xint = __interpret_float_as_int(x)
130
+ return _terminate_checksum(
131
+ xint,
132
+ get_fullname(x),
133
+ **kwargs,
134
+ )
135
+
136
+
137
+ @register_checksum_fn(int)
138
+ def checksum_int(x: int, **kwargs) -> int:
139
+ """Return a checksum for int."""
140
+ xint = x
141
+ return _terminate_checksum(
142
+ xint,
143
+ get_fullname(x),
144
+ **kwargs,
145
+ )
146
+
147
+
148
+ # Intermediate functions
149
+ @register_checksum_fn(bytearray)
150
+ def checksum_bytearray(x: bytearray, **kwargs) -> int:
151
+ """Return a checksum for bytearray."""
152
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
153
+ return _checksum_bytes_bytearray(x, **kwargs)
154
+
155
+
156
+ @register_checksum_fn(bytes)
157
+ def checksum_bytes(x: bytes, **kwargs) -> int:
158
+ """Return a checksum for bytes."""
159
+ return _checksum_bytes_bytearray(x, **kwargs)
160
+
161
+
162
+ @register_checksum_fn(complex)
163
+ def checksum_complex(x: complex, **kwargs) -> int:
164
+ """Return a checksum for complex."""
165
+ kwargs["accumulator"] = kwargs.get("accumulator", 0) + _cached_checksum_str(
166
+ get_fullname(x)
167
+ )
168
+ return checksum_list_tuple([x.real, x.imag], **kwargs)
169
+
170
+
171
+ @register_checksum_fn(FunctionType)
172
+ def checksum_function(x: FunctionType, **kwargs) -> int:
173
+ """Return a checksum for function."""
174
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
175
+ return checksum_str(x.__qualname__, **kwargs)
176
+
177
+
178
+ @register_checksum_fn(NoneType)
179
+ def checksum_none(x: None, **kwargs) -> int:
180
+ """Return a checksum for none."""
181
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
182
+ return checksum_type(x.__class__, **kwargs)
183
+
184
+
185
+ @register_checksum_fn(EllipsisType)
186
+ def checksum_ellipsis(x: None, **kwargs) -> int:
187
+ """Return a checksum for ellipsis."""
188
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
189
+ return checksum_type(x.__class__, **kwargs)
190
+
191
+
192
+ @register_checksum_fn(str)
193
+ def checksum_str(x: str, **kwargs) -> int:
194
+ """Return a checksum for str."""
195
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
196
+ return checksum_bytes(x.encode(), **kwargs)
197
+
198
+
199
+ @register_checksum_fn(type)
200
+ def checksum_type(x: type, **kwargs) -> int:
201
+ """Return a checksum for type."""
202
+ return checksum_str(x.__qualname__, **kwargs)
203
+
204
+
205
+ # Recursive functions
206
+ @register_checksum_fn(DataclassInstance)
207
+ def checksum_dataclass(x: DataclassInstance, **kwargs) -> int:
208
+ """Return a checksum for dataclass."""
209
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
210
+ return checksum_dict(asdict(x), **kwargs)
211
+
212
+
213
+ @register_checksum_fn(datetime)
214
+ def checksum_datetime(x: datetime, **kwargs) -> int:
215
+ """Return a checksum for datetime."""
216
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
217
+ return _checksum_iterable(
218
+ [
219
+ x.year,
220
+ x.month,
221
+ x.day,
222
+ x.hour,
223
+ x.minute,
224
+ x.second,
225
+ x.microsecond,
226
+ x.tzinfo,
227
+ x.fold,
228
+ ],
229
+ **kwargs,
230
+ )
231
+
232
+
233
+ @register_checksum_fn(date)
234
+ def checksum_date(x: date, **kwargs) -> int:
235
+ """Return a checksum for date."""
236
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
237
+ return _checksum_iterable([x.year, x.month, x.day], **kwargs)
238
+
239
+
240
+ @register_checksum_fn(dict)
241
+ def checksum_dict(x: dict, **kwargs) -> int:
242
+ """Return a checksum for dict."""
243
+ return _checksum_mapping(x, **kwargs)
244
+
245
+
246
+ @register_checksum_fn(Enum)
247
+ def checksum_enum(x: Enum, **kwargs) -> int:
248
+ """Return a checksum for enum."""
249
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
250
+ return _checksum_iterable((x.name, x.value), **kwargs)
251
+
252
+
253
+ @register_checksum_fn((list, tuple))
254
+ def checksum_list_tuple(x: Union[list, tuple], **kwargs) -> int:
255
+ """Return a checksum for list tuple."""
256
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
257
+ return _checksum_iterable(x, **kwargs)
258
+
259
+
260
+ @register_checksum_fn((set, frozenset))
261
+ def checksum_set(x: Union[set, frozenset], **kwargs) -> int:
262
+ """Return a checksum for set."""
263
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
264
+ # Simply use sum here, order does not matter
265
+ csum = sum(checksum_any(xi, **kwargs) for xi in x)
266
+ return csum
267
+
268
+
269
+ @register_checksum_fn(range)
270
+ def checksum_range(x: range, **kwargs) -> int:
271
+ """Return a checksum for range."""
272
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
273
+ return _checksum_iterable([x.start, x.stop, x.step], **kwargs)
274
+
275
+
276
+ @register_checksum_fn(Generator, priority=100)
277
+ def checksum_generator(x: Generator, **kwargs) -> int:
278
+ """Return a checksum for generator."""
279
+ msg = f"Cannot compute checksum for the generator object {type(x)=}, it will be consumed."
280
+ raise RuntimeError(msg)
281
+
282
+
283
+ @register_checksum_fn(MethodType)
284
+ def checksum_method(x: MethodType, **kwargs) -> int:
285
+ """Return a checksum for method."""
286
+ fn = getattr(x.__self__, x.__name__)
287
+ checksums = [
288
+ checksum_any(x.__self__, **kwargs), # type: ignore
289
+ checksum_function(fn, **kwargs),
290
+ ]
291
+ return checksum_list_tuple(checksums, **kwargs)
292
+
293
+
294
+ @register_checksum_fn(NamedTupleInstance)
295
+ def checksum_namedtuple(x: NamedTupleInstance, **kwargs) -> int:
296
+ """Return a checksum for namedtuple."""
297
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
298
+ return checksum_dict(x._asdict(), **kwargs)
299
+
300
+
301
+ @register_checksum_fn(functools.partial)
302
+ def checksum_partial(x: functools.partial, **kwargs) -> int:
303
+ """Return a checksum for partial."""
304
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
305
+ return checksum_list_tuple((x.func, x.args, x.keywords), **kwargs)
306
+
307
+
308
+ @register_checksum_fn(re.Pattern)
309
+ def checksum_pattern(x: re.Pattern, **kwargs) -> int:
310
+ """Return a checksum for pattern."""
311
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
312
+ return checksum_str(str(x), **kwargs)
313
+
314
+
315
+ @register_checksum_fn(Path)
316
+ def checksum_path(x: Path, *, resolve_path: bool = False, **kwargs) -> int:
317
+ """Return a checksum for path."""
318
+ kwargs["resolve_path"] = resolve_path
319
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
320
+ if isinstance(resolve_path, bool) and resolve_path:
321
+ x = x.expanduser().resolve()
322
+ return checksum_str(str(x), **kwargs)
323
+
324
+
325
+ @register_checksum_fn(slice)
326
+ def checksum_slice(x: slice, **kwargs) -> int:
327
+ """Return a checksum for slice."""
328
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
329
+ return checksum_list_tuple((x.start, x.stop, x.step), **kwargs)
330
+
331
+
332
+ @register_checksum_fn(custom_predicate=is_parameterized)
333
+ def checksum_parametrized(x: Any, **kwargs) -> int:
334
+ """Return a checksum for parametrized."""
335
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
336
+ return checksum_list_tuple((get_origin(x),) + get_args(x), **kwargs)
337
+
338
+
339
+ @register_checksum_fn(custom_predicate=is_collection_alias)
340
+ def checksum_collection_alias(x: Any, **kwargs) -> int:
341
+ """Return a checksum for collection alias."""
342
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
343
+ return checksum_str(x._name, **kwargs)
344
+
345
+
346
+ @register_checksum_fn(custom_predicate=is_special_form)
347
+ def checksum_special_form(x: Any, **kwargs) -> int:
348
+ """Return a checksum for special form."""
349
+ kwargs = _add_type_checksum_to_accumulator(x, kwargs)
350
+
351
+ if hasattr(x, "_name"):
352
+ name = x._name
353
+ elif hasattr(x, "__name__"):
354
+ name = x.__name__
355
+ else:
356
+ msg = f"Unsupported argument {x=} in checksum_special_form."
357
+ raise ValueError(msg)
358
+
359
+ return checksum_str(name, **kwargs)
360
+
361
+
362
+ if _CHECKSUM_PROTOCOLS:
363
+
364
+ @register_checksum_fn(Mapping, priority=-100)
365
+ def checksum_mapping(x: Mapping, **kwargs) -> int:
366
+ """Return a checksum for mapping."""
367
+ return _checksum_mapping(x, **kwargs)
368
+
369
+ @register_checksum_fn(Iterable, priority=-200)
370
+ def checksum_iterable(x: Iterable, **kwargs) -> int:
371
+ """Return a checksum for iterable."""
372
+ return _checksum_iterable(x, **kwargs)
373
+
374
+
375
+ # Private functions
376
+ def _checksum_bytes_bytearray(x: Union[bytes, bytearray], **kwargs) -> int:
377
+ """Perform the checksum bytes bytearray operation."""
378
+ xint = zlib.crc32(x) % (1 << 32)
379
+ return _terminate_checksum(
380
+ xint,
381
+ get_fullname(x),
382
+ **kwargs,
383
+ )
384
+
385
+
386
+ def _checksum_iterable(x: Iterable, **kwargs) -> int:
387
+ """Perform the checksum iterable operation."""
388
+ accumulator = kwargs.pop("accumulator", 0) + _cached_checksum_str(get_fullname(x))
389
+ csum = sum(
390
+ checksum_any(xi, accumulator=accumulator + (i + 1), **kwargs) * (i + 1)
391
+ for i, xi in enumerate(x)
392
+ )
393
+ return csum + accumulator
394
+
395
+
396
+ def _checksum_mapping(x: Mapping, **kwargs) -> int:
397
+ """Perform the checksum mapping operation."""
398
+ kwargs["accumulator"] = kwargs.get("accumulator", 0) + _cached_checksum_str(
399
+ get_fullname(x)
400
+ )
401
+ return _checksum_iterable(x.items(), **kwargs)
402
+
403
+
404
+ def _terminate_checksum(x: int, fullname: str, **kwargs) -> int:
405
+ """Returns checksum for final value + name + accumulator."""
406
+ return x + _cached_checksum_str(fullname) + kwargs.get("accumulator", 0)
407
+
408
+
409
+ def _add_type_checksum_to_accumulator(x: Any, kwargs: Dict[str, Any]) -> Dict[str, Any]:
410
+ """Perform the add type checksum to accumulator operation."""
411
+ kwargs["accumulator"] = kwargs.get("accumulator", 0) + _cached_checksum_str(
412
+ get_fullname(x)
413
+ )
414
+ return kwargs
415
+
416
+
417
+ @lru_cache(maxsize=None)
418
+ def _cached_checksum_str(x: str) -> int:
419
+ """Perform the cached checksum str operation."""
420
+ return zlib.crc32(x.encode()) % (1 << 32)
421
+
422
+
423
+ def __interpret_float_as_int(x: float) -> int:
424
+ """Perform the interpret float as int operation."""
425
+ xbytes = struct.pack(">d", x)
426
+ xint = struct.unpack(">q", xbytes)[0]
427
+ return xint