faster-eth-abi 5.2.23__cp314-cp314-musllinux_1_2_x86_64.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 (48) hide show
  1. faster_eth_abi/__init__.py +12 -0
  2. faster_eth_abi/_codec.cpython-314-x86_64-linux-musl.so +0 -0
  3. faster_eth_abi/_codec.py +83 -0
  4. faster_eth_abi/_decoding.cpython-314-x86_64-linux-musl.so +0 -0
  5. faster_eth_abi/_decoding.py +356 -0
  6. faster_eth_abi/_encoding.cpython-314-x86_64-linux-musl.so +0 -0
  7. faster_eth_abi/_encoding.py +480 -0
  8. faster_eth_abi/_grammar.cpython-314-x86_64-linux-musl.so +0 -0
  9. faster_eth_abi/_grammar.py +375 -0
  10. faster_eth_abi/abi.cpython-314-x86_64-linux-musl.so +0 -0
  11. faster_eth_abi/abi.py +17 -0
  12. faster_eth_abi/base.py +45 -0
  13. faster_eth_abi/codec.py +2809 -0
  14. faster_eth_abi/constants.cpython-314-x86_64-linux-musl.so +0 -0
  15. faster_eth_abi/constants.py +7 -0
  16. faster_eth_abi/decoding.py +556 -0
  17. faster_eth_abi/encoding.py +721 -0
  18. faster_eth_abi/exceptions.py +127 -0
  19. faster_eth_abi/from_type_str.cpython-314-x86_64-linux-musl.so +0 -0
  20. faster_eth_abi/from_type_str.py +141 -0
  21. faster_eth_abi/grammar.py +172 -0
  22. faster_eth_abi/io.py +107 -0
  23. faster_eth_abi/packed.cpython-314-x86_64-linux-musl.so +0 -0
  24. faster_eth_abi/packed.py +19 -0
  25. faster_eth_abi/py.typed +0 -0
  26. faster_eth_abi/registry.py +758 -0
  27. faster_eth_abi/tools/__init__.cpython-314-x86_64-linux-musl.so +0 -0
  28. faster_eth_abi/tools/__init__.py +3 -0
  29. faster_eth_abi/tools/_strategies.cpython-314-x86_64-linux-musl.so +0 -0
  30. faster_eth_abi/tools/_strategies.py +243 -0
  31. faster_eth_abi/typing.py +4627 -0
  32. faster_eth_abi/utils/__init__.cpython-314-x86_64-linux-musl.so +0 -0
  33. faster_eth_abi/utils/__init__.py +0 -0
  34. faster_eth_abi/utils/localcontext.cpython-314-x86_64-linux-musl.so +0 -0
  35. faster_eth_abi/utils/localcontext.py +49 -0
  36. faster_eth_abi/utils/numeric.cpython-314-x86_64-linux-musl.so +0 -0
  37. faster_eth_abi/utils/numeric.py +117 -0
  38. faster_eth_abi/utils/padding.cpython-314-x86_64-linux-musl.so +0 -0
  39. faster_eth_abi/utils/padding.py +22 -0
  40. faster_eth_abi/utils/string.cpython-314-x86_64-linux-musl.so +0 -0
  41. faster_eth_abi/utils/string.py +19 -0
  42. faster_eth_abi/utils/validation.cpython-314-x86_64-linux-musl.so +0 -0
  43. faster_eth_abi/utils/validation.py +18 -0
  44. faster_eth_abi-5.2.23.dist-info/METADATA +136 -0
  45. faster_eth_abi-5.2.23.dist-info/RECORD +48 -0
  46. faster_eth_abi-5.2.23.dist-info/WHEEL +5 -0
  47. faster_eth_abi-5.2.23.dist-info/top_level.txt +2 -0
  48. faster_eth_abi__mypyc.cpython-314-x86_64-linux-musl.so +0 -0
@@ -0,0 +1,758 @@
1
+ """Registry and predicate logic for ABI encoders and decoders.
2
+
3
+ Implements registration, lookup, and matching of encoders and decoders for ABI type strings.
4
+ """
5
+ import abc
6
+ from copy import (
7
+ copy,
8
+ )
9
+ import functools
10
+ from typing import (
11
+ Any,
12
+ Callable,
13
+ Dict,
14
+ Final,
15
+ Generic,
16
+ Iterator,
17
+ Optional,
18
+ Type,
19
+ TypeVar,
20
+ Union,
21
+ cast,
22
+ final,
23
+ )
24
+
25
+ from eth_typing import (
26
+ TypeStr,
27
+ )
28
+ from typing_extensions import (
29
+ Concatenate,
30
+ ParamSpec,
31
+ Self,
32
+ )
33
+
34
+ from . import (
35
+ decoding,
36
+ encoding,
37
+ exceptions,
38
+ grammar,
39
+ )
40
+ from .base import (
41
+ BaseCoder,
42
+ )
43
+ from .exceptions import (
44
+ MultipleEntriesFound,
45
+ NoEntriesFound,
46
+ )
47
+ from .io import (
48
+ ContextFramesBytesIO,
49
+ )
50
+
51
+ T = TypeVar("T")
52
+ P = ParamSpec("P")
53
+
54
+ Lookup = Union[TypeStr, Callable[[TypeStr], bool]]
55
+
56
+ EncoderCallable = Callable[[Any], bytes]
57
+ DecoderCallable = Callable[[ContextFramesBytesIO], Any]
58
+
59
+ Encoder = Union[EncoderCallable, Type[encoding.BaseEncoder]]
60
+ Decoder = Union[DecoderCallable, Type[decoding.BaseDecoder]]
61
+
62
+
63
+ class Copyable(abc.ABC):
64
+ @abc.abstractmethod
65
+ def copy(self) -> Self:
66
+ pass
67
+
68
+ def __copy__(self) -> Self:
69
+ return self.copy()
70
+
71
+ def __deepcopy__(self, *args: Any) -> Self:
72
+ return self.copy()
73
+
74
+
75
+ class PredicateMapping(Copyable, Generic[T]):
76
+ """
77
+ Acts as a mapping from predicate functions to values. Values are retrieved
78
+ when their corresponding predicate matches a given input. Predicates can
79
+ also be labeled to facilitate removal from the mapping.
80
+ """
81
+
82
+ def __init__(self, name: str):
83
+ self._name: Final = name
84
+ self._values: Dict[Lookup, T] = {}
85
+ self._labeled_predicates: Dict[str, Lookup] = {}
86
+
87
+ def add(self, predicate: Lookup, value: T, label: Optional[str] = None) -> None:
88
+ if predicate in self._values:
89
+ raise ValueError(f"Matcher {predicate!r} already exists in {self._name}")
90
+
91
+ if label is not None:
92
+ labeled_predicates = self._labeled_predicates
93
+ if label in labeled_predicates:
94
+ raise ValueError(
95
+ f"Matcher {predicate!r} with label '{label}' "
96
+ f"already exists in {self._name}"
97
+ )
98
+
99
+ labeled_predicates[label] = predicate
100
+
101
+ self._values[predicate] = value
102
+
103
+ def find(self, type_str: TypeStr) -> T:
104
+ results = tuple(
105
+ (predicate, value)
106
+ for predicate, value in self._values.items()
107
+ if predicate(type_str)
108
+ )
109
+
110
+ if len(results) == 0:
111
+ raise NoEntriesFound(
112
+ f"No matching entries for '{type_str}' in {self._name}"
113
+ )
114
+
115
+ predicates, values = tuple(zip(*results))
116
+
117
+ if len(results) > 1:
118
+ predicate_reprs = ", ".join(map(repr, predicates))
119
+ raise MultipleEntriesFound(
120
+ f"Multiple matching entries for '{type_str}' in {self._name}: "
121
+ f"{predicate_reprs}. This occurs when two registrations match the "
122
+ "same type string. You may need to delete one of the "
123
+ "registrations or modify its matching behavior to ensure it "
124
+ 'doesn\'t collide with other registrations. See the "Registry" '
125
+ "documentation for more information."
126
+ )
127
+
128
+ return values[0] # type: ignore [no-any-return]
129
+
130
+ def remove_by_equality(self, predicate: Lookup) -> None:
131
+ # Delete the predicate mapping to the previously stored value
132
+ try:
133
+ del self._values[predicate]
134
+ except KeyError:
135
+ raise KeyError(f"Matcher {predicate!r} not found in {self._name}")
136
+
137
+ # Delete any label which refers to this predicate
138
+ try:
139
+ label = self._label_for_predicate(predicate)
140
+ except ValueError:
141
+ pass
142
+ else:
143
+ del self._labeled_predicates[label]
144
+
145
+ def _label_for_predicate(self, predicate: Lookup) -> str:
146
+ # Both keys and values in `_labeled_predicates` are unique since the
147
+ # `add` method enforces this
148
+ for key, value in self._labeled_predicates.items():
149
+ if value is predicate:
150
+ return key
151
+
152
+ raise ValueError(
153
+ f"Matcher {predicate!r} not referred to by any label in {self._name}"
154
+ )
155
+
156
+ def remove_by_label(self, label: str) -> None:
157
+ labeled_predicates = self._labeled_predicates
158
+ try:
159
+ predicate = labeled_predicates[label]
160
+ except KeyError:
161
+ raise KeyError(f"Label '{label}' not found in {self._name}")
162
+
163
+ del labeled_predicates[label]
164
+ del self._values[predicate]
165
+
166
+ def remove(self, predicate_or_label: Union[Lookup, str]) -> None:
167
+ if callable(predicate_or_label):
168
+ self.remove_by_equality(predicate_or_label)
169
+ elif isinstance(predicate_or_label, str):
170
+ self.remove_by_label(predicate_or_label)
171
+ else:
172
+ raise TypeError(
173
+ "Key to be removed must be callable or string: got "
174
+ f"{type(predicate_or_label)}"
175
+ )
176
+
177
+ def copy(self) -> Self:
178
+ cpy = type(self)(self._name)
179
+
180
+ cpy._values = copy(self._values)
181
+ cpy._labeled_predicates = copy(self._labeled_predicates)
182
+
183
+ return cpy
184
+
185
+
186
+ class Predicate(Generic[T]):
187
+ """
188
+ Represents a predicate function to be used for type matching in
189
+ ``ABIRegistry``.
190
+ """
191
+
192
+ __slots__ = ("_string", "__hash")
193
+
194
+ _string: Optional[str]
195
+
196
+ def __init__(self) -> None:
197
+ self._string = None
198
+ self.__hash = None
199
+
200
+ def __call__(self, arg: TypeStr) -> None:
201
+ raise NotImplementedError("Must implement `__call__`")
202
+
203
+ def __str__(self) -> str:
204
+ raise NotImplementedError("Must implement `__str__`")
205
+
206
+ def __repr__(self) -> str:
207
+ return f"<{type(self).__name__} {self}>"
208
+
209
+ def __iter__(self) -> Iterator[T]:
210
+ raise NotImplementedError("must be implemented by subclass")
211
+
212
+ def __hash__(self) -> int:
213
+ hashval = self.__hash
214
+ if hashval is None:
215
+ self.__hash = hashval = hash(tuple(self))
216
+ return hashval
217
+
218
+ def __eq__(self, other: "Predicate") -> bool:
219
+ return type(self) is type(other) and tuple(self) == tuple(other)
220
+
221
+
222
+ @final
223
+ class Equals(Predicate[str]):
224
+ """
225
+ A predicate that matches any input equal to `value`.
226
+ """
227
+
228
+ __slots__ = ("value",)
229
+
230
+ def __init__(self, value: str) -> None:
231
+ super().__init__()
232
+ self.value: Final = value
233
+
234
+ def __call__(self, other: TypeStr) -> bool:
235
+ return self.value == other
236
+
237
+ def __str__(self) -> str:
238
+ # NOTE should this just be done at init time? is it always called?
239
+ string = self._string
240
+ if string is None:
241
+ self._string = string = f"(== {self.value!r})"
242
+ return string
243
+
244
+ def __iter__(self) -> Iterator[str]:
245
+ yield self.value
246
+
247
+
248
+ @final
249
+ class BaseEquals(Predicate[Union[str, bool, None]]):
250
+ """
251
+ A predicate that matches a basic type string with a base component equal to
252
+ `value` and no array component. If `with_sub` is `True`, the type string
253
+ must have a sub component to match. If `with_sub` is `False`, the type
254
+ string must *not* have a sub component to match. If `with_sub` is None,
255
+ the type string's sub component is ignored.
256
+ """
257
+
258
+ __slots__ = ("base", "with_sub")
259
+
260
+ def __init__(self, base: TypeStr, *, with_sub: Optional[bool] = None):
261
+ super().__init__()
262
+ self.base: Final = base
263
+ self.with_sub: Final = with_sub
264
+
265
+ def __call__(self, type_str: TypeStr) -> bool:
266
+ try:
267
+ abi_type = grammar.parse(type_str)
268
+ except (exceptions.ParseError, ValueError):
269
+ return False
270
+
271
+ if isinstance(abi_type, grammar.BasicType):
272
+ if abi_type.arrlist is not None:
273
+ return False
274
+
275
+ with_sub = self.with_sub
276
+ if with_sub is not None:
277
+ abi_subtype = abi_type.sub
278
+ if with_sub and abi_subtype is None:
279
+ return False
280
+ if not with_sub and abi_subtype is not None:
281
+ return False
282
+
283
+ return abi_type.base == self.base
284
+
285
+ # We'd reach this point if `type_str` did not contain a basic type
286
+ # e.g. if it contained a tuple type
287
+ return False
288
+
289
+ def __str__(self) -> str:
290
+ # NOTE should this just be done at init time? is it always called?
291
+ string = self._string
292
+ if string is None:
293
+ if self.with_sub is None:
294
+ string = f"(base == {self.base!r})"
295
+ elif self.with_sub:
296
+ string = f"(base == {self.base!r} and sub is not None)"
297
+ else:
298
+ string = f"(base == {self.base!r} and sub is None)"
299
+ self._string = string
300
+ return string
301
+
302
+ def __iter__(self) -> Iterator[Union[str, bool, None]]:
303
+ yield self.base
304
+ yield self.with_sub
305
+
306
+
307
+ def has_arrlist(type_str: TypeStr) -> bool:
308
+ """
309
+ A predicate that matches a type string with an array dimension list.
310
+ """
311
+ try:
312
+ abi_type = grammar.parse(type_str)
313
+ except (exceptions.ParseError, ValueError):
314
+ return False
315
+
316
+ return abi_type.arrlist is not None
317
+
318
+
319
+ def is_base_tuple(type_str: TypeStr) -> bool:
320
+ """
321
+ A predicate that matches a tuple type with no array dimension list.
322
+ """
323
+ try:
324
+ abi_type = grammar.parse(type_str)
325
+ except (exceptions.ParseError, ValueError):
326
+ return False
327
+
328
+ return isinstance(abi_type, grammar.TupleType) and abi_type.arrlist is None
329
+
330
+
331
+ def _clear_encoder_cache(
332
+ old_method: Callable[Concatenate["ABIRegistry", P], T]
333
+ ) -> Callable[Concatenate["ABIRegistry", P], T]:
334
+ @functools.wraps(old_method)
335
+ def new_method(self: "ABIRegistry", *args: P.args, **kwargs: P.kwargs) -> T:
336
+ self.get_encoder.cache_clear()
337
+ self.get_tuple_encoder.cache_clear()
338
+ return old_method(self, *args, **kwargs)
339
+
340
+ return new_method
341
+
342
+
343
+ def _clear_decoder_cache(
344
+ old_method: Callable[Concatenate["ABIRegistry", P], T]
345
+ ) -> Callable[Concatenate["ABIRegistry", P], T]:
346
+ @functools.wraps(old_method)
347
+ def new_method(self: "ABIRegistry", *args: P.args, **kwargs: P.kwargs) -> T:
348
+ self.get_decoder.cache_clear()
349
+ self.get_tuple_decoder.cache_clear()
350
+ return old_method(self, *args, **kwargs)
351
+
352
+ return new_method
353
+
354
+
355
+ class BaseRegistry:
356
+ @staticmethod
357
+ def _register(
358
+ mapping: PredicateMapping[T],
359
+ lookup: Lookup,
360
+ value: T,
361
+ label: Optional[str] = None,
362
+ ) -> None:
363
+ if callable(lookup):
364
+ mapping.add(lookup, value, label)
365
+ return
366
+
367
+ if isinstance(lookup, str):
368
+ mapping.add(Equals(lookup), value, lookup)
369
+ return
370
+
371
+ raise TypeError(
372
+ f"Lookup must be a callable or a value of type `str`: got {lookup!r}"
373
+ )
374
+
375
+ @staticmethod
376
+ def _unregister(mapping: PredicateMapping[Any], lookup_or_label: Lookup) -> None:
377
+ if callable(lookup_or_label):
378
+ mapping.remove_by_equality(lookup_or_label)
379
+ return
380
+
381
+ if isinstance(lookup_or_label, str):
382
+ mapping.remove_by_label(lookup_or_label)
383
+ return
384
+
385
+ raise TypeError(
386
+ f"Lookup/label must be a callable or a value of type `str`: "
387
+ f"got {lookup_or_label!r}"
388
+ )
389
+
390
+ @staticmethod
391
+ def _get_registration(mapping: PredicateMapping[T], type_str: TypeStr) -> T:
392
+ try:
393
+ value = mapping.find(type_str)
394
+ except ValueError as e:
395
+ if "No matching" in e.args[0]:
396
+ # If no matches found, attempt to parse in case lack of matches
397
+ # was due to unparsability
398
+ grammar.parse(type_str)
399
+
400
+ raise
401
+
402
+ return value
403
+
404
+
405
+ class ABIRegistry(Copyable, BaseRegistry):
406
+ def __init__(self) -> None:
407
+ self._encoders: PredicateMapping[Encoder] = PredicateMapping("encoder registry")
408
+ self._decoders: PredicateMapping[Decoder] = PredicateMapping("decoder registry")
409
+ self.get_encoder = functools.lru_cache(maxsize=None)(self._get_encoder_uncached)
410
+ self.get_decoder = functools.lru_cache(maxsize=None)(self._get_decoder_uncached)
411
+ self.get_tuple_encoder = functools.lru_cache(maxsize=None)(
412
+ self._get_tuple_encoder_uncached
413
+ )
414
+ self.get_tuple_decoder = functools.lru_cache(maxsize=None)(
415
+ self._get_tuple_decoder_uncached
416
+ )
417
+
418
+ def _get_registration(self, mapping: PredicateMapping[T], type_str: TypeStr) -> T:
419
+ coder = super()._get_registration(mapping, type_str)
420
+
421
+ if isinstance(coder, type) and issubclass(coder, BaseCoder):
422
+ return coder.from_type_str(type_str, self)
423
+
424
+ return cast(T, coder)
425
+
426
+ @_clear_encoder_cache
427
+ def register_encoder(
428
+ self, lookup: Lookup, encoder: Encoder, label: Optional[str] = None
429
+ ) -> None:
430
+ """
431
+ Registers the given ``encoder`` under the given ``lookup``. A unique
432
+ string label may be optionally provided that can be used to refer to
433
+ the registration by name. For more information about arguments, refer
434
+ to :any:`register`.
435
+ """
436
+ self._register(self._encoders, lookup, encoder, label=label)
437
+
438
+ @_clear_encoder_cache
439
+ def unregister_encoder(self, lookup_or_label: Lookup) -> None:
440
+ """
441
+ Unregisters an encoder in the registry with the given lookup or label.
442
+ If ``lookup_or_label`` is a string, the encoder with the label
443
+ ``lookup_or_label`` will be unregistered. If it is an function, the
444
+ encoder with the lookup function ``lookup_or_label`` will be
445
+ unregistered.
446
+ """
447
+ self._unregister(self._encoders, lookup_or_label)
448
+
449
+ @_clear_decoder_cache
450
+ def register_decoder(
451
+ self, lookup: Lookup, decoder: Decoder, label: Optional[str] = None
452
+ ) -> None:
453
+ """
454
+ Registers the given ``decoder`` under the given ``lookup``. A unique
455
+ string label may be optionally provided that can be used to refer to
456
+ the registration by name. For more information about arguments, refer
457
+ to :any:`register`.
458
+ """
459
+ self._register(self._decoders, lookup, decoder, label=label)
460
+
461
+ @_clear_decoder_cache
462
+ def unregister_decoder(self, lookup_or_label: Lookup) -> None:
463
+ """
464
+ Unregisters a decoder in the registry with the given lookup or label.
465
+ If ``lookup_or_label`` is a string, the decoder with the label
466
+ ``lookup_or_label`` will be unregistered. If it is an function, the
467
+ decoder with the lookup function ``lookup_or_label`` will be
468
+ unregistered.
469
+ """
470
+ self._unregister(self._decoders, lookup_or_label)
471
+
472
+ def register(
473
+ self,
474
+ lookup: Lookup,
475
+ encoder: Encoder,
476
+ decoder: Decoder,
477
+ label: Optional[str] = None,
478
+ ) -> None:
479
+ """
480
+ Registers the given ``encoder`` and ``decoder`` under the given
481
+ ``lookup``. A unique string label may be optionally provided that can
482
+ be used to refer to the registration by name.
483
+
484
+ :param lookup: A type string or type string matcher function
485
+ (predicate). When the registry is queried with a type string
486
+ ``query`` to determine which encoder or decoder to use, ``query``
487
+ will be checked against every registration in the registry. If a
488
+ registration was created with a type string for ``lookup``, it will
489
+ be considered a match if ``lookup == query``. If a registration
490
+ was created with a matcher function for ``lookup``, it will be
491
+ considered a match if ``lookup(query) is True``. If more than one
492
+ registration is found to be a match, then an exception is raised.
493
+
494
+ :param encoder: An encoder callable or class to use if ``lookup``
495
+ matches a query. If ``encoder`` is a callable, it must accept a
496
+ python value and return a ``bytes`` value. If ``encoder`` is a
497
+ class, it must be a valid subclass of :any:`encoding.BaseEncoder`
498
+ and must also implement the :any:`from_type_str` method on
499
+ :any:`base.BaseCoder`.
500
+
501
+ :param decoder: A decoder callable or class to use if ``lookup``
502
+ matches a query. If ``decoder`` is a callable, it must accept a
503
+ stream-like object of bytes and return a python value. If
504
+ ``decoder`` is a class, it must be a valid subclass of
505
+ :any:`decoding.BaseDecoder` and must also implement the
506
+ :any:`from_type_str` method on :any:`base.BaseCoder`.
507
+
508
+ :param label: An optional label that can be used to refer to this
509
+ registration by name. This label can be used to unregister an
510
+ entry in the registry via the :any:`unregister` method and its
511
+ variants.
512
+ """
513
+ self.register_encoder(lookup, encoder, label=label)
514
+ self.register_decoder(lookup, decoder, label=label)
515
+
516
+ def unregister(self, label: Optional[str]) -> None:
517
+ """
518
+ Unregisters the entries in the encoder and decoder registries which
519
+ have the label ``label``.
520
+ """
521
+ self.unregister_encoder(label)
522
+ self.unregister_decoder(label)
523
+
524
+ def _get_encoder_uncached(self, type_str: TypeStr) -> Encoder:
525
+ return self._get_registration(self._encoders, type_str)
526
+
527
+ def _get_tuple_encoder_uncached(
528
+ self,
529
+ *type_strs: TypeStr,
530
+ ) -> encoding.TupleEncoder:
531
+ encoders = tuple(map(self.get_encoder, type_strs))
532
+ return encoding.TupleEncoder(encoders=encoders)
533
+
534
+ def has_encoder(self, type_str: TypeStr) -> bool:
535
+ """
536
+ Returns ``True`` if an encoder is found for the given type string
537
+ ``type_str``. Otherwise, returns ``False``. Raises
538
+ :class:`~faster_eth_abi.exceptions.MultipleEntriesFound` if multiple encoders
539
+ are found.
540
+ """
541
+ try:
542
+ self.get_encoder(type_str)
543
+ except Exception as e:
544
+ if isinstance(e, MultipleEntriesFound):
545
+ raise e
546
+ return False
547
+
548
+ return True
549
+
550
+ def _get_decoder_uncached(self, type_str: TypeStr, strict: bool = True) -> Decoder:
551
+ decoder = self._get_registration(self._decoders, type_str)
552
+
553
+ if hasattr(decoder, "is_dynamic") and decoder.is_dynamic:
554
+ # Set a transient flag each time a call is made to ``get_decoder()``.
555
+ # Only dynamic decoders should be allowed these looser constraints. All
556
+ # other decoders should keep the default value of ``True``.
557
+ decoder.strict = strict
558
+
559
+ return decoder
560
+
561
+ def _get_tuple_decoder_uncached(
562
+ self,
563
+ *type_strs: TypeStr,
564
+ strict: bool = True,
565
+ ) -> decoding.TupleDecoder:
566
+ decoders = tuple(
567
+ self.get_decoder(type_str, strict)
568
+ for type_str in type_strs
569
+ )
570
+ return decoding.TupleDecoder(decoders=decoders)
571
+
572
+ def copy(self) -> Self:
573
+ """
574
+ Copies a registry such that new registrations can be made or existing
575
+ registrations can be unregistered without affecting any instance from
576
+ which a copy was obtained. This is useful if an existing registry
577
+ fulfills most of a user's needs but requires one or two modifications.
578
+ In that case, a copy of that registry can be obtained and the necessary
579
+ changes made without affecting the original registry.
580
+ """
581
+ cpy = type(self)()
582
+
583
+ cpy._encoders = copy(self._encoders)
584
+ cpy._decoders = copy(self._decoders)
585
+
586
+ return cpy
587
+
588
+
589
+ registry = ABIRegistry()
590
+
591
+ is_int = BaseEquals("int")
592
+ is_int8 = Equals("int8")
593
+ is_int16 = Equals("int16")
594
+ is_uint = BaseEquals("uint")
595
+ is_uint8 = Equals("uint8")
596
+ is_uint16 = Equals("uint16")
597
+
598
+ for size in (8, 16):
599
+ registry.register(
600
+ Equals(f"uint{size}"),
601
+ encoding.UnsignedIntegerEncoder,
602
+ decoding.UnsignedIntegerDecoder,
603
+ label=f"uint{size}",
604
+ )
605
+ registry.register(
606
+ Equals(f"int{size}"),
607
+ encoding.SignedIntegerEncoder,
608
+ decoding.SignedIntegerDecoder,
609
+ label=f"int{size}",
610
+ )
611
+
612
+ registry.register(
613
+ lambda s: is_uint(s) and not is_uint8(s) and not is_uint16(s),
614
+ encoding.UnsignedIntegerEncoder,
615
+ decoding.UnsignedIntegerDecoder,
616
+ label="uint",
617
+ )
618
+ registry.register(
619
+ lambda s: is_int(s) and not is_int8(s) and not is_int16(s),
620
+ encoding.SignedIntegerEncoder,
621
+ decoding.SignedIntegerDecoder,
622
+ label="int",
623
+ )
624
+ registry.register(
625
+ BaseEquals("address"),
626
+ encoding.AddressEncoder,
627
+ decoding.AddressDecoder,
628
+ label="address",
629
+ )
630
+ registry.register(
631
+ BaseEquals("bool"),
632
+ encoding.BooleanEncoder,
633
+ decoding.BooleanDecoder,
634
+ label="bool",
635
+ )
636
+ registry.register(
637
+ BaseEquals("ufixed"),
638
+ encoding.UnsignedFixedEncoder,
639
+ decoding.UnsignedFixedDecoder,
640
+ label="ufixed",
641
+ )
642
+ registry.register(
643
+ BaseEquals("fixed"),
644
+ encoding.SignedFixedEncoder,
645
+ decoding.SignedFixedDecoder,
646
+ label="fixed",
647
+ )
648
+ registry.register(
649
+ BaseEquals("bytes", with_sub=True),
650
+ encoding.BytesEncoder,
651
+ decoding.BytesDecoder,
652
+ label="bytes<M>",
653
+ )
654
+ registry.register(
655
+ BaseEquals("bytes", with_sub=False),
656
+ encoding.ByteStringEncoder,
657
+ decoding.ByteStringDecoder,
658
+ label="bytes",
659
+ )
660
+ registry.register(
661
+ BaseEquals("function"),
662
+ encoding.BytesEncoder,
663
+ decoding.BytesDecoder,
664
+ label="function",
665
+ )
666
+ registry.register(
667
+ BaseEquals("string"),
668
+ encoding.TextStringEncoder,
669
+ decoding.StringDecoder,
670
+ label="string",
671
+ )
672
+ registry.register(
673
+ has_arrlist,
674
+ encoding.BaseArrayEncoder,
675
+ decoding.BaseArrayDecoder,
676
+ label="has_arrlist",
677
+ )
678
+ registry.register(
679
+ is_base_tuple,
680
+ encoding.TupleEncoder,
681
+ decoding.TupleDecoder,
682
+ label="is_base_tuple",
683
+ )
684
+
685
+ registry_packed = ABIRegistry()
686
+
687
+ for size in (8, 16):
688
+ registry_packed.register_encoder(
689
+ Equals(f"uint{size}"),
690
+ encoding.PackedUnsignedIntegerEncoderCached,
691
+ label=f"uint{size}",
692
+ )
693
+ registry_packed.register_encoder(
694
+ Equals(f"int{size}"),
695
+ encoding.PackedSignedIntegerEncoderCached,
696
+ label=f"int{size}",
697
+ )
698
+
699
+ registry_packed.register_encoder(
700
+ lambda s: is_uint(s) and not is_uint8(s) and not is_uint16(s),
701
+ encoding.PackedUnsignedIntegerEncoder,
702
+ label="uint",
703
+ )
704
+ registry_packed.register_encoder(
705
+ lambda s: is_int(s) and not is_int8(s) and not is_int16(s),
706
+ encoding.PackedSignedIntegerEncoder,
707
+ label="int",
708
+ )
709
+ registry_packed.register_encoder(
710
+ BaseEquals("address"),
711
+ encoding.PackedAddressEncoder,
712
+ label="address",
713
+ )
714
+ registry_packed.register_encoder(
715
+ BaseEquals("bool"),
716
+ encoding.PackedBooleanEncoder,
717
+ label="bool",
718
+ )
719
+ registry_packed.register_encoder(
720
+ BaseEquals("ufixed"),
721
+ encoding.PackedUnsignedFixedEncoder,
722
+ label="ufixed",
723
+ )
724
+ registry_packed.register_encoder(
725
+ BaseEquals("fixed"),
726
+ encoding.PackedSignedFixedEncoder,
727
+ label="fixed",
728
+ )
729
+ registry_packed.register_encoder(
730
+ BaseEquals("bytes", with_sub=True),
731
+ encoding.PackedBytesEncoder,
732
+ label="bytes<M>",
733
+ )
734
+ registry_packed.register_encoder(
735
+ BaseEquals("bytes", with_sub=False),
736
+ encoding.PackedByteStringEncoder,
737
+ label="bytes",
738
+ )
739
+ registry_packed.register_encoder(
740
+ BaseEquals("function"),
741
+ encoding.PackedBytesEncoder,
742
+ label="function",
743
+ )
744
+ registry_packed.register_encoder(
745
+ BaseEquals("string"),
746
+ encoding.PackedTextStringEncoder,
747
+ label="string",
748
+ )
749
+ registry_packed.register_encoder(
750
+ has_arrlist,
751
+ encoding.PackedArrayEncoder,
752
+ label="has_arrlist",
753
+ )
754
+ registry_packed.register_encoder(
755
+ is_base_tuple,
756
+ encoding.TupleEncoder,
757
+ label="is_base_tuple",
758
+ )