Skip to content

Commit 1ce53ce

Browse files
committed
feat: compile events utils
1 parent dcad374 commit 1ce53ce

File tree

2 files changed

+53
-61
lines changed

2 files changed

+53
-61
lines changed

faster_web3/_utils/events.py

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
Any,
1212
Collection,
1313
Dict,
14+
Final,
1415
Iterable,
1516
List,
1617
Optional,
1718
Sequence,
1819
Tuple,
1920
Union,
2021
cast,
22+
final,
2123
)
2224

2325
from faster_eth_abi import (
@@ -42,7 +44,6 @@
4244
to_bytes,
4345
to_dict,
4446
to_hex,
45-
to_tuple,
4647
)
4748
from faster_eth_utils.abi import (
4849
collapse_if_tuple,
@@ -149,8 +150,7 @@ def construct_event_topic_set(
149150
for arg, arg_options in zipped_abi_and_args
150151
]
151152

152-
topics = list(normalize_topic_list([event_topic] + encoded_args))
153-
return topics
153+
return list(normalize_topic_list([event_topic] + encoded_args))
154154

155155

156156
def construct_event_data_set(
@@ -193,19 +193,17 @@ def construct_event_data_set(
193193
for arg, arg_options in zipped_abi_and_args
194194
]
195195

196-
data = [
196+
return [
197197
list(permutation) if any(value is not None for value in permutation) else []
198198
for permutation in itertools.product(*encoded_args)
199199
]
200-
return data
201200

202201

203202
def is_dynamic_sized_type(type_str: TypeStr) -> bool:
204203
abi_type = grammar.parse(type_str)
205204
return abi_type.is_dynamic
206205

207206

208-
@to_tuple
209207
def get_event_abi_types_for_decoding(
210208
event_inputs: Sequence[Union[ABIComponent, ABIComponentIndexed]],
211209
) -> Iterable[TypeStr]:
@@ -214,11 +212,14 @@ def get_event_abi_types_for_decoding(
214212
`string`. Because of this we need to modify the types so that we can
215213
decode the log entries using the correct types.
216214
"""
217-
for input_abi in event_inputs:
218-
if input_abi.get("indexed") and is_dynamic_sized_type(input_abi["type"]):
219-
yield "bytes32"
220-
else:
221-
yield collapse_if_tuple(input_abi)
215+
return tuple(
216+
(
217+
"bytes32"
218+
if input_abi.get("indexed") and is_dynamic_sized_type(input_abi["type"])
219+
else collapse_if_tuple(input_abi)
220+
)
221+
for input_abi in event_inputs
222+
)
222223

223224

224225
@curry
@@ -255,8 +256,7 @@ def get_event_data(
255256

256257
# sanity check that there are not name intersections between the topic
257258
# names and the data argument names.
258-
duplicate_names = set(log_topic_names).intersection(log_data_names)
259-
if duplicate_names:
259+
if duplicate_names := set(log_topic_names).intersection(log_data_names):
260260
raise InvalidEventABI(
261261
"The following argument names are duplicated "
262262
f"between event inputs: '{', '.join(duplicate_names)}'"
@@ -280,10 +280,8 @@ def get_event_data(
280280
)
281281

282282
event_args = dict(
283-
itertools.chain(
284-
zip(log_topic_names, normalized_topic_data),
285-
named_log_data.items(),
286-
)
283+
zip(log_topic_names, normalized_topic_data),
284+
**named_log_data,
287285
)
288286

289287
event_data = EventData(
@@ -303,9 +301,8 @@ def get_event_data(
303301
return event_data
304302

305303

306-
@to_tuple
307304
def pop_singlets(seq: Sequence[Any]) -> Iterable[Any]:
308-
yield from (i[0] if is_list_like(i) and len(i) == 1 else i for i in seq)
305+
return tuple(i[0] if is_list_like(i) and len(i) == 1 else i for i in seq)
309306

310307

311308
@curry
@@ -318,42 +315,40 @@ def remove_trailing_from_seq(
318315
return seq[:index]
319316

320317

321-
normalize_topic_list = compose(
318+
normalize_topic_list: Final = compose(
322319
remove_trailing_from_seq(remove_value=None),
323320
pop_singlets,
324321
)
325322

326323

327324
def is_indexed(arg: Any) -> bool:
328-
if isinstance(arg, TopicArgumentFilter):
329-
return True
330-
return False
325+
return isinstance(arg, TopicArgumentFilter)
331326

332327

333-
is_not_indexed = complement(is_indexed)
328+
is_not_indexed: Final = complement(is_indexed)
334329

335330

336331
class BaseEventFilterBuilder:
337-
formatter = None
338-
_from_block = None
339-
_to_block = None
340-
_address = None
341-
_immutable = False
342332

343333
def __init__(
344334
self,
345335
event_abi: ABIEvent,
346336
abi_codec: ABICodec,
347337
formatter: Optional[EventData] = None,
348338
) -> None:
349-
self.event_abi = event_abi
350-
self.abi_codec = abi_codec
351-
self.formatter = formatter
352-
self.event_topic = initialize_event_topics(self.event_abi)
353-
self.args = AttributeDict(
339+
self.event_abi: Final = event_abi
340+
self.abi_codec: Final = abi_codec
341+
self.formatter: Final = formatter
342+
self.event_topic: Final = initialize_event_topics(self.event_abi)
343+
self.args: Final = AttributeDict(
354344
_build_argument_filters_from_event_abi(event_abi, abi_codec)
355345
)
356-
self._ordered_arg_names = tuple(arg["name"] for arg in event_abi["inputs"])
346+
self._ordered_arg_names: Final = tuple(arg["name"] for arg in event_abi["inputs"])
347+
348+
self._from_block: Optional[BlockIdentifier] = None
349+
self._to_block: Optional[BlockIdentifier] = None
350+
self._address: Optional[ChecksumAddress] = None
351+
self._immutable: bool = False
357352

358353
@property
359354
def from_block(self) -> BlockIdentifier:
@@ -402,12 +397,10 @@ def ordered_args(self) -> Tuple[Any, ...]:
402397
return tuple(map(self.args.__getitem__, self._ordered_arg_names))
403398

404399
@property
405-
@to_tuple
406400
def indexed_args(self) -> Tuple[Any, ...]:
407401
return tuple(filter(is_indexed, self.ordered_args))
408402

409403
@property
410-
@to_tuple
411404
def data_args(self) -> Tuple[Any, ...]:
412405
return tuple(filter(is_not_indexed, self.ordered_args))
413406

@@ -431,9 +424,10 @@ def filter_params(self) -> FilterParams:
431424
"toBlock": self.to_block,
432425
"address": self.address,
433426
}
434-
return valfilter(lambda x: x is not None, params)
427+
return {k: v for k, v in params.items() if v is not None}
435428

436429

430+
@final
437431
class EventFilterBuilder(BaseEventFilterBuilder):
438432
def deploy(self, w3: "Web3") -> "LogFilter":
439433
if not isinstance(w3, faster_web3.Web3):
@@ -452,6 +446,7 @@ def deploy(self, w3: "Web3") -> "LogFilter":
452446
return log_filter
453447

454448

449+
@final
455450
class AsyncEventFilterBuilder(BaseEventFilterBuilder):
456451
async def deploy(self, async_w3: "AsyncWeb3") -> "AsyncLogFilter":
457452
if not isinstance(async_w3, faster_web3.AsyncWeb3):
@@ -475,7 +470,7 @@ def initialize_event_topics(event_abi: ABIEvent) -> Union[bytes, List[Any]]:
475470
if event_abi["anonymous"] is False:
476471
return event_abi_to_log_topic(event_abi)
477472
else:
478-
return list()
473+
return []
479474

480475

481476
@to_dict
@@ -494,21 +489,18 @@ def _build_argument_filters_from_event_abi(
494489
yield key, value
495490

496491

497-
array_to_tuple = apply_formatter_if(is_list_like, tuple)
492+
array_to_tuple: Final = apply_formatter_if(is_list_like, tuple)
498493

499494

500-
@to_tuple
501495
def _normalize_match_values(match_values: Collection[Any]) -> Iterable[Any]:
502-
for value in match_values:
503-
yield array_to_tuple(value)
496+
return tuple(map(array_to_tuple, match_values))
504497

505498

506499
class BaseArgumentFilter(ABC):
507-
_match_values: Optional[Tuple[Any, ...]] = None
508-
_immutable = False
509-
510500
def __init__(self, arg_type: TypeStr) -> None:
511-
self.arg_type = arg_type
501+
self.arg_type: Final = arg_type
502+
self._match_values: Optional[Tuple[Any, ...]] = None
503+
self._immutable = False
512504

513505
def match_single(self, value: Any) -> None:
514506
if self._immutable:
@@ -536,29 +528,27 @@ def match_values(self) -> None:
536528
pass
537529

538530

531+
@final
539532
class DataArgumentFilter(BaseArgumentFilter):
540533
# type ignore b/c conflict with BaseArgumentFilter.match_values type
541534
@property
542535
def match_values(self) -> Tuple[TypeStr, Tuple[Any, ...]]: # type: ignore
543536
return self.arg_type, self._match_values
544537

545538

539+
@final
546540
class TopicArgumentFilter(BaseArgumentFilter):
547541
def __init__(self, arg_type: TypeStr, abi_codec: ABICodec) -> None:
548-
self.abi_codec = abi_codec
549-
self.arg_type = arg_type
542+
super().__init__(arg_type)
543+
self.abi_codec: Final = abi_codec
550544

551-
@to_tuple
552545
def _get_match_values(self) -> Iterable[HexStr]:
553-
yield from (self._encode(value) for value in self._match_values)
546+
return tuple(map(self._encode, cast(Tuple[Any, ...], self._match_values)))
554547

555548
# type ignore b/c conflict with BaseArgumentFilter.match_values type
556549
@property
557550
def match_values(self) -> Optional[Tuple[HexStr, ...]]: # type: ignore
558-
if self._match_values is not None:
559-
return self._get_match_values()
560-
else:
561-
return None
551+
return self._get_match_values() if self._match_values is not None else None
562552

563553
def _encode(self, value: Any) -> HexStr:
564554
if is_dynamic_sized_type(self.arg_type):
@@ -567,12 +557,13 @@ def _encode(self, value: Any) -> HexStr:
567557
return to_hex(self.abi_codec.encode([self.arg_type], [value]))
568558

569559

560+
@final
570561
class EventLogErrorFlags(Enum):
571-
Discard = "discard"
572-
Ignore = "ignore"
573-
Strict = "strict"
574-
Warn = "warn"
562+
Discard: Final = "discard"
563+
Ignore: Final = "ignore"
564+
Strict: Final = "strict"
565+
Warn: Final = "warn"
575566

576567
@classmethod
577-
def flag_options(self) -> List[str]:
578-
return [key.upper() for key in self.__members__.keys()]
568+
def flag_options(cls) -> List[str]:
569+
return [key.upper() for key in cls.__members__.keys()]

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"faster_web3/_utils/decorators.py",
8585
"faster_web3/_utils/encoding.py",
8686
"faster_web3/_utils/error_formatters_utils.py",
87+
"faster_web3/_utils/events.py",
8788
"faster_web3/_utils/fee_utils.py",
8889
"faster_web3/_utils/formatters.py",
8990
"faster_web3/_utils/http.py",

0 commit comments

Comments
 (0)