Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): better docs with gpt-4o #16

Merged
merged 2 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion evmspec/_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,37 @@

class StringToIntEnumMeta(EnumMeta):
"""
A metaclass for Enums that allows conversion from string to integer Enum members.
A metaclass for Enums that enables conversion from string or integer
values to Enum members using the member map.

When a value is given, the process to find the corresponding Enum member
is as follows:

- If the value exists in the `_member_map_`, the corresponding Enum
member is returned.
- If the value is not found in the `_member_map_`, the original value is
returned and passed to the base `EnumMeta`'s `__call__` method. This
method may raise an exception if the value does not correspond to any
Enum member as per typical Enum behavior.

Args:
value: The value to be converted to an Enum member. It can be either
a string that matches a member's name or an integer that
matches a member's value.
*args: Additional arguments.
**kw: Additional keyword arguments.
"""

def __call__(cls, value: Union[str, int], *args, **kw):
"""Attempts to convert a given value to an Enum member.

If the value exists in the `_member_map_`, the corresponding Enum
member is returned. If not, the original value is passed to the base
`EnumMeta`'s `__call__` method.

Args:
value: The value to be converted to an Enum member.
*args: Additional arguments.
**kw: Additional keyword arguments.
"""
return super().__call__(cls._member_map_.get(value, value), *args, **kw) # type: ignore [arg-type]
25 changes: 19 additions & 6 deletions evmspec/_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@


class IntId(uint):
"""A base class for identifiers that do not support arithmetic operations.

This class raises a TypeError when attempts are made to perform any
of the following arithmetic operations on its instances: addition,
subtraction, multiplication, true division, floor division, and exponentiation.
"""

def __add__(*_):
raise TypeError(f"You cannot perform math on a {type(_[0]).__name__}")

Expand Down Expand Up @@ -40,18 +47,24 @@ def __rpow__(*_):


class ChainId(IntId):
"""
Represents a unique identifier for an Ethereum chain, used to distinguish between different blockchain networks.
"""Represents a unique identifier for an Ethereum chain.

It is used to distinguish between different blockchain networks.
This class does not support any arithmetic operations.
"""


class TransactionIndex(IntId):
"""
Represents the index of a transaction within a block, used to identify the transaction's position.
"""Represents the index of a transaction within a block.

It is used to identify the transaction's position in the block.
This class does not support any arithmetic operations.
"""


class LogIndex(IntId):
"""
Represents the index of a log entry within a transaction, used to identify the log's position.
"""Represents the index of a log entry within a transaction.

It is used to identify the log's position within the transaction.
This class does not support any arithmetic operations.
"""
126 changes: 122 additions & 4 deletions evmspec/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,40 @@ class Address(str):
"""

def __new__(cls, address: str):
"""Creates a new Address instance with checksum validation."""
"""Creates a new Address instance with checksum validation.

Args:
address: A string representing the Ethereum address.

Returns:
An Address object with a checksummed address.
"""
return super().__new__(cls, to_checksum_address(address))

@classmethod
def _decode_hook(cls, typ: Type["Address"], obj: str):
"""Decodes a string into an Address instance."""
"""Returns a checksummed version of the address.

Args:
typ: The type that is expected to be decoded to.
obj: The object to decode, expected to be a string representation of an Ethereum address.

Returns:
A checksummed Address.
"""
return cls.checksum(obj)

@classmethod
@ttl_cache(ttl=600)
def checksum(cls, address: str) -> Self:
"""Returns the checksummed version of the address."""
"""Returns the checksummed version of the address.

Args:
address: A string representing the Ethereum address.

Returns:
The checksummed Ethereum address.
"""
return cls(address)


Expand All @@ -52,6 +74,14 @@ class uint(int):

@classmethod
def fromhex(cls, hexstr: str) -> Self:
"""Converts a hexadecimal string to a uint.

Args:
hexstr: A string representing a hexadecimal number.

Returns:
A uint object representing the integer value of the hexadecimal string.
"""
return cls(hexstr, 16)

"""
Expand All @@ -78,10 +108,27 @@ def __repr__(self) -> str:

@classmethod
def _decode_hook(cls, typ: Type["uint"], obj: str):
"""Decodes a string or number into a uint.

Args:
typ: The type that is expected to be decoded to.
obj: The object to decode, expected to be a string or number.

Returns:
A uint object representing the decoded value.
"""
return typ(obj, 16)

@classmethod
def _decode(cls, obj) -> "uint":
"""Attempts to decode an object as a uint, handling TypeErrors.

Args:
obj: The object to decode.

Returns:
A uint object representing the decoded value.
"""
try:
return cls.fromhex(obj)
except TypeError as e:
Expand All @@ -93,6 +140,14 @@ def _decode(cls, obj) -> "uint":
class Wei(uint):
@cached_property
def scaled(self) -> "Decimal":
"""Returns the scaled decimal representation of Wei.

Calculation:
The value in Wei divided by 10**18 to convert to Ether.

Returns:
A Decimal object representing the scaled Ether value.
"""
return Decimal(self) / 10**18

# @property
Expand All @@ -109,14 +164,30 @@ class Nonce(uint): ...
class UnixTimestamp(uint):
@cached_property
def datetime(self) -> datetime:
"""Converts the Unix timestamp to a datetime object in UTC."""
"""Converts the Unix timestamp to a datetime object in UTC.

Returns:
A datetime object representing the UTC date and time.
"""
return datetime.fromtimestamp(self, tz=timezone.utc)


# Hook


def _decode_hook(typ: Type, obj: object):
"""A generic decode hook for converting objects to specific types.

Args:
typ: The type that is expected to be decoded to.
obj: The object to decode.

Returns:
The object decoded to the specified type.

Raises:
NotImplementedError: If the type cannot be handled.
"""
if issubclass(typ, (HexBytes, Enum, Decimal)):
return typ(obj) # type: ignore [arg-type]
elif typ is Address:
Expand All @@ -139,6 +210,17 @@ def _decode_hook(typ: Type, obj: object):

class HexBytes32(HexBytes):
def __new__(cls, v):
"""Create a new HexBytes32 object.

Args:
v: A value that can be converted to HexBytes32.

Returns:
A HexBytes32 object.

Raises:
ValueError: If the string representation is not the correct length.
"""
# if it has 0x prefix it came from the chain or a user and we should validate the size
# when it doesnt have the prefix it came out of one of my dbs in a downstream lib and we can trust the size.
if isinstance(v, str) and v.startswith("0x"):
Expand All @@ -157,6 +239,14 @@ def __repr__(self) -> str:

@staticmethod
def _get_missing_bytes(input_bytes: HexBytes) -> bytes:
"""Calculate the number of missing bytes and return them.

Args:
input_bytes: The input bytes to check.

Returns:
A bytes object representing the missing bytes.
"""
missing_length = 32 - len(input_bytes)
return missing_length * ONE_EMPTY_BYTE

Expand All @@ -170,6 +260,14 @@ def strip(self) -> str: # type: ignore [override]

@staticmethod
def _check_hexstr(hexstr: str):
"""Checks if a hex string is of a valid length.

Args:
hexstr: The hex string to check.

Raises:
ValueError: If the hex string is of an invalid length.
"""
l = len(hexstr)
if l > 66:
raise ValueError("too high", len(hexstr), hexstr)
Expand All @@ -186,6 +284,18 @@ class TransactionHash(HexBytes32):
async def get_receipt(
self, decode_to: Type[_T], decode_hook: _DecodeHook[_T] = _decode_hook
) -> "TransactionReceipt":
"""Async method to get the transaction receipt.

Args:
decode_to: The type to decode the receipt to.
decode_hook: A hook function to perform the decoding.

Returns:
A TransactionReceipt object for the transaction.

Raises:
ImportError: If 'dank_mids' cannot be imported.
"""
import dank_mids

return await dank_mids.eth.get_transaction_receipt(
Expand All @@ -194,6 +304,14 @@ async def get_receipt(

@a_sync # TODO; compare how these type check, they both function the same
async def get_logs(self) -> Tuple["Log", ...]:
"""Async method to get the logs for the transaction.

Returns:
A tuple of Log objects for the transaction.

Raises:
ImportError: If 'dank_mids' cannot be imported.
"""
try:
import dank_mids
except ImportError:
Expand Down
16 changes: 14 additions & 2 deletions evmspec/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@
class ErigonBlockHeader(LazyDictStruct, frozen=True, kw_only=True, forbid_unknown_fields=True): # type: ignore [call-arg]
"""
Represents a block header in the Erigon client.

This class is designed to utilize `LazyDictStruct` for handling block header data,
ensuring immutability and strictness to known fields. It is currently under development,
and specific features may not yet be functional. There may be known issues needing resolution.

Attributes:
timestamp (UnixTimestamp): The Unix timestamp for when the block was collated.
parentHash (HexBytes): The hash of the parent block.
uncleHash (HexBytes): The hash of the list of uncle headers.
coinbase (Address): The address of the miner who mined the block.
root (HexBytes): The root hash of the state trie.
difficulty (uint): The difficulty level of the block.
"""

timestamp: UnixTimestamp
Expand All @@ -17,13 +29,13 @@ class ErigonBlockHeader(LazyDictStruct, frozen=True, kw_only=True, forbid_unknow
"""The hash of the parent block."""

uncleHash: HexBytes
"""The hash of the uncle block."""
"""The hash of the list of uncle headers."""

coinbase: Address
"""The address of the miner who mined the block."""

root: HexBytes
"""The root hash of the block."""
"""The root hash of the state trie."""

difficulty: uint
"""The difficulty level of the block."""
Loading