Skip to content

Commit 65938cf

Browse files
authored
feat: strengthen typing and remove suppressions (#451)
- Replaced '# type: ignore' suppressions in discovery transport with 'assert isinstance' guards - Removed hasattr defensive checks in node.py (Checkpoint.root is Bytes32, always provides .hex()) - Narrowed Coroutine[Any, Any, None] to Coroutine[None, None, None] in sync service and removed typing.Any import - Updated unit test mocks to provide spec matching assertions
1 parent 2835375 commit 65938cf

File tree

4 files changed

+42
-39
lines changed

4 files changed

+42
-39
lines changed

src/lean_spec/subspecs/networking/discovery/transport.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ def __init__(self, transport_handler: DiscoveryTransport) -> None:
135135

136136
def connection_made(self, transport: asyncio.transports.BaseTransport) -> None:
137137
"""Called when UDP socket is ready."""
138-
self._transport = transport # type: ignore[assignment]
138+
assert isinstance(transport, asyncio.DatagramTransport)
139+
self._transport = transport
139140

140141
def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None:
141142
"""Called when a UDP packet is received."""
@@ -219,8 +220,10 @@ async def start(self, host: str = "0.0.0.0", port: int = 9000) -> None:
219220
lambda: DiscoveryProtocol(self),
220221
local_addr=(host, port),
221222
)
222-
self._transport = transport # type: ignore[assignment]
223-
self._protocol = protocol # type: ignore[assignment]
223+
assert isinstance(transport, asyncio.DatagramTransport)
224+
assert isinstance(protocol, DiscoveryProtocol)
225+
self._transport = transport
226+
self._protocol = protocol
224227

225228
self._running = True
226229
logger.info("Discovery transport started on %s:%d", host, port)

src/lean_spec/subspecs/node/node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,8 @@ async def _log_justified_finalized_periodically(self) -> None:
484484
metrics.lean_validators_count.set(count)
485485
j = store.latest_justified
486486
f = store.latest_finalized
487-
j_root = j.root.hex() if hasattr(j.root, "hex") else str(j.root)
488-
f_root = f.root.hex() if hasattr(f.root, "hex") else str(f.root)
487+
j_root = j.root.hex()
488+
f_root = f.root.hex()
489489
logger.info("=" * 64)
490490
logger.info(
491491
"Peers=%s | Justified slot=%s root=%s | Finalized slot=%s root=%s",

src/lean_spec/subspecs/sync/service.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import time
4242
from collections.abc import Callable, Coroutine
4343
from dataclasses import dataclass, field
44-
from typing import TYPE_CHECKING, Any
44+
from typing import TYPE_CHECKING
4545

4646
from lean_spec.subspecs.chain.clock import SlotClock
4747
from lean_spec.subspecs.containers import (
@@ -164,7 +164,7 @@ class SyncService:
164164
)
165165
"""Block processor function. Defaults to the store's block processing."""
166166

167-
_publish_agg_fn: Callable[[SignedAggregatedAttestation], Coroutine[Any, Any, None]] = field(
167+
_publish_agg_fn: Callable[[SignedAggregatedAttestation], Coroutine[None, None, None]] = field(
168168
default=_noop_publish_agg
169169
)
170170
"""Callback for publishing aggregated attestations to the network."""
@@ -204,7 +204,7 @@ class SyncService:
204204
"""
205205

206206
def set_publish_agg_fn(
207-
self, fn: Callable[[SignedAggregatedAttestation], Coroutine[Any, Any, None]]
207+
self, fn: Callable[[SignedAggregatedAttestation], Coroutine[None, None, None]]
208208
) -> None:
209209
"""Wire the aggregated attestation publisher after construction.
210210

tests/lean_spec/subspecs/networking/discovery/test_transport.py

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def test_connection_made_stores_transport(self):
4242
mock_handler = MagicMock()
4343
protocol = DiscoveryProtocol(mock_handler)
4444

45-
mock_transport = MagicMock()
45+
mock_transport = MagicMock(spec=asyncio.DatagramTransport)
4646
protocol.connection_made(mock_transport)
4747

4848
assert protocol._transport is mock_transport
@@ -189,8 +189,8 @@ async def test_start_creates_udp_endpoint(self, local_node_id, local_private_key
189189
)
190190

191191
# Mock the event loop's create_datagram_endpoint.
192-
mock_transport_obj = MagicMock()
193-
mock_protocol_obj = MagicMock()
192+
mock_transport_obj = MagicMock(spec=asyncio.DatagramTransport)
193+
mock_protocol_obj = MagicMock(spec=DiscoveryProtocol)
194194

195195
with patch.object(
196196
asyncio.get_event_loop(),
@@ -213,8 +213,8 @@ async def test_start_is_idempotent(self, local_node_id, local_private_key, local
213213
local_enr=local_enr,
214214
)
215215

216-
mock_transport_obj = MagicMock()
217-
mock_protocol_obj = MagicMock()
216+
mock_transport_obj = MagicMock(spec=asyncio.DatagramTransport)
217+
mock_protocol_obj = MagicMock(spec=DiscoveryProtocol)
218218

219219
with patch.object(
220220
asyncio.get_event_loop(),
@@ -238,8 +238,8 @@ async def test_stop_closes_transport(self, local_node_id, local_private_key, loc
238238
local_enr=local_enr,
239239
)
240240

241-
mock_transport_obj = MagicMock()
242-
mock_protocol_obj = MagicMock()
241+
mock_transport_obj = MagicMock(spec=asyncio.DatagramTransport)
242+
mock_protocol_obj = MagicMock(spec=DiscoveryProtocol)
243243

244244
with patch.object(
245245
asyncio.get_event_loop(),
@@ -262,8 +262,8 @@ async def test_stop_cancels_pending_requests(self, local_node_id, local_private_
262262
local_enr=local_enr,
263263
)
264264

265-
mock_transport_obj = MagicMock()
266-
mock_protocol_obj = MagicMock()
265+
mock_transport_obj = MagicMock(spec=asyncio.DatagramTransport)
266+
mock_protocol_obj = MagicMock(spec=DiscoveryProtocol)
267267

268268
with patch.object(
269269
asyncio.get_event_loop(),
@@ -347,8 +347,8 @@ async def test_send_response_without_session_returns_false(
347347
local_enr=local_enr,
348348
)
349349

350-
mock_transport_obj = MagicMock()
351-
mock_protocol_obj = MagicMock()
350+
mock_transport_obj = MagicMock(spec=asyncio.DatagramTransport)
351+
mock_protocol_obj = MagicMock(spec=DiscoveryProtocol)
352352

353353
with patch.object(
354354
asyncio.get_event_loop(),
@@ -767,8 +767,8 @@ async def test_pending_requests_cleared_on_stop(
767767
local_enr=local_enr,
768768
)
769769

770-
mock_transport_obj = MagicMock()
771-
mock_protocol_obj = MagicMock()
770+
mock_transport_obj = MagicMock(spec=asyncio.DatagramTransport)
771+
mock_protocol_obj = MagicMock(spec=DiscoveryProtocol)
772772

773773
with patch.object(
774774
asyncio.get_event_loop(),
@@ -809,8 +809,8 @@ async def test_pending_request_futures_cancelled_on_stop(
809809
local_enr=local_enr,
810810
)
811811

812-
mock_transport_obj = MagicMock()
813-
mock_protocol_obj = MagicMock()
812+
mock_transport_obj = MagicMock(spec=asyncio.DatagramTransport)
813+
mock_protocol_obj = MagicMock(spec=DiscoveryProtocol)
814814

815815
with patch.object(
816816
asyncio.get_event_loop(),
@@ -871,11 +871,11 @@ async def test_send_ping_returns_none_on_timeout(
871871
config=config,
872872
)
873873

874-
mock_udp = MagicMock()
874+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
875875
with patch.object(
876876
asyncio.get_event_loop(),
877877
"create_datagram_endpoint",
878-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
878+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
879879
):
880880
await transport.start("127.0.0.1", 9000)
881881

@@ -899,11 +899,11 @@ async def test_send_ping_sends_packet_to_correct_address(
899899
config=config,
900900
)
901901

902-
mock_udp = MagicMock()
902+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
903903
with patch.object(
904904
asyncio.get_event_loop(),
905905
"create_datagram_endpoint",
906-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
906+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
907907
):
908908
await transport.start("127.0.0.1", 9000)
909909

@@ -929,11 +929,11 @@ async def test_send_ping_registers_node_address(
929929
config=config,
930930
)
931931

932-
mock_udp = MagicMock()
932+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
933933
with patch.object(
934934
asyncio.get_event_loop(),
935935
"create_datagram_endpoint",
936-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
936+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
937937
):
938938
await transport.start("127.0.0.1", 9000)
939939

@@ -975,11 +975,11 @@ async def test_send_findnode_returns_empty_on_timeout(
975975
config=config,
976976
)
977977

978-
mock_udp = MagicMock()
978+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
979979
with patch.object(
980980
asyncio.get_event_loop(),
981981
"create_datagram_endpoint",
982-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
982+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
983983
):
984984
await transport.start("127.0.0.1", 9000)
985985

@@ -1003,11 +1003,11 @@ async def test_send_findnode_sends_packet_to_correct_address(
10031003
config=config,
10041004
)
10051005

1006-
mock_udp = MagicMock()
1006+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
10071007
with patch.object(
10081008
asyncio.get_event_loop(),
10091009
"create_datagram_endpoint",
1010-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
1010+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
10111011
):
10121012
await transport.start("127.0.0.1", 9000)
10131013

@@ -1052,11 +1052,11 @@ async def test_send_talkreq_returns_none_on_timeout(
10521052
config=config,
10531053
)
10541054

1055-
mock_udp = MagicMock()
1055+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
10561056
with patch.object(
10571057
asyncio.get_event_loop(),
10581058
"create_datagram_endpoint",
1059-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
1059+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
10601060
):
10611061
await transport.start("127.0.0.1", 9000)
10621062

@@ -1303,11 +1303,11 @@ async def test_send_whoareyou_sends_packet(
13031303
local_enr=local_enr,
13041304
)
13051305

1306-
mock_udp = MagicMock()
1306+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
13071307
with patch.object(
13081308
asyncio.get_event_loop(),
13091309
"create_datagram_endpoint",
1310-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
1310+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
13111311
):
13121312
await transport.start("127.0.0.1", 9000)
13131313

@@ -1338,11 +1338,11 @@ async def test_send_whoareyou_uses_cached_enr_seq(
13381338
)
13391339
transport.register_enr(remote_node_id, remote_enr)
13401340

1341-
mock_udp = MagicMock()
1341+
mock_udp = MagicMock(spec=asyncio.DatagramTransport)
13421342
with patch.object(
13431343
asyncio.get_event_loop(),
13441344
"create_datagram_endpoint",
1345-
new=AsyncMock(return_value=(mock_udp, MagicMock())),
1345+
new=AsyncMock(return_value=(mock_udp, MagicMock(spec=DiscoveryProtocol))),
13461346
):
13471347
await transport.start("127.0.0.1", 9000)
13481348

0 commit comments

Comments
 (0)