Skip to content

Commit 346f023

Browse files
committed
refactor: replace with for better type safety
Replace bound patterns with Python 3.11+ type for cleaner, more idiomatic type hints in method returns. Keeps for Generic classes that need type constraints. This improves type safety and reduces boilerplate code.
1 parent c97de26 commit 346f023

File tree

4 files changed

+17
-25
lines changed

4 files changed

+17
-25
lines changed

src/ethereum_test_base_types/base_types.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
to_number,
2222
)
2323

24-
N = TypeVar("N", bound="Number")
25-
2624

2725
class ToStringSchema:
2826
"""
@@ -44,7 +42,7 @@ def __get_pydantic_core_schema__(
4442
class Number(int, ToStringSchema):
4543
"""Class that helps represent numbers in tests."""
4644

47-
def __new__(cls, input_number: NumberConvertible | N):
45+
def __new__(cls, input_number: NumberConvertible | Self):
4846
"""Create a new Number object."""
4947
return super(Number, cls).__new__(cls, to_number(input_number))
5048

@@ -57,7 +55,7 @@ def hex(self) -> str:
5755
return hex(self)
5856

5957
@classmethod
60-
def or_none(cls: Type[N], input_number: N | NumberConvertible | None) -> N | None:
58+
def or_none(cls: Type[Self], input_number: Self | NumberConvertible | None) -> Self | None:
6159
"""Convert the input to a Number while accepting None."""
6260
if input_number is None:
6361
return input_number
@@ -67,7 +65,7 @@ def or_none(cls: Type[N], input_number: N | NumberConvertible | None) -> N | Non
6765
class Wei(Number):
6866
"""Class that helps represent wei that can be parsed from strings."""
6967

70-
def __new__(cls, input_number: NumberConvertible | N):
68+
def __new__(cls, input_number: NumberConvertible | Self):
7169
"""Create a new Number object."""
7270
if isinstance(input_number, str):
7371
words = input_number.split()
@@ -209,9 +207,6 @@ def __get_pydantic_core_schema__(
209207
)
210208

211209

212-
S = TypeVar("S", bound="FixedSizeHexNumber")
213-
214-
215210
class FixedSizeHexNumber(int, ToStringSchema):
216211
"""
217212
A base class that helps represent an integer as a fixed byte-length
@@ -233,7 +228,7 @@ class Sized(cls): # type: ignore
233228

234229
return Sized
235230

236-
def __new__(cls, input_number: NumberConvertible | N):
231+
def __new__(cls, input_number: NumberConvertible | Self):
237232
"""Create a new Number object."""
238233
i = to_number(input_number)
239234
if i > cls.max_value:
@@ -276,9 +271,6 @@ class HashInt(FixedSizeHexNumber[32]): # type: ignore
276271
pass
277272

278273

279-
T = TypeVar("T", bound="FixedSizeBytes")
280-
281-
282274
class FixedSizeBytes(Bytes):
283275
"""Class that helps represent bytes of fixed length in tests."""
284276

@@ -296,7 +288,7 @@ class Sized(cls): # type: ignore
296288

297289
def __new__(
298290
cls,
299-
input_bytes: FixedSizeBytesConvertible | T,
291+
input_bytes: FixedSizeBytesConvertible | Self,
300292
*,
301293
left_padding: bool = False,
302294
right_padding: bool = False,
@@ -319,7 +311,9 @@ def __hash__(self) -> int:
319311
return super(FixedSizeBytes, self).__hash__()
320312

321313
@classmethod
322-
def or_none(cls: Type[T], input_bytes: T | FixedSizeBytesConvertible | None) -> T | None:
314+
def or_none(
315+
cls: Type[Self], input_bytes: Self | FixedSizeBytesConvertible | None
316+
) -> Self | None:
323317
"""Convert the input to a Fixed Size Bytes while accepting None."""
324318
if input_bytes is None:
325319
return input_bytes

src/ethereum_test_base_types/pydantic.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44

55
from pydantic import BaseModel, ConfigDict, RootModel
66
from pydantic.alias_generators import to_camel
7+
from typing_extensions import Self
78

89
from .mixins import ModelCustomizationsMixin
910

10-
Model = TypeVar("Model", bound=BaseModel)
11-
1211
RootModelRootType = TypeVar("RootModelRootType")
1312

1413

@@ -27,7 +26,7 @@ class EthereumTestRootModel(RootModel[RootModelRootType], ModelCustomizationsMix
2726
class CopyValidateModel(EthereumTestBaseModel):
2827
"""Model that supports copying with validation."""
2928

30-
def copy(self: Model, **kwargs) -> Model:
29+
def copy(self: Self, **kwargs) -> Self:
3130
"""Create a copy of the model with the updated fields that are validated."""
3231
return self.__class__(**(self.model_dump(exclude_unset=True) | kwargs))
3332

src/ethereum_test_specs/base.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
from functools import reduce
66
from os import path
77
from pathlib import Path
8-
from typing import Callable, ClassVar, Dict, Generator, List, Sequence, Type, TypeVar
8+
from typing import Callable, ClassVar, Dict, Generator, List, Sequence, Type
99

1010
import pytest
1111
from pydantic import BaseModel, Field, PrivateAttr
12+
from typing_extensions import Self
1213

1314
from ethereum_clis import Result, TransitionTool
1415
from ethereum_test_base_types import to_hex
@@ -48,9 +49,6 @@ def verify_result(result: Result, env: Environment):
4849
assert result.withdrawals_root == to_hex(Withdrawal.list_root(env.withdrawals))
4950

5051

51-
T = TypeVar("T", bound="BaseTest")
52-
53-
5452
class BaseTest(BaseModel):
5553
"""Represents a base Ethereum test which must return a single test fixture."""
5654

@@ -91,11 +89,11 @@ def __pydantic_init_subclass__(cls, **kwargs):
9189

9290
@classmethod
9391
def from_test(
94-
cls: Type[T],
92+
cls: Type[Self],
9593
*,
9694
base_test: "BaseTest",
9795
**kwargs,
98-
) -> T:
96+
) -> Self:
9997
"""Create a test in a different format from a base test."""
10098
new_instance = cls(
10199
tag=base_test.tag,

src/ethereum_test_types/account_types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from ethereum_types.bytes import Bytes20
88
from ethereum_types.numeric import U256, Bytes32, Uint
99
from pydantic import PrivateAttr
10+
from typing_extensions import Self
1011

1112
from ethereum_test_base_types import (
1213
Account,
@@ -126,9 +127,9 @@ def get_nonce(self) -> Number:
126127
self.nonce = Number(nonce + 1)
127128
return nonce
128129

129-
def copy(self) -> "EOA":
130+
def copy(self) -> Self:
130131
"""Return copy of the EOA."""
131-
return EOA(Address(self), key=self.key, nonce=self.nonce)
132+
return self.__class__(Address(self), key=self.key, nonce=self.nonce)
132133

133134

134135
class Alloc(BaseAlloc):

0 commit comments

Comments
 (0)