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