faster-eth-abi 5.2.4__cp314-cp314t-macosx_11_0_arm64.whl → 5.2.6__cp314-cp314t-macosx_11_0_arm64.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 (29) hide show
  1. c42f5c78bc058f310136__mypyc.cpython-314t-darwin.so +0 -0
  2. faster_eth_abi/_codec.cpython-314t-darwin.so +0 -0
  3. faster_eth_abi/_codec.py +82 -0
  4. faster_eth_abi/_encoding.cpython-314t-darwin.so +0 -0
  5. faster_eth_abi/_encoding.py +103 -0
  6. faster_eth_abi/abi.cpython-314t-darwin.so +0 -0
  7. faster_eth_abi/codec.py +6 -30
  8. faster_eth_abi/constants.cpython-314t-darwin.so +0 -0
  9. faster_eth_abi/encoding.py +36 -93
  10. faster_eth_abi/from_type_str.cpython-314t-darwin.so +0 -0
  11. faster_eth_abi/grammar.py +5 -4
  12. faster_eth_abi/packed.cpython-314t-darwin.so +0 -0
  13. faster_eth_abi/registry.py +25 -2
  14. faster_eth_abi/tools/__init__.cpython-314t-darwin.so +0 -0
  15. faster_eth_abi/tools/_strategies.cpython-314t-darwin.so +0 -0
  16. faster_eth_abi/utils/__init__.cpython-314t-darwin.so +0 -0
  17. faster_eth_abi/utils/numeric.cpython-314t-darwin.so +0 -0
  18. faster_eth_abi/utils/padding.cpython-314t-darwin.so +0 -0
  19. faster_eth_abi/utils/string.cpython-314t-darwin.so +0 -0
  20. faster_eth_abi/utils/validation.cpython-314t-darwin.so +0 -0
  21. faster_eth_abi/utils/validation.py +1 -5
  22. {faster_eth_abi-5.2.4.dist-info → faster_eth_abi-5.2.6.dist-info}/METADATA +19 -2
  23. faster_eth_abi-5.2.6.dist-info/RECORD +42 -0
  24. faster_eth_abi-5.2.6.dist-info/top_level.txt +3 -0
  25. a1f8aa123fabc88e2b56__mypyc.cpython-314t-darwin.so +0 -0
  26. faster_eth_abi-5.2.4.dist-info/RECORD +0 -38
  27. faster_eth_abi-5.2.4.dist-info/top_level.txt +0 -3
  28. {faster_eth_abi-5.2.4.dist-info → faster_eth_abi-5.2.6.dist-info}/WHEEL +0 -0
  29. {faster_eth_abi-5.2.4.dist-info → faster_eth_abi-5.2.6.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,82 @@
1
+ from typing import (
2
+ TYPE_CHECKING,
3
+ Any,
4
+ Iterable,
5
+ Tuple,
6
+ cast,
7
+ )
8
+
9
+ from eth_typing import (
10
+ Decodable,
11
+ TypeStr,
12
+ )
13
+
14
+ from faster_eth_abi.utils.validation import (
15
+ validate_bytes_param,
16
+ validate_list_like_param,
17
+ )
18
+
19
+ if TYPE_CHECKING:
20
+ from faster_eth_abi.codec import (
21
+ ABIDecoder,
22
+ ABIEncoder,
23
+ )
24
+
25
+
26
+ def encode_c(
27
+ self: "ABIEncoder",
28
+ types: Iterable[TypeStr],
29
+ args: Iterable[Any],
30
+ ) -> bytes:
31
+ """
32
+ Encodes the python values in ``args`` as a sequence of binary values of
33
+ the ABI types in ``types`` via the head-tail mechanism.
34
+
35
+ :param types: A list or tuple of string representations of the ABI types
36
+ that will be used for encoding e.g. ``('uint256', 'bytes[]',
37
+ '(int,int)')``
38
+ :param args: A list or tuple of python values to be encoded.
39
+
40
+ :returns: The head-tail encoded binary representation of the python
41
+ values in ``args`` as values of the ABI types in ``types``.
42
+ """
43
+ # validate encode types and args
44
+ validate_list_like_param(types, "types")
45
+ validate_list_like_param(args, "args")
46
+
47
+ encoder = self._registry.get_tuple_encoder(*types)
48
+
49
+ return encoder(args)
50
+
51
+
52
+ def decode_c(
53
+ self: "ABIDecoder",
54
+ types: Iterable[TypeStr],
55
+ data: Decodable,
56
+ strict: bool = True,
57
+ ) -> Tuple[Any, ...]:
58
+ """
59
+ Decodes the binary value ``data`` as a sequence of values of the ABI types
60
+ in ``types`` via the head-tail mechanism into a tuple of equivalent python
61
+ values.
62
+
63
+ :param types: A list or tuple of string representations of the ABI types that
64
+ will be used for decoding e.g. ``('uint256', 'bytes[]', '(int,int)')``
65
+ :param data: The binary value to be decoded.
66
+ :param strict: If ``False``, dynamic-type decoders will ignore validations such
67
+ as making sure the data is padded to a multiple of 32 bytes or checking that
68
+ padding bytes are zero / empty. ``False`` is how the Solidity ABI decoder
69
+ currently works. However, ``True`` is the default for the faster-eth-abi
70
+ library.
71
+
72
+ :returns: A tuple of equivalent python values for the ABI values
73
+ represented in ``data``.
74
+ """
75
+ # validate decode types and data
76
+ validate_list_like_param(types, "types")
77
+ validate_bytes_param(data, "data")
78
+
79
+ decoder = self._registry.get_tuple_decoder(*types, strict=strict)
80
+ stream = self.stream_class(data)
81
+
82
+ return cast(Tuple[Any, ...], decoder(stream))
@@ -0,0 +1,103 @@
1
+ from itertools import (
2
+ accumulate,
3
+ )
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Any,
7
+ Callable,
8
+ List,
9
+ Optional,
10
+ Sequence,
11
+ TypeVar,
12
+ )
13
+
14
+ if TYPE_CHECKING:
15
+ from faster_eth_abi.encoding import (
16
+ BaseEncoder,
17
+ )
18
+
19
+
20
+ T = TypeVar("T")
21
+
22
+
23
+ def encode_tuple(
24
+ values: Sequence[Any],
25
+ encoders: Sequence["BaseEncoder"],
26
+ ) -> bytes:
27
+ raw_head_chunks: List[Optional[bytes]] = []
28
+ tail_chunks: List[bytes] = []
29
+ for value, encoder in zip(values, encoders):
30
+ if getattr(encoder, "is_dynamic", False):
31
+ raw_head_chunks.append(None)
32
+ tail_chunks.append(encoder(value))
33
+ else:
34
+ raw_head_chunks.append(encoder(value))
35
+ tail_chunks.append(b"")
36
+
37
+ head_length = sum(32 if item is None else len(item) for item in raw_head_chunks)
38
+ tail_offsets = (0, *accumulate(len(item) for item in tail_chunks[:-1]))
39
+ head_chunks = tuple(
40
+ encode_uint_256(head_length + offset) if chunk is None else chunk
41
+ for chunk, offset in zip(raw_head_chunks, tail_offsets)
42
+ )
43
+
44
+ return b"".join(head_chunks) + b"".join(tail_chunks)
45
+
46
+
47
+ def encode_fixed(
48
+ value: Any,
49
+ encode_fn: Callable[[Any], bytes],
50
+ is_big_endian: bool,
51
+ data_byte_size: int,
52
+ ) -> bytes:
53
+ base_encoded_value = encode_fn(value)
54
+ if is_big_endian:
55
+ return base_encoded_value.rjust(data_byte_size, b"\x00")
56
+ else:
57
+ return base_encoded_value.ljust(data_byte_size, b"\x00")
58
+
59
+
60
+ def encode_signed(
61
+ value: T,
62
+ encode_fn: Callable[[T], bytes],
63
+ data_byte_size: int,
64
+ ) -> bytes:
65
+ base_encoded_value = encode_fn(value)
66
+ if value >= 0:
67
+ return base_encoded_value.rjust(data_byte_size, b"\x00")
68
+ else:
69
+ return base_encoded_value.rjust(data_byte_size, b"\xff")
70
+
71
+
72
+ def encode_elements(item_encoder: "BaseEncoder", value: Sequence[Any]) -> bytes:
73
+ tail_chunks = tuple(item_encoder(i) for i in value)
74
+
75
+ items_are_dynamic: bool = getattr(item_encoder, "is_dynamic", False)
76
+ if not items_are_dynamic or len(value) == 0:
77
+ return b"".join(tail_chunks)
78
+
79
+ head_length = 32 * len(value)
80
+ tail_offsets = (0, *accumulate(len(item) for item in tail_chunks[:-1]))
81
+ head_chunks = tuple(
82
+ encode_uint_256(head_length + offset) for offset in tail_offsets
83
+ )
84
+ return b"".join(head_chunks) + b"".join(tail_chunks)
85
+
86
+
87
+ def encode_elements_dynamic(item_encoder: "BaseEncoder", value: Sequence[Any]) -> bytes:
88
+ encoded_size = encode_uint_256(len(value))
89
+ encoded_elements = encode_elements(item_encoder, value)
90
+ return encoded_size + encoded_elements
91
+
92
+
93
+ def encode_uint_256(i: int) -> bytes:
94
+ # An optimized version of the `encode_uint_256` in `encoding.py` which
95
+ # does not perform any validation. We should not have any issues here
96
+ # unless you're encoding really really massive iterables.
97
+ big_endian = int_to_big_endian(i)
98
+ return big_endian.rjust(32, b"\x00")
99
+
100
+
101
+ def int_to_big_endian(value: int) -> bytes:
102
+ # vendored from eth-utils so it can compile nicely into faster-eth-abi's binary
103
+ return value.to_bytes((value.bit_length() + 7) // 8 or 1, "big")
Binary file
faster_eth_abi/codec.py CHANGED
@@ -2,7 +2,6 @@ from typing import (
2
2
  Any,
3
3
  Iterable,
4
4
  Tuple,
5
- cast,
6
5
  )
7
6
 
8
7
  from eth_typing.abi import (
@@ -10,12 +9,12 @@ from eth_typing.abi import (
10
9
  TypeStr,
11
10
  )
12
11
 
12
+ from faster_eth_abi._codec import (
13
+ decode_c,
14
+ encode_c,
15
+ )
13
16
  from faster_eth_abi.decoding import (
14
17
  ContextFramesBytesIO,
15
- TupleDecoder,
16
- )
17
- from faster_eth_abi.encoding import (
18
- TupleEncoder,
19
18
  )
20
19
  from faster_eth_abi.exceptions import (
21
20
  EncodingError,
@@ -23,10 +22,6 @@ from faster_eth_abi.exceptions import (
23
22
  from faster_eth_abi.registry import (
24
23
  ABIRegistry,
25
24
  )
26
- from faster_eth_abi.utils.validation import (
27
- validate_bytes_param,
28
- validate_list_like_param,
29
- )
30
25
 
31
26
 
32
27
  class BaseABICoder:
@@ -64,15 +59,7 @@ class ABIEncoder(BaseABICoder):
64
59
  :returns: The head-tail encoded binary representation of the python
65
60
  values in ``args`` as values of the ABI types in ``types``.
66
61
  """
67
- # validate encode types and args
68
- validate_list_like_param(types, "types")
69
- validate_list_like_param(args, "args")
70
-
71
- encoders = tuple(self._registry.get_encoder(type_str) for type_str in types)
72
-
73
- encoder = TupleEncoder(encoders=encoders)
74
-
75
- return encoder(args)
62
+ return encode_c(self, types, args)
76
63
 
77
64
  def is_encodable(self, typ: TypeStr, arg: Any) -> bool:
78
65
  """
@@ -149,18 +136,7 @@ class ABIDecoder(BaseABICoder):
149
136
  :returns: A tuple of equivalent python values for the ABI values
150
137
  represented in ``data``.
151
138
  """
152
- # validate decode types and data
153
- validate_list_like_param(types, "types")
154
- validate_bytes_param(data, "data")
155
-
156
- decoders = tuple(
157
- self._registry.get_decoder(type_str, strict=strict) for type_str in types
158
- )
159
-
160
- decoder = TupleDecoder(decoders=decoders)
161
- stream = self.stream_class(data)
162
-
163
- return cast(Tuple[Any, ...], decoder(stream))
139
+ return decode_c(self, types, data, strict)
164
140
 
165
141
 
166
142
  class ABICodec(ABIEncoder, ABIDecoder):
@@ -1,18 +1,16 @@
1
1
  import abc
2
2
  import codecs
3
3
  import decimal
4
- from itertools import (
5
- accumulate,
6
- )
7
4
  from typing import (
8
5
  Any,
6
+ NoReturn,
9
7
  Optional,
8
+ Sequence,
10
9
  Tuple,
11
10
  Type,
12
11
  )
13
12
 
14
13
  from faster_eth_utils import (
15
- int_to_big_endian,
16
14
  is_address,
17
15
  is_boolean,
18
16
  is_bytes,
@@ -23,6 +21,14 @@ from faster_eth_utils import (
23
21
  to_canonical_address,
24
22
  )
25
23
 
24
+ from faster_eth_abi._encoding import (
25
+ encode_elements,
26
+ encode_elements_dynamic,
27
+ encode_fixed,
28
+ encode_signed,
29
+ encode_tuple,
30
+ int_to_big_endian,
31
+ )
26
32
  from faster_eth_abi.base import (
27
33
  BaseCoder,
28
34
  )
@@ -45,8 +51,6 @@ from faster_eth_abi.utils.numeric import (
45
51
  compute_unsigned_integer_bounds,
46
52
  )
47
53
  from faster_eth_abi.utils.padding import (
48
- fpad,
49
- zpad,
50
54
  zpad_right,
51
55
  )
52
56
  from faster_eth_abi.utils.string import (
@@ -82,7 +86,7 @@ class BaseEncoder(BaseCoder, metaclass=abc.ABCMeta):
82
86
  value: Any,
83
87
  exc: Type[Exception] = EncodingTypeError,
84
88
  msg: Optional[str] = None,
85
- ) -> None:
89
+ ) -> NoReturn:
86
90
  """
87
91
  Throws a standard exception for when a value is not encodable by an
88
92
  encoder.
@@ -133,26 +137,7 @@ class TupleEncoder(BaseEncoder):
133
137
 
134
138
  def encode(self, values):
135
139
  self.validate_value(values)
136
-
137
- raw_head_chunks = []
138
- tail_chunks = []
139
- for value, encoder in zip(values, self.encoders):
140
- if getattr(encoder, "is_dynamic", False):
141
- raw_head_chunks.append(None)
142
- tail_chunks.append(encoder(value))
143
- else:
144
- raw_head_chunks.append(encoder(value))
145
- tail_chunks.append(b"")
146
-
147
- head_length = sum(32 if item is None else len(item) for item in raw_head_chunks)
148
- tail_offsets = (0,) + tuple(accumulate(map(len, tail_chunks[:-1])))
149
- head_chunks = tuple(
150
- encode_uint_256(head_length + offset) if chunk is None else chunk
151
- for chunk, offset in zip(raw_head_chunks, tail_offsets)
152
- )
153
-
154
- encoded_value = b"".join(head_chunks + tuple(tail_chunks))
155
- return encoded_value
140
+ return encode_tuple(values, self.encoders)
156
141
 
157
142
  @parse_tuple_type_str
158
143
  def from_type_str(cls, abi_type, registry):
@@ -194,18 +179,13 @@ class FixedSizeEncoder(BaseEncoder):
194
179
  def validate_value(self, value):
195
180
  raise NotImplementedError("Must be implemented by subclasses")
196
181
 
197
- def encode(self, value):
182
+ def encode(self, value: Any) -> bytes:
198
183
  self.validate_value(value)
199
184
  if self.encode_fn is None:
200
185
  raise AssertionError("`encode_fn` is None")
201
- base_encoded_value = self.encode_fn(value)
202
-
203
- if self.is_big_endian:
204
- padded_encoded_value = zpad(base_encoded_value, self.data_byte_size)
205
- else:
206
- padded_encoded_value = zpad_right(base_encoded_value, self.data_byte_size)
207
-
208
- return padded_encoded_value
186
+ return encode_fixed(
187
+ value, self.encode_fn, self.is_big_endian, self.data_byte_size
188
+ )
209
189
 
210
190
 
211
191
  class Fixed32ByteSizeEncoder(FixedSizeEncoder):
@@ -217,7 +197,7 @@ class BooleanEncoder(Fixed32ByteSizeEncoder):
217
197
  is_big_endian = True
218
198
 
219
199
  @classmethod
220
- def validate_value(cls, value):
200
+ def validate_value(cls, value: Any) -> None:
221
201
  if not is_boolean(value):
222
202
  cls.invalidate_value(value)
223
203
 
@@ -301,19 +281,12 @@ class SignedIntegerEncoder(NumberEncoder):
301
281
  bounds_fn = staticmethod(compute_signed_integer_bounds)
302
282
  type_check_fn = staticmethod(is_integer)
303
283
 
304
- def encode_fn(self, value):
284
+ def encode_fn(self, value: int) -> bytes:
305
285
  return int_to_big_endian(value % (2**self.value_bit_size))
306
286
 
307
287
  def encode(self, value):
308
288
  self.validate_value(value)
309
- base_encoded_value = self.encode_fn(value)
310
-
311
- if value >= 0:
312
- padded_encoded_value = zpad(base_encoded_value, self.data_byte_size)
313
- else:
314
- padded_encoded_value = fpad(base_encoded_value, self.data_byte_size)
315
-
316
- return padded_encoded_value
289
+ return encode_signed(value, self.encode_fn, self.data_byte_size)
317
290
 
318
291
  @parse_type_str("int")
319
292
  def from_type_str(cls, abi_type, registry):
@@ -353,7 +326,7 @@ class BaseFixedEncoder(NumberEncoder):
353
326
  self.invalidate_value(
354
327
  value,
355
328
  exc=IllegalValue,
356
- msg=f"residue {repr(residue)} outside allowed fractional precision of "
329
+ msg=f"residue {residue!r} outside allowed fractional precision of "
357
330
  f"{self.frac_places}",
358
331
  )
359
332
 
@@ -415,14 +388,7 @@ class SignedFixedEncoder(BaseFixedEncoder):
415
388
 
416
389
  def encode(self, value):
417
390
  self.validate_value(value)
418
- base_encoded_value = self.encode_fn(value)
419
-
420
- if value >= 0:
421
- padded_encoded_value = zpad(base_encoded_value, self.data_byte_size)
422
- else:
423
- padded_encoded_value = fpad(base_encoded_value, self.data_byte_size)
424
-
425
- return padded_encoded_value
391
+ return encode_signed(value, self.encode_fn, self.data_byte_size)
426
392
 
427
393
  @parse_type_str("fixed")
428
394
  def from_type_str(cls, abi_type, registry):
@@ -452,7 +418,7 @@ class AddressEncoder(Fixed32ByteSizeEncoder):
452
418
  is_big_endian = True
453
419
 
454
420
  @classmethod
455
- def validate_value(cls, value):
421
+ def validate_value(cls, value: Any) -> None:
456
422
  if not is_address(value):
457
423
  cls.invalidate_value(value)
458
424
 
@@ -474,7 +440,7 @@ class PackedAddressEncoder(AddressEncoder):
474
440
  class BytesEncoder(Fixed32ByteSizeEncoder):
475
441
  is_big_endian = False
476
442
 
477
- def validate_value(self, value):
443
+ def validate_value(self, value: Any) -> None:
478
444
  if not is_bytes(value):
479
445
  self.invalidate_value(value)
480
446
 
@@ -508,7 +474,7 @@ class ByteStringEncoder(BaseEncoder):
508
474
  is_dynamic = True
509
475
 
510
476
  @classmethod
511
- def validate_value(cls, value):
477
+ def validate_value(cls, value: Any) -> None:
512
478
  if not is_bytes(value):
513
479
  cls.invalidate_value(value)
514
480
 
@@ -540,7 +506,7 @@ class TextStringEncoder(BaseEncoder):
540
506
  is_dynamic = True
541
507
 
542
508
  @classmethod
543
- def validate_value(cls, value):
509
+ def validate_value(cls, value: Any) -> None:
544
510
  if not is_text(value):
545
511
  cls.invalidate_value(value)
546
512
 
@@ -579,7 +545,7 @@ class BaseArrayEncoder(BaseEncoder):
579
545
  if self.item_encoder is None:
580
546
  raise ValueError("`item_encoder` may not be none")
581
547
 
582
- def validate_value(self, value):
548
+ def validate_value(self, value: Any) -> None:
583
549
  if not is_list_like(value):
584
550
  self.invalidate_value(
585
551
  value,
@@ -589,24 +555,9 @@ class BaseArrayEncoder(BaseEncoder):
589
555
  for item in value:
590
556
  self.item_encoder.validate_value(item)
591
557
 
592
- def encode_elements(self, value):
558
+ def encode_elements(self, value: Sequence[Any]) -> bytes:
593
559
  self.validate_value(value)
594
-
595
- item_encoder = self.item_encoder
596
- if item_encoder is None:
597
- raise AssertionError("`item_encoder` is None")
598
- tail_chunks = tuple(item_encoder(i) for i in value)
599
-
600
- items_are_dynamic = getattr(item_encoder, "is_dynamic", False)
601
- if not items_are_dynamic or len(value) == 0:
602
- return b"".join(tail_chunks)
603
-
604
- head_length = 32 * len(value)
605
- tail_offsets = (0,) + tuple(accumulate(map(len, tail_chunks[:-1])))
606
- head_chunks = tuple(
607
- encode_uint_256(head_length + offset) for offset in tail_offsets
608
- )
609
- return b"".join(head_chunks + tail_chunks)
560
+ return encode_elements(self.item_encoder, value)
610
561
 
611
562
  @parse_type_str(with_arrlist=True)
612
563
  def from_type_str(cls, abi_type, registry):
@@ -627,7 +578,7 @@ class BaseArrayEncoder(BaseEncoder):
627
578
  class PackedArrayEncoder(BaseArrayEncoder):
628
579
  array_size = None
629
580
 
630
- def validate_value(self, value):
581
+ def validate_value(self, value: Any) -> None:
631
582
  super().validate_value(value)
632
583
 
633
584
  if self.array_size is not None and len(value) != self.array_size:
@@ -638,10 +589,8 @@ class PackedArrayEncoder(BaseArrayEncoder):
638
589
  "expected",
639
590
  )
640
591
 
641
- def encode(self, value):
642
- encoded_elements = self.encode_elements(value)
643
-
644
- return encoded_elements
592
+ def encode(self, value: Sequence[Any]) -> bytes:
593
+ return encode_elements(self.item_encoder, value)
645
594
 
646
595
  @parse_type_str(with_arrlist=True)
647
596
  def from_type_str(cls, abi_type, registry):
@@ -671,7 +620,7 @@ class SizedArrayEncoder(BaseArrayEncoder):
671
620
  if self.array_size is None:
672
621
  raise ValueError("`array_size` may not be none")
673
622
 
674
- def validate_value(self, value):
623
+ def validate_value(self, value: Any) -> None:
675
624
  super().validate_value(value)
676
625
 
677
626
  if len(value) != self.array_size:
@@ -682,18 +631,12 @@ class SizedArrayEncoder(BaseArrayEncoder):
682
631
  "expected",
683
632
  )
684
633
 
685
- def encode(self, value):
686
- encoded_elements = self.encode_elements(value)
687
-
688
- return encoded_elements
634
+ def encode(self, value: Sequence[Any]) -> bytes:
635
+ return encode_elements(self.item_encoder, value)
689
636
 
690
637
 
691
638
  class DynamicArrayEncoder(BaseArrayEncoder):
692
639
  is_dynamic = True
693
640
 
694
- def encode(self, value):
695
- encoded_size = encode_uint_256(len(value))
696
- encoded_elements = self.encode_elements(value)
697
- encoded_value = encoded_size + encoded_elements
698
-
699
- return encoded_value
641
+ def encode(self, value: Sequence[Any]) -> bytes:
642
+ return encode_elements_dynamic(self.item_encoder, value)
faster_eth_abi/grammar.py CHANGED
@@ -458,10 +458,11 @@ def normalize(type_str: TypeStr) -> TypeStr:
458
458
  :param type_str: The type string to be normalized.
459
459
  :returns: The canonical version of the input type string.
460
460
  """
461
- return TYPE_ALIAS_RE.sub(
462
- lambda match: TYPE_ALIASES[match.group(0)],
463
- type_str,
464
- )
461
+ return TYPE_ALIAS_RE.sub(__normalize, type_str)
462
+
463
+
464
+ def __normalize(match: re.Match[str]) -> str:
465
+ return TYPE_ALIASES[match.group(0)]
465
466
 
466
467
 
467
468
  parse: Final = visitor.parse
@@ -347,6 +347,12 @@ class ABIRegistry(Copyable, BaseRegistry):
347
347
  self._decoders = PredicateMapping("decoder registry")
348
348
  self.get_encoder = functools.lru_cache(maxsize=None)(self._get_encoder_uncached)
349
349
  self.get_decoder = functools.lru_cache(maxsize=None)(self._get_decoder_uncached)
350
+ self.get_tuple_encoder = functools.lru_cache(maxsize=None)(
351
+ self._get_tuple_encoder_uncached
352
+ )
353
+ self.get_tuple_decoder = functools.lru_cache(maxsize=None)(
354
+ self._get_tuple_decoder_uncached
355
+ )
350
356
 
351
357
  def _get_registration(self, mapping, type_str):
352
358
  coder = super()._get_registration(mapping, type_str)
@@ -454,9 +460,17 @@ class ABIRegistry(Copyable, BaseRegistry):
454
460
  self.unregister_encoder(label)
455
461
  self.unregister_decoder(label)
456
462
 
457
- def _get_encoder_uncached(self, type_str):
463
+ def _get_encoder_uncached(self, type_str: TypeStr): # type: ignore [no-untyped-def]
458
464
  return self._get_registration(self._encoders, type_str)
459
465
 
466
+ def _get_tuple_encoder_uncached(
467
+ self,
468
+ *type_strs: TypeStr,
469
+ ) -> encoding.TupleEncoder:
470
+ return encoding.TupleEncoder(
471
+ encoders=tuple(self.get_encoder(type_str) for type_str in type_strs)
472
+ )
473
+
460
474
  def has_encoder(self, type_str: TypeStr) -> bool:
461
475
  """
462
476
  Returns ``True`` if an encoder is found for the given type string
@@ -473,7 +487,7 @@ class ABIRegistry(Copyable, BaseRegistry):
473
487
 
474
488
  return True
475
489
 
476
- def _get_decoder_uncached(self, type_str, strict=True):
490
+ def _get_decoder_uncached(self, type_str: TypeStr, strict: bool = True): # type: ignore [no-untyped-def]
477
491
  decoder = self._get_registration(self._decoders, type_str)
478
492
 
479
493
  if hasattr(decoder, "is_dynamic") and decoder.is_dynamic:
@@ -484,6 +498,15 @@ class ABIRegistry(Copyable, BaseRegistry):
484
498
 
485
499
  return decoder
486
500
 
501
+ def _get_tuple_decoder_uncached(
502
+ self,
503
+ *type_strs: TypeStr,
504
+ strict: bool = True,
505
+ ) -> decoding.TupleDecoder:
506
+ return decoding.TupleDecoder(
507
+ decoders=tuple(self.get_decoder(type_str, strict) for type_str in type_strs)
508
+ )
509
+
487
510
  def copy(self):
488
511
  """
489
512
  Copies a registry such that new registrations can be made or existing
@@ -2,13 +2,9 @@ from typing import (
2
2
  Any,
3
3
  )
4
4
 
5
- from faster_eth_utils import (
6
- is_bytes,
7
- )
8
-
9
5
 
10
6
  def validate_bytes_param(param: Any, param_name: str) -> None:
11
- if not is_bytes(param):
7
+ if not isinstance(param, (bytes, bytearray)):
12
8
  raise TypeError(
13
9
  f"The `{param_name}` value must be of bytes type. Got {type(param)}"
14
10
  )
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: faster_eth_abi
3
- Version: 5.2.4
4
- Summary: A fork of eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding, implemented in C.
3
+ Version: 5.2.6
4
+ Summary: A aster fork of eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding. Implemented in C.
5
5
  Home-page: https://github.com/BobTheBuidler/faster-eth-abi
6
6
  Author: The Ethereum Foundation
7
7
  Author-email: snakecharmers@ethereum.org
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
21
22
  Classifier: Programming Language :: Python :: Implementation :: CPython
22
23
  Requires-Python: >=3.8, <4
23
24
  Description-Content-Type: text/markdown
@@ -36,6 +37,8 @@ Requires-Dist: pre-commit>=3.4.0; extra == "dev"
36
37
  Requires-Dist: tox>=4.0.0; extra == "dev"
37
38
  Requires-Dist: twine; extra == "dev"
38
39
  Requires-Dist: wheel; extra == "dev"
40
+ Requires-Dist: pytest-codspeed; extra == "dev"
41
+ Requires-Dist: pytest-benchmark; extra == "dev"
39
42
  Requires-Dist: sphinx>=6.0.0; extra == "dev"
40
43
  Requires-Dist: sphinx-autobuild>=2021.3.14; extra == "dev"
41
44
  Requires-Dist: sphinx_rtd_theme>=1.0.0; extra == "dev"
@@ -74,6 +77,20 @@ Dynamic: requires-dist
74
77
  Dynamic: requires-python
75
78
  Dynamic: summary
76
79
 
80
+ ### I forked eth-abi and compiled it to C. It does the same stuff, now faster
81
+
82
+ [![PyPI](https://img.shields.io/pypi/v/faster-eth-abi.svg?logo=Python&logoColor=white)](https://pypi.org/project/faster-eth-abi/)
83
+ [![Monthly Downloads](https://img.shields.io/pypi/dm/faster-eth-abi)](https://pypistats.org/packages/faster-eth-abi)
84
+ [![Codspeed.io Status](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/BobTheBuidler/faster-eth-abi)
85
+
86
+ ##### This fork will be kept up-to-date with [eth-abi](https://github.com/ethereum/eth-abi). I will pull updates as they are released and push new [faster-eth-abi](https://github.com/BobTheBuidler/faster-eth-abi) releases to [PyPI](https://pypi.org/project/faster-eth-abi/).
87
+
88
+ ##### You can find the compiled C code on faster-eth-abi [master](https://github.com/BobTheBuidler/eth-abi/tree/master) branch.
89
+
90
+ ##### We benchmark `faster-eth-abi` against the original `eth-abi` for your convenience. [See results](https://github.com/BobTheBuidler/faster-eth-abi/tree/master/benchmarks/results).
91
+
92
+ ##### The original eth-abi readme is below:
93
+
77
94
  # Ethereum Contract Interface (ABI) Utility
78
95
 
79
96
  [![Join the conversation on Discord](https://img.shields.io/discord/809793915578089484?color=blue&label=chat&logo=discord&logoColor=white)](https://discord.gg/GHryRvPB84)
@@ -0,0 +1,42 @@
1
+ c42f5c78bc058f310136__mypyc.cpython-314t-darwin.so,sha256=eBRjBdOOrOb-CHOmQ_OXVkQqNY62jIdp0zEvTwGJQO4,449072
2
+ faster_eth_abi/_encoding.cpython-314t-darwin.so,sha256=8CJf8JxvrN7y7nTXri-4KfwIGdqHHvUAhNiWlVf6Uys,51040
3
+ faster_eth_abi/_encoding.py,sha256=dViSQVK5XvSuLBZADiXImJqXf4dIHkAHYWFzEiJtq-0,3114
4
+ faster_eth_abi/abi.cpython-314t-darwin.so,sha256=kdfQeepcPB9xGYOYJihM9aVttzcwdcK0QXqvjRcWPcQ,50984
5
+ faster_eth_abi/packed.py,sha256=qDPBjish_0h26O7xGWopnlD4pRkphFuFq4izgIqT600,301
6
+ faster_eth_abi/encoding.py,sha256=yYgXubRd3ZxVP6QPrdHhYnjFGSPtqfyaXh4QBLnURms,18163
7
+ faster_eth_abi/registry.py,sha256=kCcz1mJiENDzl9jKzJ99EiSLSSIFxfi4-96Fe59qrJM,20529
8
+ faster_eth_abi/constants.py,sha256=uJbuND1rFs_Pexuz58TKd-BJPuoA6hLqFEX6kkDS-dE,107
9
+ faster_eth_abi/io.py,sha256=PjOnBChWh_-6ADkpJQONnxHVwsAfC_4bRiT6YQhlP6c,3728
10
+ faster_eth_abi/__init__.py,sha256=55jGpiVbsTGNu-c_rr-wwyH3eqEv9MELSTWa4AMiKvU,205
11
+ faster_eth_abi/decoding.py,sha256=xLon-1I5EZCZBgsTZsvl-ienFY2ZUr5D2FqzsiTdQS0,17347
12
+ faster_eth_abi/packed.cpython-314t-darwin.so,sha256=XPzxGhbWPD2Op6DDG8Tw-qnov3BNfeZLGkHenwfB-4c,51008
13
+ faster_eth_abi/grammar.py,sha256=unpmDhCsUs1PdLW2XbtKF5ij84nJOqVXhuKI8t_-aXk,13369
14
+ faster_eth_abi/from_type_str.cpython-314t-darwin.so,sha256=0jmdkZL_KuCijgAT09Khx-kKlMsfYzk0VMdmjnKyWSA,51080
15
+ faster_eth_abi/from_type_str.py,sha256=aAZ58YUBZuMF_DovGkthvnacAD6X6VkYFs0Zbv9JxoM,4311
16
+ faster_eth_abi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ faster_eth_abi/abi.py,sha256=HzkXy0EjHraNbbC5l-EhVqVcx5vy8tcykiKIO4Fp1xw,366
18
+ faster_eth_abi/exceptions.py,sha256=Q_b62R-E0OtlxQGLQSyx6BXkBbLf259KQ1pT5Eb1oh8,2952
19
+ faster_eth_abi/_codec.py,sha256=xVKz8JQW51sCs2eroQBUXEe_SXduT14wRSObzhZuNjo,2461
20
+ faster_eth_abi/codec.py,sha256=KMIgLUBeutkDTsRts8Y2Ydt3V0n5bMGLd21CZvwR9ds,4437
21
+ faster_eth_abi/_codec.cpython-314t-darwin.so,sha256=K70EYWlS6rlI9--coPlHbMU2XktDbLpiCU99gSXNc6Q,51008
22
+ faster_eth_abi/constants.cpython-314t-darwin.so,sha256=jDPHvUF00NLOOyj9ntWWv79SqdqD0qfLUSGi0-tJ650,51040
23
+ faster_eth_abi/base.py,sha256=eMpUM78FhJg5wHPj6glvJRpS1AmvQ_1ks9ENwyu68hc,1188
24
+ faster_eth_abi/tools/_strategies.py,sha256=iLIjqRw7FlEEIXtnhSgtrWwbxO74dslT0EQrgE2o8I8,5960
25
+ faster_eth_abi/tools/_strategies.cpython-314t-darwin.so,sha256=eRwr7M0qGFfaBDqZvfmjd-0INS-g3MdFuIqEbkWxymQ,51072
26
+ faster_eth_abi/tools/__init__.py,sha256=trtATEmgu4ctg04qkejbODDzvDSofgcVJ3rkzMP_hQE,51
27
+ faster_eth_abi/tools/__init__.cpython-314t-darwin.so,sha256=SuDQhh9sDMc7XZxek2ndvjV_DuFOOVg1R7G7OPcgQXk,51008
28
+ faster_eth_abi/utils/numeric.cpython-314t-darwin.so,sha256=UFIqrd-RQhssxofpwJ4jd4OeY0p-ycyAqj2KisR7zJ0,51040
29
+ faster_eth_abi/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ faster_eth_abi/utils/validation.cpython-314t-darwin.so,sha256=jWjXVTOqsGddGE87CHEJG6oM367YkkfJVI920N-2l_A,51056
31
+ faster_eth_abi/utils/padding.cpython-314t-darwin.so,sha256=8NeZiSvC-K3mfXia6GwWc7BrLmcg2CTDZ8_SkPR6eXU,51040
32
+ faster_eth_abi/utils/__init__.cpython-314t-darwin.so,sha256=Ll7y5xrgG5lQmjhNwh6kdRmjB6rWFOsf2ok1P6KPBxc,51008
33
+ faster_eth_abi/utils/numeric.py,sha256=VU6Z76zvZn7rYaZMyDy1XO9A9ukKTzOrtA80jypp_LQ,2146
34
+ faster_eth_abi/utils/string.py,sha256=fjsAR2C7Xlu5bHomxx5l4rlADFtByzGTQfugMTo8TQk,436
35
+ faster_eth_abi/utils/string.cpython-314t-darwin.so,sha256=sLug1cp9xoVH_DxhmcFCH8LzCjomL3PRCe7UUBZDcs4,51024
36
+ faster_eth_abi/utils/padding.py,sha256=JBuFhdrvKWLrmmJBZ-a6pqbHWydAuiUBt2aBjCwVcVE,493
37
+ faster_eth_abi/utils/validation.py,sha256=NA2wRacYEBdkpQnZfmeDvzF-sHyy6NT2QzCFuBnYJVI,521
38
+ faster_eth_abi-5.2.6.dist-info/RECORD,,
39
+ faster_eth_abi-5.2.6.dist-info/WHEEL,sha256=26nyvDx4qlf6NyRSh1NSNrXJDCQeX0hnJ7EH1bB1egM,137
40
+ faster_eth_abi-5.2.6.dist-info/top_level.txt,sha256=5cP87jVHTOdG5bgQZ3ws5MGsnIwm_yX-WalM08iynHc,51
41
+ faster_eth_abi-5.2.6.dist-info/METADATA,sha256=ASeQJaeQE08DxXJLTBY_zMuODrA67CDt7vUB0wGAM9c,5385
42
+ faster_eth_abi-5.2.6.dist-info/licenses/LICENSE,sha256=P_zrhVa0OXK-_XuA0RF3d3gwMLXRSBkn2fWraC4CFLo,1106
@@ -0,0 +1,3 @@
1
+ c42f5c78bc058f310136__mypyc
2
+ eth_abi
3
+ faster_eth_abi
@@ -1,38 +0,0 @@
1
- a1f8aa123fabc88e2b56__mypyc.cpython-314t-darwin.so,sha256=-OjYHNrJ3FHe6dbOu6J_wyjSwPMcDVL0jKXNWRM5SzY,302288
2
- faster_eth_abi/abi.cpython-314t-darwin.so,sha256=u9JTCt22hJikAUH1pzEEWXBXqC17SryohV1Z8Sj8uoQ,50728
3
- faster_eth_abi/packed.py,sha256=qDPBjish_0h26O7xGWopnlD4pRkphFuFq4izgIqT600,301
4
- faster_eth_abi/encoding.py,sha256=Ht1g6Xa2y-npY5YrI1zjVcerf7YSZX-cYHZ6IJE5G5M,19988
5
- faster_eth_abi/registry.py,sha256=ja53ifO-YlxZa_k0jtjHYa8nAJ9LJQNc9kVthss_TYo,19667
6
- faster_eth_abi/constants.py,sha256=uJbuND1rFs_Pexuz58TKd-BJPuoA6hLqFEX6kkDS-dE,107
7
- faster_eth_abi/io.py,sha256=PjOnBChWh_-6ADkpJQONnxHVwsAfC_4bRiT6YQhlP6c,3728
8
- faster_eth_abi/__init__.py,sha256=55jGpiVbsTGNu-c_rr-wwyH3eqEv9MELSTWa4AMiKvU,205
9
- faster_eth_abi/decoding.py,sha256=xLon-1I5EZCZBgsTZsvl-ienFY2ZUr5D2FqzsiTdQS0,17347
10
- faster_eth_abi/packed.cpython-314t-darwin.so,sha256=efRZ4_l8uSjKvk2fPaobAAozBsqPJiaVrkKBhQioHZM,50736
11
- faster_eth_abi/grammar.py,sha256=9Q4niyiw8cAKXwVMlpfayPNcWkerZXM6WuWBEjx2TQ8,13335
12
- faster_eth_abi/from_type_str.cpython-314t-darwin.so,sha256=_tcRAgfq_5H2UU88jLb94bDkTCmpAGaZ1Dw0b36hElQ,50776
13
- faster_eth_abi/from_type_str.py,sha256=aAZ58YUBZuMF_DovGkthvnacAD6X6VkYFs0Zbv9JxoM,4311
14
- faster_eth_abi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- faster_eth_abi/abi.py,sha256=HzkXy0EjHraNbbC5l-EhVqVcx5vy8tcykiKIO4Fp1xw,366
16
- faster_eth_abi/exceptions.py,sha256=Q_b62R-E0OtlxQGLQSyx6BXkBbLf259KQ1pT5Eb1oh8,2952
17
- faster_eth_abi/codec.py,sha256=wjKLVR4Qb4hn2bloeEeZ4lQs7uLKoZq5c6rSTJVlCeo,5174
18
- faster_eth_abi/constants.cpython-314t-darwin.so,sha256=WkJiq86kqBw08PrGGvhfi9Bqc4VBn3z4gv1hb6vFuOI,50752
19
- faster_eth_abi/base.py,sha256=eMpUM78FhJg5wHPj6glvJRpS1AmvQ_1ks9ENwyu68hc,1188
20
- faster_eth_abi/tools/_strategies.py,sha256=iLIjqRw7FlEEIXtnhSgtrWwbxO74dslT0EQrgE2o8I8,5960
21
- faster_eth_abi/tools/_strategies.cpython-314t-darwin.so,sha256=t4wuixEyeiDud40Geh6kD6uEybth4ynBfqJvnhlhTYw,50784
22
- faster_eth_abi/tools/__init__.py,sha256=trtATEmgu4ctg04qkejbODDzvDSofgcVJ3rkzMP_hQE,51
23
- faster_eth_abi/tools/__init__.cpython-314t-darwin.so,sha256=TW6d04ub0J-zEY3aj7vI15L_g1EfDv5DxN3Q1PfB39U,50736
24
- faster_eth_abi/utils/numeric.cpython-314t-darwin.so,sha256=_DYT_dxZWz4zeTEQbnY2ZN5NQ34ZgFQrDD5_OUMHZ3A,50752
25
- faster_eth_abi/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- faster_eth_abi/utils/validation.cpython-314t-darwin.so,sha256=jW9eQzurbfA0z7IEVSZF5V0yeYHr3iDE6Lr_nznxGQE,50768
27
- faster_eth_abi/utils/padding.cpython-314t-darwin.so,sha256=PsvYsvHzv5LJY810s4Vjk2kWRA6IcmR7j-q7YRmYXqA,50752
28
- faster_eth_abi/utils/__init__.cpython-314t-darwin.so,sha256=UMqif0i39DZsvlypjMlQySag-qPO9fYwK-kyyxGYUeI,50736
29
- faster_eth_abi/utils/numeric.py,sha256=VU6Z76zvZn7rYaZMyDy1XO9A9ukKTzOrtA80jypp_LQ,2146
30
- faster_eth_abi/utils/string.py,sha256=fjsAR2C7Xlu5bHomxx5l4rlADFtByzGTQfugMTo8TQk,436
31
- faster_eth_abi/utils/string.cpython-314t-darwin.so,sha256=g7bBFuHl3nneBBjTKkhe743xyPeVdx42jefnQhPs3Us,50752
32
- faster_eth_abi/utils/padding.py,sha256=JBuFhdrvKWLrmmJBZ-a6pqbHWydAuiUBt2aBjCwVcVE,493
33
- faster_eth_abi/utils/validation.py,sha256=kqDxlcIyb55Y80FdcCYtWP1-8geCePsH3_yPTayxdM8,547
34
- faster_eth_abi-5.2.4.dist-info/RECORD,,
35
- faster_eth_abi-5.2.4.dist-info/WHEEL,sha256=26nyvDx4qlf6NyRSh1NSNrXJDCQeX0hnJ7EH1bB1egM,137
36
- faster_eth_abi-5.2.4.dist-info/top_level.txt,sha256=NbjfpQ9lBrFaSYDeeRrYo2vn3ZGVqu_9MZ0LOqjzQho,51
37
- faster_eth_abi-5.2.4.dist-info/METADATA,sha256=KuZsNosWAxgduSru00lsek6bd9H2_B4PFGX1cPA-o-A,4129
38
- faster_eth_abi-5.2.4.dist-info/licenses/LICENSE,sha256=P_zrhVa0OXK-_XuA0RF3d3gwMLXRSBkn2fWraC4CFLo,1106
@@ -1,3 +0,0 @@
1
- a1f8aa123fabc88e2b56__mypyc
2
- eth_abi
3
- faster_eth_abi