-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Closed
Description
What happened?
Summary
The documented example from Web3.py (link) which looks like this:
from aiohttp import ClientSession
from web3 import AsyncWeb3, AsyncHTTPProvider
async def bug() -> None:
w3 = AsyncWeb3(AsyncHTTPProvider(endpoint_uri))
custom_session = ClientSession()
await w3.provider.cache_async_session(custom_session)
w3.provider.disconnect()Causes type checkers like mypy, pyright and ty to throw an error along these lines:
error[unresolved-attribute]: Type `AsyncBaseProvider` has no attribute `cache_async_session`
--> src/silly_test.py:10:11
|
8 | # If you want to pass in your own session:
9 | custom_session = ClientSession()
10 | await w3.provider.cache_async_session(custom_session) # This method is an async method so it needs to be handled accordingly
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11 | # when you're finished, disconnect:
12 | w3.provider.disconnect()
|
info: rule `unresolved-attribute` is enabled by default
Fill this section in if you know how this could or should be fixed
The AsyncWeb3.provider property is annotated to return an instance of AsyncBaseProvider. The issue is that AsyncBaseProvider doesn't have a cache_async_session attribute or method.
While the AsyncHTTPProvider subclass does have a cache_async_session method, the type annotations don't provide enough information for the type checker to know that w3.provider is an instance of AsyncHTTPProvider instead of the more general AsyncBaseProvider.
To fix this, you could try making the AsyncWeb3 class generic. The following approach might resolve the issue, but you will need to test it:
diff --git a/web3/main.py b/web3/main.py
index b388f95b..35286871 100644
--- a/web3/main.py
+++ b/web3/main.py
@@ -43,6 +43,8 @@ from typing import (
Type,
Union,
cast,
+ Generic,
+ TypeVar,
)
from eth_typing import (
@@ -447,7 +449,10 @@ class Web3(BaseWeb3):
# -- async -- #
-class AsyncWeb3(BaseWeb3):
+T = TypeVar("T", bound=AsyncBaseProvider)
+
+
+class AsyncWeb3(BaseWeb3, Generic[T]):
# mypy Types
eth: AsyncEth
net: AsyncNet
@@ -460,7 +465,7 @@ class AsyncWeb3(BaseWeb3):
def __init__(
self,
- provider: Optional[AsyncBaseProvider] = None,
+ provider: Optional[T] = None,
middleware: Optional[Sequence[Any]] = None,
modules: Optional[Dict[str, Union[Type[Module], Sequence[Any]]]] = None,
external_modules: Optional[
@@ -486,11 +491,11 @@ class AsyncWeb3(BaseWeb3):
return await self.provider.is_connected(show_traceback)
@property
- def provider(self) -> AsyncBaseProvider:
- return cast(AsyncBaseProvider, self.manager.provider)
+ def provider(self) -> T:
+ return cast(T, self.manager.provider)
@provider.setter
- def provider(self, provider: AsyncBaseProvider) -> None:
+ def provider(self, provider: T) -> None:
self.manager.provider = providerweb3 Version
7.13.0
Python Version
3.12
Operating System
ubuntu 24
Metadata
Metadata
Assignees
Labels
No labels