From 0350b5e703c39e855ac6f10bfe9530aa914f0a46 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 21 May 2026 00:30:39 +0200 Subject: [PATCH] refactor: PEP 695 generic syntax for SSZ collections and Store Convert SSZVector, SSZList, and the lstar Store to PEP 695 generic syntax. The bounds (T: SSZType, StateT/BlockT: Container) now live inline in the class header, dropping three module-level TypeVar blocks and the Generic and TypeVar imports across two files. Pydantic 2.12 emits identical __pydantic_generic_metadata__ under both syntaxes, so the element-type recovery helper in collections is unaffected. StateT and BlockT also leave __all__ since they are now class-scoped and unused outside the file. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lean_spec/forks/lstar/store.py | 12 +++--------- src/lean_spec/types/collections.py | 14 ++------------ 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/lean_spec/forks/lstar/store.py b/src/lean_spec/forks/lstar/store.py index 79321c0da..d48290931 100644 --- a/src/lean_spec/forks/lstar/store.py +++ b/src/lean_spec/forks/lstar/store.py @@ -4,9 +4,9 @@ The Store tracks all information required for the LMD GHOST forkchoice algorithm. """ -__all__ = ["AttestationSignatureEntry", "BlockT", "StateT", "Store"] +__all__ = ["AttestationSignatureEntry", "Store"] -from typing import Generic, NamedTuple, TypeVar +from typing import NamedTuple from pydantic import Field @@ -21,12 +21,6 @@ from lean_spec.types.base import StrictBaseModel from lean_spec.types.container import Container -StateT = TypeVar("StateT", bound=Container) -"""Per-fork post-state type tracked alongside each known block.""" - -BlockT = TypeVar("BlockT", bound=Container) -"""Per-fork block type stored in the forkchoice view.""" - class AttestationSignatureEntry(NamedTuple): """ @@ -40,7 +34,7 @@ class AttestationSignatureEntry(NamedTuple): signature: Signature -class Store(StrictBaseModel, Generic[StateT, BlockT]): +class Store[StateT: Container, BlockT: Container](StrictBaseModel): """ Forkchoice store tracking chain state and validator attestations. diff --git a/src/lean_spec/types/collections.py b/src/lean_spec/types/collections.py index f83b33b97..26350bcf9 100644 --- a/src/lean_spec/types/collections.py +++ b/src/lean_spec/types/collections.py @@ -8,10 +8,8 @@ IO, Any, ClassVar, - Generic, Protocol, Self, - TypeVar, cast, overload, override, @@ -38,14 +36,6 @@ class IntFieldElement(Protocol): value: int -T = TypeVar("T", bound=SSZType) -"""Generic type parameter for SSZ collection elements. - -Bound to SSZType to ensure elements are valid SSZ types. -Enables type checkers to infer correct return types for indexed access. -""" - - def _extract_element_type_from_generic(cls: type, origin_class: type) -> type[SSZType] | None: """Extract ELEMENT_TYPE from Pydantic's generic metadata.""" for base in cls.__bases__: @@ -94,7 +84,7 @@ def _validate_offsets(offsets: list[int], scope: int, type_name: str) -> None: ) -class SSZVector(SSZModel, Generic[T]): +class SSZVector[T: SSZType](SSZModel): """Fixed-length, immutable SSZ sequence. Contains exactly LENGTH elements of type ELEMENT_TYPE. @@ -260,7 +250,7 @@ def elements(self) -> list[T]: return list(self.data) -class SSZList(SSZModel, Generic[T]): +class SSZList[T: SSZType](SSZModel): """Variable-length SSZ sequence with a maximum capacity. Contains between 0 and LIMIT elements of type ELEMENT_TYPE.