Skip to content

Commit d206a1c

Browse files
codebydivineclaude
andcommitted
refactor: streamline API architecture and improve type safety
- Consolidate API methods and simplify class structure - Enhance type definitions and model consistency - Update examples to reflect new API patterns - Improve test coverage for core functionality 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent f3e6965 commit d206a1c

File tree

13 files changed

+206
-359
lines changed

13 files changed

+206
-359
lines changed

examples/endpoints/evm/balances.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
#!/usr/bin/env python3
22
"""Token Balances Example - See your crypto portfolio instantly."""
33

4+
# Import shared helper functions
5+
import sys
6+
from pathlib import Path
7+
48
import anyio
59

610
from thegraph_token_api import TokenAPI
711

8-
9-
def format_amount(value):
10-
"""Format large numbers with K/M suffixes."""
11-
if value >= 1_000_000:
12-
return f"{value / 1_000_000:.1f}M"
13-
if value >= 1_000:
14-
return f"{value / 1_000:.1f}K"
15-
return f"{value:.2f}"
12+
sys.path.append(str(Path(__file__).parent.parent.parent))
13+
from _helpers import format_amount
1614

1715

1816
async def main():

examples/endpoints/evm/prices.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
#!/usr/bin/env python3
22
"""Price History Example - Track token prices over time."""
33

4+
# Import shared helper functions
5+
import sys
46
from datetime import datetime
7+
from pathlib import Path
58

69
import anyio
710

811
from thegraph_token_api import Interval, TokenAPI
912

13+
sys.path.append(str(Path(__file__).parent.parent.parent))
14+
from _helpers import format_price_change
15+
1016

1117
def parse_datetime(datetime_str):
1218
"""Parse ISO datetime string safely."""
@@ -16,14 +22,6 @@ def parse_datetime(datetime_str):
1622
return None
1723

1824

19-
def format_price_change(open_price, close_price):
20-
"""Calculate and format price change percentage."""
21-
if not open_price or open_price == 0:
22-
return "±0.0%"
23-
change = ((close_price - open_price) / open_price) * 100
24-
return f"{change:+.1f}%"
25-
26-
2725
async def main():
2826
print("📈 Price History")
2927
print("=" * 16)

examples/endpoints/evm/transfers.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
#!/usr/bin/env python3
22
"""Token Transfers Example - Track token movements on-chain."""
33

4-
from datetime import datetime
4+
# Import shared helper functions
5+
import sys
6+
from pathlib import Path
57

68
import anyio
79

810
from thegraph_token_api import TokenAPI
911

10-
11-
def format_time(timestamp):
12-
"""Format timestamp to readable time."""
13-
try:
14-
return datetime.fromtimestamp(timestamp).strftime("%H:%M")
15-
except (ValueError, OSError, OverflowError):
16-
return "??:??"
12+
sys.path.append(str(Path(__file__).parent.parent.parent))
13+
from _helpers import format_time
1714

1815

1916
async def main():

examples/endpoints/svm/swaps.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
#!/usr/bin/env python3
22
"""Solana DEX Swaps Example - Track Solana trading activity."""
33

4-
from datetime import datetime
4+
# Import shared helper functions
5+
import sys
6+
from pathlib import Path
57

68
import anyio
79

810
from thegraph_token_api import SwapPrograms, TokenAPI
911

10-
11-
def get_symbol(mint_obj):
12-
"""Get token symbol or shortened mint address."""
13-
if hasattr(mint_obj, "symbol") and mint_obj.symbol:
14-
return mint_obj.symbol
15-
return str(mint_obj)[:6] + "..."
16-
17-
18-
def format_time(timestamp):
19-
"""Format timestamp to readable time."""
20-
try:
21-
return datetime.fromtimestamp(timestamp).strftime("%H:%M")
22-
except (ValueError, OSError, OverflowError):
23-
return "??:??"
12+
sys.path.append(str(Path(__file__).parent.parent.parent))
13+
from _helpers import format_time, get_symbol
2414

2515

2616
async def main():

src/thegraph_token_api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ async def main():
8080
SolanaTransfer,
8181
SolanaTransfersResponse,
8282
Statistics,
83+
StringEnum,
8384
Swap,
8485
SwapPrograms,
8586
SwapsResponse,
@@ -98,6 +99,7 @@ async def main():
9899
__all__ = [
99100
"TokenAPI", # Main interface
100101
# Export all types
102+
"StringEnum",
101103
"NetworkId",
102104
"SolanaNetworkId",
103105
"TokenStandard",

src/thegraph_token_api/base.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
import os
8+
from typing import Any
89

910
# Import divine-typed-requests (should be installed as a package)
1011
from typed_requests import NetworkingManager # type: ignore[attr-defined]
@@ -49,6 +50,23 @@ def _validate_pagination(self, limit: int, page: int) -> None:
4950
if page < 1:
5051
raise ValueError("page must be 1 or greater")
5152

53+
def _build_base_params(self, network: str, limit: int = 10, page: int = 1) -> dict[str, str | int]:
54+
"""Build base parameters common to most API calls."""
55+
self._validate_pagination(limit, page)
56+
return {
57+
"network_id": network,
58+
"limit": limit,
59+
"page": page,
60+
}
61+
62+
def _add_optional_params(self, params: dict, **kwargs: Any) -> dict:
63+
"""Add optional parameters to params dict, excluding None values."""
64+
for key, value in kwargs.items():
65+
if value is not None:
66+
# Convert enum values to strings
67+
params[key] = str(value) if hasattr(value, "value") else value
68+
return params
69+
5270
async def __aenter__(self):
5371
"""Async context manager entry."""
5472
await self.manager.startup()

src/thegraph_token_api/evm.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,8 @@ async def get_nft_ownerships(
9090
Returns:
9191
NFTOwnershipsResponse with validated data
9292
"""
93-
self._validate_pagination(limit, page)
94-
params = {"network_id": self.network, "limit": limit, "page": page}
95-
if token_standard:
96-
params["token_standard"] = str(token_standard)
93+
params = self._build_base_params(self.network, limit, page)
94+
self._add_optional_params(params, token_standard=token_standard)
9795

9896
response = await self.manager.get(
9997
f"{self.base_url}/nft/ownerships/evm/{address}",

src/thegraph_token_api/models.py

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,7 @@
1313

1414
@dataclass
1515
class BaseModel:
16-
"""Base model with dict-like access for backward compatibility."""
17-
18-
def __getitem__(self, key):
19-
"""Support dictionary-style access for backward compatibility."""
20-
return getattr(self, key, None)
21-
22-
def get(self, key, default=None):
23-
"""Support .get() method for backward compatibility."""
24-
return getattr(self, key, default)
16+
"""Base model class."""
2517

2618

2719
@dataclass
@@ -139,18 +131,6 @@ class Transfer(BaseModel):
139131
symbol: str | None = None
140132
decimals: float | None = None
141133

142-
def __getitem__(self, key):
143-
"""Support dictionary-style access with 'from' key mapping."""
144-
if key == "from":
145-
return self.from_address
146-
return super().__getitem__(key)
147-
148-
def get(self, key, default=None):
149-
"""Support .get() method with 'from' key mapping."""
150-
if key == "from":
151-
return self.from_address
152-
return super().get(key, default)
153-
154134

155135
@dataclass
156136
class SolanaTransfer(BaseModel):
@@ -223,22 +203,6 @@ class NFTActivity(BaseModel):
223203
transfer_type: str | None = None
224204
token_standard: str | None = None
225205

226-
def __getitem__(self, key):
227-
"""Support dictionary-style access with special key mappings."""
228-
if key == "@type":
229-
return self.activity_type
230-
if key == "from":
231-
return self.from_address
232-
return super().__getitem__(key)
233-
234-
def get(self, key, default=None):
235-
"""Support .get() method with special key mappings."""
236-
if key == "@type":
237-
return self.activity_type
238-
if key == "from":
239-
return self.from_address
240-
return super().get(key, default)
241-
242206

243207
@dataclass
244208
class Token(BaseModel):

0 commit comments

Comments
 (0)