Skip to content

Commit 4b85a4d

Browse files
committed
feat: compile events utils
1 parent d9ef7f5 commit 4b85a4d

File tree

2 files changed

+52
-58
lines changed

2 files changed

+52
-58
lines changed

faster_web3/_utils/events.py

Lines changed: 51 additions & 58 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,
@@ -152,8 +153,7 @@ def construct_event_topic_set(
152153
for arg, arg_options in zipped_abi_and_args
153154
]
154155

155-
topics = list(normalize_topic_list([event_topic] + encoded_args))
156-
return topics
156+
return list(normalize_topic_list([event_topic] + encoded_args))
157157

158158

159159
def construct_event_data_set(
@@ -196,19 +196,17 @@ def construct_event_data_set(
196196
for arg, arg_options in zipped_abi_and_args
197197
]
198198

199-
data = [
199+
return [
200200
list(permutation) if any(value is not None for value in permutation) else []
201201
for permutation in itertools.product(*encoded_args)
202202
]
203-
return data
204203

205204

206205
def is_dynamic_sized_type(type_str: TypeStr) -> bool:
207206
abi_type = grammar.parse(type_str)
208207
return abi_type.is_dynamic
209208

210209

211-
@to_tuple
212210
def get_event_abi_types_for_decoding(
213211
event_inputs: Sequence[Union[ABIComponent, ABIComponentIndexed]],
214212
) -> Iterable[TypeStr]:
@@ -217,11 +215,14 @@ def get_event_abi_types_for_decoding(
217215
`string`. Because of this we need to modify the types so that we can
218216
decode the log entries using the correct types.
219217
"""
220-
for input_abi in event_inputs:
221-
if input_abi.get("indexed") and is_dynamic_sized_type(input_abi["type"]):
222-
yield "bytes32"
223-
else:
224-
yield collapse_if_tuple(input_abi)
218+
return tuple(
219+
(
220+
"bytes32"
221+
if input_abi.get("indexed") and is_dynamic_sized_type(input_abi["type"])
222+
else collapse_if_tuple(input_abi)
223+
)
224+
for input_abi in event_inputs
225+
)
225226

226227

227228
@curry
@@ -258,8 +259,7 @@ def get_event_data(
258259

259260
# sanity check that there are not name intersections between the topic
260261
# names and the data argument names.
261-
duplicate_names = set(log_topic_names).intersection(log_data_names)
262-
if duplicate_names:
262+
if duplicate_names := set(log_topic_names).intersection(log_data_names):
263263
raise InvalidEventABI(
264264
"The following argument names are duplicated "
265265
f"between event inputs: '{', '.join(duplicate_names)}'"
@@ -283,10 +283,8 @@ def get_event_data(
283283
)
284284

285285
event_args = dict(
286-
itertools.chain(
287-
zip(log_topic_names, normalized_topic_data),
288-
named_log_data.items(),
289-
)
286+
zip(log_topic_names, normalized_topic_data),
287+
**named_log_data,
290288
)
291289

292290
event_data = EventData(
@@ -306,9 +304,8 @@ def get_event_data(
306304
return event_data
307305

308306

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

313310

314311
@curry
@@ -321,7 +318,7 @@ def remove_trailing_from_seq(
321318
return seq[:index]
322319

323320

324-
normalize_topic_list = compose(
321+
normalize_topic_list: Final = compose(
325322
remove_trailing_from_seq(remove_value=None),
326323
pop_singlets,
327324
)
@@ -331,30 +328,30 @@ def is_indexed(arg: Any) -> TypeGuard["TopicArgumentFilter"]:
331328
return isinstance(arg, TopicArgumentFilter)
332329

333330

334-
is_not_indexed = complement(is_indexed)
331+
is_not_indexed: Final = complement(is_indexed)
335332

336333

337334
class BaseEventFilterBuilder:
338-
formatter = None
339-
_from_block = None
340-
_to_block = None
341-
_address = None
342-
_immutable = False
343335

344336
def __init__(
345337
self,
346338
event_abi: ABIEvent,
347339
abi_codec: ABICodec,
348340
formatter: Optional[EventData] = None,
349341
) -> None:
350-
self.event_abi = event_abi
351-
self.abi_codec = abi_codec
352-
self.formatter = formatter
353-
self.event_topic = initialize_event_topics(self.event_abi)
354-
self.args = AttributeDict(
342+
self.event_abi: Final = event_abi
343+
self.abi_codec: Final = abi_codec
344+
self.formatter: Final = formatter
345+
self.event_topic: Final = initialize_event_topics(self.event_abi)
346+
self.args: Final = AttributeDict(
355347
_build_argument_filters_from_event_abi(event_abi, abi_codec)
356348
)
357-
self._ordered_arg_names = tuple(arg["name"] for arg in event_abi["inputs"])
349+
self._ordered_arg_names: Final = tuple(arg["name"] for arg in event_abi["inputs"])
350+
351+
self._from_block: Optional[BlockIdentifier] = None
352+
self._to_block: Optional[BlockIdentifier] = None
353+
self._address: Optional[ChecksumAddress] = None
354+
self._immutable: bool = False
358355

359356
@property
360357
def from_block(self) -> BlockIdentifier:
@@ -403,12 +400,10 @@ def ordered_args(self) -> Tuple[Any, ...]:
403400
return tuple(map(self.args.__getitem__, self._ordered_arg_names))
404401

405402
@property
406-
@to_tuple
407403
def indexed_args(self) -> Tuple[Any, ...]:
408404
return tuple(filter(is_indexed, self.ordered_args))
409405

410406
@property
411-
@to_tuple
412407
def data_args(self) -> Tuple[Any, ...]:
413408
return tuple(filter(is_not_indexed, self.ordered_args))
414409

@@ -432,9 +427,10 @@ def filter_params(self) -> FilterParams:
432427
"toBlock": self.to_block,
433428
"address": self.address,
434429
}
435-
return valfilter(lambda x: x is not None, params)
430+
return {k: v for k, v in params.items() if v is not None}
436431

437432

433+
@final
438434
class EventFilterBuilder(BaseEventFilterBuilder):
439435
def deploy(self, w3: "Web3") -> "LogFilter":
440436
if not isinstance(w3, faster_web3.Web3):
@@ -453,6 +449,7 @@ def deploy(self, w3: "Web3") -> "LogFilter":
453449
return log_filter
454450

455451

452+
@final
456453
class AsyncEventFilterBuilder(BaseEventFilterBuilder):
457454
async def deploy(self, async_w3: "AsyncWeb3[Any]") -> "AsyncLogFilter":
458455
if not isinstance(async_w3, faster_web3.AsyncWeb3):
@@ -476,7 +473,7 @@ def initialize_event_topics(event_abi: ABIEvent) -> Union[bytes, List[Any]]:
476473
if event_abi["anonymous"] is False:
477474
return event_abi_to_log_topic(event_abi)
478475
else:
479-
return list()
476+
return []
480477

481478

482479
@to_dict
@@ -495,21 +492,18 @@ def _build_argument_filters_from_event_abi(
495492
yield key, value
496493

497494

498-
array_to_tuple = apply_formatter_if(is_list_like, tuple)
495+
array_to_tuple: Final = apply_formatter_if(is_list_like, tuple)
499496

500497

501-
@to_tuple
502498
def _normalize_match_values(match_values: Collection[Any]) -> Iterable[Any]:
503-
for value in match_values:
504-
yield array_to_tuple(value)
499+
return tuple(map(array_to_tuple, match_values))
505500

506501

507502
class BaseArgumentFilter(ABC):
508-
_match_values: Optional[Tuple[Any, ...]] = None
509-
_immutable = False
510-
511503
def __init__(self, arg_type: TypeStr) -> None:
512-
self.arg_type = arg_type
504+
self.arg_type: Final = arg_type
505+
self._match_values: Optional[Tuple[Any, ...]] = None
506+
self._immutable = False
513507

514508
def match_single(self, value: Any) -> None:
515509
if self._immutable:
@@ -537,29 +531,27 @@ def match_values(self) -> None:
537531
pass
538532

539533

534+
@final
540535
class DataArgumentFilter(BaseArgumentFilter):
541536
# type ignore b/c conflict with BaseArgumentFilter.match_values type
542537
@property
543538
def match_values(self) -> Tuple[TypeStr, Tuple[Any, ...]]: # type: ignore
544539
return self.arg_type, self._match_values
545540

546541

542+
@final
547543
class TopicArgumentFilter(BaseArgumentFilter):
548544
def __init__(self, arg_type: TypeStr, abi_codec: ABICodec) -> None:
549-
self.abi_codec = abi_codec
550-
self.arg_type = arg_type
545+
super().__init__(arg_type)
546+
self.abi_codec: Final = abi_codec
551547

552-
@to_tuple
553548
def _get_match_values(self) -> Iterable[HexStr]:
554-
yield from (self._encode(value) for value in self._match_values)
549+
return tuple(map(self._encode, cast(Tuple[Any, ...], self._match_values)))
555550

556551
# type ignore b/c conflict with BaseArgumentFilter.match_values type
557552
@property
558553
def match_values(self) -> Optional[Tuple[HexStr, ...]]: # type: ignore
559-
if self._match_values is not None:
560-
return self._get_match_values()
561-
else:
562-
return None
554+
return self._get_match_values() if self._match_values is not None else None
563555

564556
def _encode(self, value: Any) -> HexStr:
565557
if is_dynamic_sized_type(self.arg_type):
@@ -568,12 +560,13 @@ def _encode(self, value: Any) -> HexStr:
568560
return to_hex(self.abi_codec.encode([self.arg_type], [value]))
569561

570562

563+
@final
571564
class EventLogErrorFlags(Enum):
572-
Discard = "discard"
573-
Ignore = "ignore"
574-
Strict = "strict"
575-
Warn = "warn"
565+
Discard: Final = "discard"
566+
Ignore: Final = "ignore"
567+
Strict: Final = "strict"
568+
Warn: Final = "warn"
576569

577570
@classmethod
578-
def flag_options(self) -> List[str]:
579-
return [key.upper() for key in self.__members__.keys()]
571+
def flag_options(cls) -> List[str]:
572+
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)