Skip to content

Commit 7b0b2de

Browse files
alexanderlhicksclaudetcoratger
authored
chore(ty): make suppressions ty-native and enforce honesty (leanEthereum#826)
Standardize on ty as the single type checker. Every suppression is now ty-native (# ty: ignore[code]), load-bearing, and documented, and ty itself blocks stale or duplicate suppressions going forward. - Enable the unused-ignore-comment rule, which flags any suppression that no longer matches a real diagnostic. - Remove 23 dead mypy-style # type: ignore comments that ty does not need: create_store in the lstar spec (ty raises nothing there) plus 22 across the test suite and testing framework (frozen-assignment tests, abstract instantiation, operator-error paths, mock overrides). - Convert the genuinely-needed override suppressions to ty-native form with the correct rule code (invalid-method-override). - Document the load-bearing suppressions: the two clock forward references forced by the interval/slot import cycle, and the field exponentiation override. ty honors mypy-style # type: ignore comments, so the dead ones were silently accepted; the new rule surfaces them and keeps the ignore set honest. just check passes and the affected tests are green. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Thomas Coratger <60488569+tcoratger@users.noreply.github.com>
1 parent e17e11d commit 7b0b2de

16 files changed

Lines changed: 37 additions & 29 deletions

File tree

packages/testing/src/consensus_testing/test_fixtures/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class BaseConsensusFixture(BaseFixture):
1616

1717
# Class-level registry of all consensus fixture formats
1818
# Override parent's formats to maintain a separate registry
19-
formats: ClassVar[dict[str, type["BaseConsensusFixture"]]] = {} # type: ignore[assignment]
19+
formats: ClassVar[dict[str, type["BaseConsensusFixture"]]] = {}
2020

2121
expect_exception: type[Exception] | None = None
2222
"""

packages/testing/src/framework/pytest_plugins/filler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item
285285
return
286286

287287
fork_class = config.test_fork_class
288-
layer_module = config.layer_module # type: ignore[attribute-defined]
288+
layer_module = config.layer_module
289289
registry = layer_module.forks.registry
290290
verbose = config.getoption("verbose")
291291
deselected = []
@@ -469,7 +469,7 @@ def base_spec_filler_parametrizer_func(
469469
) -> Any:
470470
"""Fixture used to instantiate an auto-fillable fixture object."""
471471

472-
class FixtureWrapper(fixture_class): # type: ignore[misc]
472+
class FixtureWrapper(fixture_class):
473473
"""Wrapper class that auto-fills and collects fixtures on instantiation."""
474474

475475
def __init__(self, **kwargs: Any) -> None:

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ python-version = "3.12"
8989
[tool.ty.src]
9090
exclude = [".claude/"]
9191

92+
[tool.ty.rules]
93+
# Flag any suppression comment that no longer matches a real diagnostic.
94+
# Keeps the ignore set honest as the code evolves and prevents stale or duplicate suppressions.
95+
unused-ignore-comment = "error"
96+
9297
[tool.ty.terminal]
9398
error-on-warning = true
9499

src/lean_spec/spec/crypto/koalabear.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ def __rmul__(self, other: Any) -> NoReturn:
148148
"""Reverse multiplication: reject non-Fp left operand to prevent silent int fallback."""
149149
self._reject(other, "*")
150150

151+
# The int base declares a three-argument pow with an optional modulus.
152+
#
153+
# The field already reduces modulo P, so the modulus argument is meaningless here.
154+
# Narrowing to the field type is intentional and safe by Liskov substitution.
151155
def __pow__(self, exponent: int) -> Self: # ty: ignore[invalid-method-override]
152156
"""Field exponentiation."""
153157
return type(self)(pow(int(self), exponent, P))

src/lean_spec/spec/forks/lstar/fork_choice.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
class ForkChoiceMixin(LstarSpecContract):
3737
"""Fork choice and store maintenance for the lstar fork."""
3838

39-
def create_store( # type: ignore[override] # ty: ignore[invalid-method-override]
39+
def create_store(
4040
self,
4141
state: SpecStateType,
4242
anchor_block: SpecBlockType,

src/lean_spec/spec/ssz/collections.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,11 @@ def __len__(self) -> int:
216216
"""Return the number of elements in the sequence."""
217217
return len(self.data)
218218

219+
# The parent Pydantic model iterates field name and value pairs.
220+
# Yielding elements instead is the intended collection behavior.
221+
# The narrower element type violates strict Liskov substitution, so it is suppressed.
219222
@override
220-
def __iter__(self) -> Iterator[T]: # type: ignore[override]
223+
def __iter__(self) -> Iterator[T]: # ty: ignore[invalid-method-override]
221224
"""
222225
Iterate over the elements.
223226

tests/lean_spec/helpers/mocks.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,25 @@
2828
class StoreInterceptingSpec(LstarSpec):
2929
"""Spec stub that forwards consensus calls to the store argument."""
3030

31-
def on_block( # type: ignore[override]
32-
self, store: Any, signed_block: Any, *args: Any, **kwargs: Any
33-
) -> Any:
31+
def on_block(self, store: Any, signed_block: Any, *args: Any, **kwargs: Any) -> Any:
3432
"""Forward to store.on_block."""
3533
kwargs.pop("scheme", None)
3634
return store.on_block(signed_block, *args, **kwargs)
3735

38-
def on_gossip_attestation( # type: ignore[override]
36+
def on_gossip_attestation(
3937
self, store: Any, signed_attestation: Any, *args: Any, **kwargs: Any
4038
) -> Any:
4139
"""Forward to store.on_gossip_attestation."""
4240
kwargs.pop("scheme", None)
4341
return store.on_gossip_attestation(signed_attestation, *args, **kwargs)
4442

45-
def on_gossip_aggregated_attestation( # type: ignore[override]
43+
def on_gossip_aggregated_attestation(
4644
self, store: Any, signed_attestation: Any, *args: Any, **kwargs: Any
4745
) -> Any:
4846
"""Forward to store.on_gossip_aggregated_attestation."""
4947
return store.on_gossip_aggregated_attestation(signed_attestation, *args, **kwargs)
5048

51-
def tick_interval( # type: ignore[override]
52-
self, store: Any, has_proposal: bool, is_aggregator: bool = False
53-
) -> Any:
49+
def tick_interval(self, store: Any, has_proposal: bool, is_aggregator: bool = False) -> Any:
5450
"""Forward to store.tick_interval."""
5551
return store.tick_interval(has_proposal, is_aggregator)
5652

tests/lean_spec/node/chain/test_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def __init__(self, emit: list[SignedAggregatedAttestation] | None = None) -> Non
5555
self.ticks: list[tuple[int, bool, bool]] = []
5656
self.emit = emit or []
5757

58-
def tick_interval( # type: ignore[override]
58+
def tick_interval(
5959
self, store: Store, has_proposal: bool, is_aggregator: bool = False
6060
) -> tuple[Store, list[SignedAggregatedAttestation]]:
6161
"""Advance the real store, record the call, then emit at the aggregation interval."""

tests/lean_spec/node/networking/gossipsub/integration/test_mesh_formation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
TOPIC = TopicId("test/mesh")
2525

2626

27-
def _all_meshes_in_bounds(network: GossipsubTestNetwork, params, topic: str) -> bool: # type: ignore[no-untyped-def]
27+
def _all_meshes_in_bounds(network: GossipsubTestNetwork, params, topic: str) -> bool:
2828
"""Check whether every node's mesh is within [D_low, D_high]."""
2929
return all(params.d_low <= node.get_mesh_size(topic) <= params.d_high for node in network.nodes)
3030

tests/lean_spec/node/networking/service/test_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ async def test_stop_async_iteration_exception_caught(self, peer_id: PeerId) -> N
144144
sync_service = create_mock_sync_service(peer_id)
145145
svc = NetworkService(
146146
sync_service=sync_service,
147-
event_source=source, # type: ignore[arg-type]
147+
event_source=source,
148148
network_name=FORK_DIGEST,
149149
)
150150
await svc.run()

0 commit comments

Comments
 (0)