Skip to content

Commit 0123ca2

Browse files
committed
Make sure inheritance of the codec comes from the Web3 instance
- Use the web3 object instance reference for ``Module`` and ``web3.ens`` since the codec is set on the Web3 instance itself and for general consistency. - Add tests to guarantee object reference consistency. - ``ENS.from_web3()`` should be excluded from this because that creates a new instance of ENS that is entirely separate from the initial web3 instance.
1 parent 10345cd commit 0123ca2

File tree

6 files changed

+216
-11
lines changed

6 files changed

+216
-11
lines changed

ens/ens.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,19 @@ def from_web3(cls, w3: "Web3", addr: ChecksumAddress = None) -> "ENS":
112112
"""
113113
Generate an ENS instance with web3
114114
115-
:param `web3.Web3` w3: to infer connection information
115+
:param `web3.Web3` w3: to infer connection, middleware, and codec information
116116
:param hex-string addr: the address of the ENS registry on-chain. If not
117117
provided, defaults to the mainnet ENS registry address.
118118
"""
119119
provider = w3.manager.provider
120120
middlewares = w3.middleware_onion.middlewares
121-
return cls(cast("BaseProvider", provider), addr=addr, middlewares=middlewares)
121+
ns = cls(cast("BaseProvider", provider), addr=addr, middlewares=middlewares)
122+
123+
# set codec and strict bytes type check flag from w3
124+
ns.w3.strict_bytes_type_checking = w3.strict_bytes_type_checking
125+
ns.w3.codec = w3.codec
126+
127+
return ns
122128

123129
def address(self, name: str) -> Optional[ChecksumAddress]:
124130
"""
Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,104 @@
1+
from ens import ENS
2+
3+
14
def test_strict_bytes_type_checking_turns_on_and_off(w3):
2-
# TODO: write this test
3-
pass
5+
assert w3.strict_bytes_type_checking
6+
assert not w3.is_encodable("bytes2", b"\x01")
7+
8+
w3.strict_bytes_type_checking = False
9+
assert not w3.strict_bytes_type_checking
10+
assert w3.is_encodable("bytes2", b"\x01")
11+
12+
w3.strict_bytes_type_checking = True
13+
assert w3.strict_bytes_type_checking
14+
assert not w3.is_encodable("bytes2", b"\x01")
15+
16+
17+
def test_ens_module_uses_strict_byte_type_check_from_web3_instance_reference(w3):
18+
assert w3.strict_bytes_type_checking
19+
assert not w3.is_encodable("bytes2", b"\x01")
20+
assert w3.ens.w3.strict_bytes_type_checking
21+
assert not w3.ens.w3.is_encodable("bytes2", b"\x01")
22+
23+
w3.strict_bytes_type_checking = False
24+
assert not w3.strict_bytes_type_checking
25+
assert not w3.ens.w3.strict_bytes_type_checking
26+
assert w3.is_encodable("bytes2", b"\x01")
27+
assert w3.ens.w3.is_encodable("bytes2", b"\x01")
28+
29+
w3.strict_bytes_type_checking = True
30+
assert w3.strict_bytes_type_checking
31+
assert w3.ens.w3.strict_bytes_type_checking
32+
assert not w3.is_encodable("bytes2", b"\x01")
33+
assert not w3.ens.w3.is_encodable("bytes2", b"\x01")
34+
35+
36+
def test_ens_from_web3_inherits_w3_codec_and_strict_byte_type_checking(w3):
37+
ns = ENS.from_web3(w3)
38+
39+
assert w3.strict_bytes_type_checking
40+
assert not w3.is_encodable("bytes2", b"\x01")
41+
42+
assert ns.w3.strict_bytes_type_checking
43+
assert not ns.w3.is_encodable("bytes2", b"\x01")
44+
45+
w3.strict_bytes_type_checking = False
46+
assert not w3.strict_bytes_type_checking
47+
assert w3.is_encodable("bytes2", b"\x01")
48+
49+
another_ns = ENS.from_web3(w3)
50+
assert not another_ns.w3.strict_bytes_type_checking
51+
assert another_ns.w3.is_encodable("bytes2", b"\x01")
52+
53+
54+
def test_modules_use_codec_and_strict_byte_type_check_from_web3_instance_reference(
55+
w3, module1, module2, module3
56+
):
57+
assert w3.codec == w3.eth.codec
58+
assert w3.codec == w3.net.codec
59+
assert w3.codec == w3.geth.codec
60+
61+
assert w3.strict_bytes_type_checking
62+
assert not w3.is_encodable("bytes2", b"\x01")
63+
assert not w3.eth.codec.is_encodable("bytes2", b"\x01")
64+
assert not w3.net.codec.is_encodable("bytes2", b"\x01")
65+
assert not w3.geth.codec.is_encodable("bytes2", b"\x01")
66+
67+
w3.strict_bytes_type_checking = False
68+
assert not w3.strict_bytes_type_checking
69+
assert w3.is_encodable("bytes2", b"\x01")
70+
assert w3.eth.codec.is_encodable("bytes2", b"\x01")
71+
assert w3.net.codec.is_encodable("bytes2", b"\x01")
72+
assert w3.geth.codec.is_encodable("bytes2", b"\x01")
73+
74+
# add modules after byte check swap
75+
76+
w3.attach_modules(
77+
{
78+
"module1": module1,
79+
"module2": (
80+
module2,
81+
{
82+
"submodule1": (module3,),
83+
},
84+
),
85+
}
86+
)
87+
88+
assert w3.codec == w3.module1.codec
89+
assert w3.codec == w3.module2.codec
90+
assert w3.codec == w3.module2.submodule1.codec
91+
92+
assert w3.module1.codec.is_encodable("bytes2", b"\x01")
93+
assert w3.module2.codec.is_encodable("bytes2", b"\x01")
94+
assert w3.module2.submodule1.codec.is_encodable("bytes2", b"\x01")
95+
96+
w3.strict_bytes_type_checking = True
97+
assert w3.strict_bytes_type_checking
98+
assert not w3.is_encodable("bytes2", b"\x01")
99+
assert not w3.eth.codec.is_encodable("bytes2", b"\x01")
100+
assert not w3.net.codec.is_encodable("bytes2", b"\x01")
101+
assert not w3.geth.codec.is_encodable("bytes2", b"\x01")
102+
assert not w3.module1.codec.is_encodable("bytes2", b"\x01")
103+
assert not w3.module2.codec.is_encodable("bytes2", b"\x01")
104+
assert not w3.module2.submodule1.codec.is_encodable("bytes2", b"\x01")

tests/ens/test_ens.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44
ENS,
55
AsyncENS,
66
)
7+
from web3 import Web3
78
from web3.middleware import (
89
async_validation_middleware,
910
pythonic_middleware,
1011
)
12+
from web3.providers.eth_tester import (
13+
AsyncEthereumTesterProvider,
14+
)
1115

1216

1317
def test_from_web3_inherits_web3_middlewares(w3):
@@ -18,13 +22,99 @@ def test_from_web3_inherits_web3_middlewares(w3):
1822
assert ns.w3.middleware_onion.get("test_middleware") == test_middleware
1923

2024

25+
def test_from_web3_does_not_set_w3_object_reference(w3):
26+
assert w3.strict_bytes_type_checking
27+
28+
ns = ENS.from_web3(w3)
29+
assert ns.w3.strict_bytes_type_checking
30+
31+
assert w3 != ns.w3 # assert not the same object
32+
33+
w3.strict_bytes_type_checking = False
34+
assert not w3.strict_bytes_type_checking
35+
36+
assert ns.w3.strict_bytes_type_checking # assert unchanged instance property
37+
38+
39+
def test_w3_ens_for_empty_ens_sets_w3_object_reference(w3):
40+
assert w3.strict_bytes_type_checking
41+
assert w3.ens.w3.strict_bytes_type_checking
42+
43+
assert w3 == w3.ens.w3 # assert same object
44+
45+
w3.strict_bytes_type_checking = False
46+
assert not w3.strict_bytes_type_checking
47+
assert not w3.ens.w3.strict_bytes_type_checking
48+
49+
50+
def test_w3_ens_setter_sets_w3_object_reference_on_ens(w3):
51+
ns = ENS.from_web3(w3)
52+
w3.ens = ns
53+
assert ns == w3.ens
54+
assert w3 == w3.ens.w3
55+
56+
assert w3.strict_bytes_type_checking
57+
assert w3.ens.w3.strict_bytes_type_checking
58+
59+
w3.strict_bytes_type_checking = False
60+
assert not w3.strict_bytes_type_checking
61+
assert not w3.ens.w3.strict_bytes_type_checking
62+
63+
2164
# -- async -- #
2265

2366

67+
@pytest.fixture
68+
def async_w3():
69+
return Web3(AsyncEthereumTesterProvider())
70+
71+
2472
@pytest.mark.asyncio
2573
async def test_async_from_web3_inherits_web3_middlewares(async_w3):
2674
test_middleware = async_validation_middleware
2775
async_w3.middleware_onion.add(test_middleware, "test_middleware")
2876

2977
ns = AsyncENS.from_web3(async_w3)
3078
assert ns.w3.middleware_onion.get("test_middleware") == test_middleware
79+
80+
81+
@pytest.mark.asyncio
82+
async def test_async_from_web3_does_not_set_w3_object_reference(async_w3):
83+
assert async_w3.strict_bytes_type_checking
84+
85+
ns = AsyncENS.from_web3(async_w3)
86+
assert ns.w3.strict_bytes_type_checking
87+
88+
assert async_w3 != ns.w3 # assert not the same object
89+
90+
async_w3.strict_bytes_type_checking = False
91+
assert not async_w3.strict_bytes_type_checking
92+
93+
assert ns.w3.strict_bytes_type_checking # assert unchanged instance property
94+
95+
96+
@pytest.mark.asyncio
97+
async def test_async_w3_ens_for_empty_ens_sets_w3_object_reference(async_w3):
98+
assert async_w3.strict_bytes_type_checking
99+
assert async_w3.ens.w3.strict_bytes_type_checking
100+
101+
assert async_w3 == async_w3.ens.w3 # assert same object
102+
103+
async_w3.strict_bytes_type_checking = False
104+
assert not async_w3.strict_bytes_type_checking
105+
assert not async_w3.ens.w3.strict_bytes_type_checking
106+
107+
108+
@pytest.mark.asyncio
109+
async def test_async_w3_ens_setter_sets_w3_object_reference_on_ens(async_w3):
110+
ns = AsyncENS.from_web3(async_w3)
111+
async_w3.ens = ns
112+
assert ns == async_w3.ens
113+
assert async_w3 == async_w3.ens.w3
114+
115+
assert async_w3.strict_bytes_type_checking
116+
assert async_w3.ens.w3.strict_bytes_type_checking
117+
118+
async_w3.strict_bytes_type_checking = False
119+
assert not async_w3.strict_bytes_type_checking
120+
assert not async_w3.ens.w3.strict_bytes_type_checking

web3/main.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,6 @@ def __init__(
252252
ens: Union[ENS, AsyncENS, "Empty"] = empty,
253253
) -> None:
254254
self.manager = self.RequestManager(self, provider, middlewares)
255-
# this codec gets used in the module initialization,
256-
# so it needs to come before attach_modules
257255
self.codec = ABICodec(build_strict_registry())
258256

259257
if modules is None:
@@ -369,14 +367,20 @@ def is_encodable(self, _type: TypeStr, value: Any) -> bool:
369367
@property
370368
def ens(self) -> Union[ENS, AsyncENS, "Empty"]:
371369
if self._ens is empty:
372-
return (
373-
AsyncENS.from_web3(self) if self.eth.is_async else ENS.from_web3(self)
370+
ns = (
371+
AsyncENS.from_web3(self)
372+
if self.provider.is_async
373+
else ENS.from_web3(self)
374374
)
375+
ns.w3 = self # set self object reference for ``ENS.w3``
376+
return cast(AsyncENS, ns) if self.provider.is_async else cast(ENS, ns)
375377

376378
return self._ens
377379

378380
@ens.setter
379381
def ens(self, new_ens: Union[ENS, AsyncENS, "Empty"]) -> None:
382+
if new_ens:
383+
new_ens.w3 = self # set self object reference for ``ENS.w3``
380384
self._ens = new_ens
381385

382386
@property

web3/module.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,11 @@ def __init__(self, w3: "Web3") -> None:
108108
else:
109109
self.retrieve_caller_fn = retrieve_blocking_method_call_fn(w3, self)
110110
self.w3 = w3
111-
self.codec: ABICodec = w3.codec
111+
112+
@property
113+
def codec(self) -> ABICodec:
114+
# use codec set on the Web3 instance
115+
return self.w3.codec
112116

113117
def attach_methods(
114118
self,

web3/pm.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,11 +575,11 @@ def _validate_set_registry(self) -> None:
575575
def _validate_set_ens(self) -> None:
576576
if not self.w3:
577577
raise InvalidAddress(
578-
"Could not look up ENS address because no web3 " "connection available"
578+
"Could not look up ENS address because no web3 connection available"
579579
)
580580
elif not self.w3.ens:
581581
raise InvalidAddress(
582-
"Could not look up ENS address because web3.ens is " "set to None"
582+
"Could not look up ENS address because web3.ens is not set up"
583583
)
584584

585585

0 commit comments

Comments
 (0)