From 4e8b444d4acec69ca37229dfbe6a0344c6f82b39 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Thu, 16 Oct 2025 08:27:21 +0000 Subject: [PATCH 1/7] feat: compile exceptions --- faster_web3/exceptions.py | 62 +++++++++++++++++++++++++++++++++------ setup.py | 1 + 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/faster_web3/exceptions.py b/faster_web3/exceptions.py index 054ec98324..89a2b2f1dd 100644 --- a/faster_web3/exceptions.py +++ b/faster_web3/exceptions.py @@ -4,8 +4,10 @@ TYPE_CHECKING, Any, Dict, + Final, Optional, Union, + final, ) from faster_web3.types import ( @@ -31,7 +33,7 @@ class Web3Exception(Exception): # deal with other exceptions """ - user_message: Optional[str] = None + user_message: Final[Optional[str]] def __init__( self, @@ -44,6 +46,7 @@ def __init__( self.user_message = user_message +@final class Web3AssertionError(Web3Exception, AssertionError): """ A web3.py exception wrapper for `AssertionError`, for better control over @@ -58,6 +61,7 @@ class Web3ValueError(Web3Exception, ValueError): """ +@final class Web3AttributeError(Web3Exception, AttributeError): """ A web3.py exception wrapper for `AttributeError`, for better control over @@ -65,6 +69,7 @@ class Web3AttributeError(Web3Exception, AttributeError): """ +@final class Web3TypeError(Web3Exception, TypeError): """ A web3.py exception wrapper for `TypeError`, for better control over @@ -72,12 +77,14 @@ class Web3TypeError(Web3Exception, TypeError): """ +@final class MethodNotSupported(Web3Exception): """ Raised when a method is not supported by the provider. """ +@final class BadFunctionCallOutput(Web3Exception): """ We failed to decode ABI output. @@ -86,18 +93,21 @@ class BadFunctionCallOutput(Web3Exception): """ +@final class BlockNumberOutOfRange(Web3Exception): """ block_identifier passed does not match known block. """ +@final class ProviderConnectionError(Web3Exception): """ Raised when unable to connect to a provider """ +@final class CannotHandleRequest(Web3Exception): """ Raised by a provider to signal that it cannot handle an RPC request and @@ -105,12 +115,14 @@ class CannotHandleRequest(Web3Exception): """ +@final class TooManyRequests(Web3Exception): """ Raised by a provider to signal that too many requests have been made consecutively. """ +@final class MultipleFailedRequests(Web3Exception): """ Raised by a provider to signal that multiple requests to retrieve the same @@ -118,12 +130,14 @@ class MultipleFailedRequests(Web3Exception): """ +@final class InvalidAddress(Web3Exception): """ The supplied address does not have a valid checksum, as defined in EIP-55 """ +@final class NameNotFound(Web3Exception): """ Raised when a caller provides an Ethereum Name Service name that @@ -131,6 +145,7 @@ class NameNotFound(Web3Exception): """ +@final class StaleBlockchain(Web3Exception): """ Raised by the stalecheck_middleware when the latest block is too old. @@ -153,6 +168,7 @@ def __str__(self) -> str: return self.args[0] +@final class MismatchedABI(Web3Exception): """ Raised when an ABI does not match with supplied parameters, or when an @@ -160,6 +176,7 @@ class MismatchedABI(Web3Exception): """ +@final class ABIEventNotFound(AttributeError, MismatchedABI): """ Raised when an attempt is made to access an event @@ -167,6 +184,7 @@ class ABIEventNotFound(AttributeError, MismatchedABI): """ +@final class ABIFunctionNotFound(AttributeError, MismatchedABI): """ Raised when an attempt is made to access a function @@ -174,18 +192,21 @@ class ABIFunctionNotFound(AttributeError, MismatchedABI): """ +@final class ABIConstructorNotFound(Web3Exception): """ Raised when a constructor function doesn't exist in contract. """ +@final class ABIFallbackNotFound(Web3Exception): """ Raised when a fallback function doesn't exist in contract. """ +@final class ABIReceiveNotFound(Web3Exception): """ Raised when a receive function doesn't exist in contract. @@ -198,30 +219,35 @@ class Web3ValidationError(Web3Exception): """ +@final class ExtraDataLengthError(Web3ValidationError): """ Raised when an RPC call returns >32 bytes of extraData. """ +@final class NoABIFunctionsFound(Web3Exception): """ Raised when an ABI is present, but doesn't contain any functions. """ +@final class NoABIFound(Web3Exception): """ Raised when no ABI is present. """ +@final class NoABIEventsFound(Web3Exception): """ Raised when an ABI doesn't contain any events. """ +@final class InsufficientData(Web3Exception): """ Raised when there are insufficient data points to @@ -229,6 +255,7 @@ class InsufficientData(Web3Exception): """ +@final class TimeExhausted(Web3Exception): """ Raised when a method has not retrieved the desired @@ -236,18 +263,21 @@ class TimeExhausted(Web3Exception): """ +@final class InfuraProjectIdNotFound(Web3Exception): """ Raised when there is no Infura Project Id set. """ +@final class LogTopicError(Web3Exception): """ Raised when the number of log topics is mismatched. """ +@final class InvalidEventABI(Web3Exception): """ Raised when the event ABI is invalid. @@ -265,30 +295,33 @@ def __init__( data: Optional[Union[str, Dict[str, str]]] = None, ): super().__init__(message, data) - self.message = message - self.data = data + self.message: Final = message + self.data: Final = data +@final class ContractCustomError(ContractLogicError): """ Raised on a contract revert custom error """ +@final class ContractPanicError(ContractLogicError): """ Raised when a contract reverts with Panic, as of Solidity 0.8.0 """ +@final class OffchainLookup(ContractLogicError): """ Raised when a contract reverts with OffchainLookup as described in EIP-3668 """ def __init__(self, payload: Dict[str, Any], data: Optional[str] = None) -> None: - self.payload = payload - self.data = data + self.payload: Final = payload + self.data: Final = data super().__init__(data=data) @@ -301,6 +334,7 @@ def __init__(self, message: str) -> None: super().__init__(message) +@final class TransactionTypeMismatch(InvalidTransaction): """ Raised when legacy transaction values are used alongside dynamic @@ -312,6 +346,7 @@ def __init__(self) -> None: super().__init__(message) +@final class BadResponseFormat(Web3Exception): """ Raised when a JSON-RPC response comes back in an unexpected format @@ -327,10 +362,10 @@ class TaskNotRunning(Web3Exception): def __init__( self, task: "asyncio.Task[Any]", message: Optional[str] = None ) -> None: - self.task = task + self.task: Final = task if message is None: message = f"Task {task} is not running." - self.message = message + self.message: Final = message super().__init__(message) @@ -340,6 +375,7 @@ class PersistentConnectionError(Web3Exception): """ +@final class ReadBufferLimitReached(PersistentConnectionError, Web3ValueError): """ Raised when the read buffer limit is reached while reading data from a persistent @@ -347,12 +383,14 @@ class ReadBufferLimitReached(PersistentConnectionError, Web3ValueError): """ +@final class PersistentConnectionClosedOK(PersistentConnectionError): """ Raised when a persistent connection is closed gracefully by the server. """ +@final class SubscriptionProcessingFinished(PersistentConnectionError): """ Raised to alert the subscription manager that the processing of subscriptions @@ -360,6 +398,7 @@ class SubscriptionProcessingFinished(PersistentConnectionError): """ +@final class SubscriptionHandlerTaskException(TaskNotRunning): """ Raised to alert the subscription manager that an exception occurred in the @@ -388,28 +427,32 @@ def __init__( message, user_message=user_message, ) - self.message = message - self.rpc_response = rpc_response + self.message: Final = message + self.rpc_response: Final = rpc_response +@final class MethodUnavailable(Web3RPCError): """ Raised when the method is not available on the node """ +@final class RequestTimedOut(Web3RPCError): """ Raised when a request to the node times out. """ +@final class TransactionNotFound(Web3RPCError): """ Raised when a tx hash used to look up a tx in a jsonrpc call cannot be found. """ +@final class TransactionIndexingInProgress(Web3RPCError): """ Raised when a transaction receipt is not yet available due to transaction indexing @@ -417,6 +460,7 @@ class TransactionIndexingInProgress(Web3RPCError): """ +@final class BlockNotFound(Web3RPCError): """ Raised when the block id used to look up a block in a jsonrpc call cannot be found. diff --git a/setup.py b/setup.py index 32021b698e..ae56e16c79 100644 --- a/setup.py +++ b/setup.py @@ -97,6 +97,7 @@ "faster_web3/beacon", "faster_web3/constants.py", "faster_web3/contract/utils.py", + "faster_web3/exceptions.py", "faster_web3/gas_strategies", "faster_web3/providers/eth_tester", "faster_web3/tools/benchmark/node.py", From de49d2ccd0e819be596cc02c79f18da45e553a46 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Thu, 16 Oct 2025 08:53:56 +0000 Subject: [PATCH 2/7] fix --- faster_web3/exceptions.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/faster_web3/exceptions.py b/faster_web3/exceptions.py index 89a2b2f1dd..c8421faabb 100644 --- a/faster_web3/exceptions.py +++ b/faster_web3/exceptions.py @@ -10,6 +10,10 @@ final, ) +from mypy_extensions import ( + mypyc_attr, +) + from faster_web3.types import ( BlockData, RPCResponse, @@ -19,6 +23,7 @@ import asyncio +@mypyc_attr(allow_interpreted_subclasses=True) class Web3Exception(Exception): """ Exception mixin inherited by all exceptions of web3.py @@ -47,6 +52,7 @@ def __init__( @final +@mypyc_attr(native_class=False) class Web3AssertionError(Web3Exception, AssertionError): """ A web3.py exception wrapper for `AssertionError`, for better control over @@ -62,6 +68,7 @@ class Web3ValueError(Web3Exception, ValueError): @final +@mypyc_attr(native_class=False) class Web3AttributeError(Web3Exception, AttributeError): """ A web3.py exception wrapper for `AttributeError`, for better control over @@ -70,6 +77,7 @@ class Web3AttributeError(Web3Exception, AttributeError): @final +@mypyc_attr(native_class=False) class Web3TypeError(Web3Exception, TypeError): """ A web3.py exception wrapper for `TypeError`, for better control over @@ -169,6 +177,7 @@ def __str__(self) -> str: @final +@mypyc_attr(allow_interpreted_subclasses=True) class MismatchedABI(Web3Exception): """ Raised when an ABI does not match with supplied parameters, or when an @@ -177,6 +186,7 @@ class MismatchedABI(Web3Exception): @final +@mypyc_attr(native_class=False) class ABIEventNotFound(AttributeError, MismatchedABI): """ Raised when an attempt is made to access an event @@ -185,6 +195,7 @@ class ABIEventNotFound(AttributeError, MismatchedABI): @final +@mypyc_attr(native_class=False) class ABIFunctionNotFound(AttributeError, MismatchedABI): """ Raised when an attempt is made to access a function From 107aa348813555b80d10bfdec84448d04a003319 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Thu, 16 Oct 2025 09:03:55 +0000 Subject: [PATCH 3/7] fix --- faster_web3/exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/faster_web3/exceptions.py b/faster_web3/exceptions.py index c8421faabb..1a5a436267 100644 --- a/faster_web3/exceptions.py +++ b/faster_web3/exceptions.py @@ -23,7 +23,7 @@ import asyncio -@mypyc_attr(allow_interpreted_subclasses=True) +@mypyc_attr(native_class=False) class Web3Exception(Exception): """ Exception mixin inherited by all exceptions of web3.py @@ -177,7 +177,7 @@ def __str__(self) -> str: @final -@mypyc_attr(allow_interpreted_subclasses=True) +@mypyc_attr(native_class=False) class MismatchedABI(Web3Exception): """ Raised when an ABI does not match with supplied parameters, or when an From e77743caa273b2cee3b2b95116fe05e11fe891da Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Thu, 16 Oct 2025 09:08:12 +0000 Subject: [PATCH 4/7] fix --- faster_web3/exceptions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/faster_web3/exceptions.py b/faster_web3/exceptions.py index 1a5a436267..91a2029385 100644 --- a/faster_web3/exceptions.py +++ b/faster_web3/exceptions.py @@ -387,6 +387,7 @@ class PersistentConnectionError(Web3Exception): @final +@mypyc_attr(native_class=False) class ReadBufferLimitReached(PersistentConnectionError, Web3ValueError): """ Raised when the read buffer limit is reached while reading data from a persistent From 52fffe004630611a602047add17360051423cb77 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Thu, 16 Oct 2025 09:13:19 +0000 Subject: [PATCH 5/7] fix --- faster_web3/exceptions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/faster_web3/exceptions.py b/faster_web3/exceptions.py index 91a2029385..1ca33c67ea 100644 --- a/faster_web3/exceptions.py +++ b/faster_web3/exceptions.py @@ -380,6 +380,7 @@ def __init__( super().__init__(message) +@mypyc_attr(native_class=False) class PersistentConnectionError(Web3Exception): """ Raised when a persistent connection encounters an error. From 8f08038e64f2355755f08ca7af791548e59e3796 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Thu, 16 Oct 2025 09:17:48 +0000 Subject: [PATCH 6/7] fix --- faster_web3/exceptions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/faster_web3/exceptions.py b/faster_web3/exceptions.py index 1ca33c67ea..0d5a07ce32 100644 --- a/faster_web3/exceptions.py +++ b/faster_web3/exceptions.py @@ -60,6 +60,7 @@ class Web3AssertionError(Web3Exception, AssertionError): """ +@mypyc_attr(native_class=False) class Web3ValueError(Web3Exception, ValueError): """ A web3.py exception wrapper for `ValueError`, for better control over From 9293957f0cf7db0b5aa2b5ce243c65345f7a2da4 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Thu, 16 Oct 2025 09:20:11 +0000 Subject: [PATCH 7/7] fix --- faster_web3/exceptions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/faster_web3/exceptions.py b/faster_web3/exceptions.py index 0d5a07ce32..4a875a5245 100644 --- a/faster_web3/exceptions.py +++ b/faster_web3/exceptions.py @@ -398,6 +398,7 @@ class ReadBufferLimitReached(PersistentConnectionError, Web3ValueError): @final +@mypyc_attr(native_class=False) class PersistentConnectionClosedOK(PersistentConnectionError): """ Raised when a persistent connection is closed gracefully by the server. @@ -405,6 +406,7 @@ class PersistentConnectionClosedOK(PersistentConnectionError): @final +@mypyc_attr(native_class=False) class SubscriptionProcessingFinished(PersistentConnectionError): """ Raised to alert the subscription manager that the processing of subscriptions