Skip to content

Commit 640f570

Browse files
codebydivineclaude
andcommitted
feat: add async context manager support to TokenAPI
- Implement __aenter__ and __aexit__ methods for proper async context manager protocol - Enables proper HTTP client lifecycle management with 'async with TokenAPI() as api:' syntax - Resolves "TokenAPI object does not support the asynchronous context manager protocol" error - Maintains backward compatibility with existing direct instantiation usage - Updated documentation with context manager examples 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 26276b9 commit 640f570

File tree

2 files changed

+17
-11
lines changed

2 files changed

+17
-11
lines changed

src/thegraph_token_api/logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ def get_logger(name: str) -> BoundLogger:
2424
logger_factory=structlog.stdlib.LoggerFactory(),
2525
wrapper_class=structlog.stdlib.BoundLogger,
2626
cache_logger_on_first_use=True,
27-
)
27+
)

src/thegraph_token_api/simple.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -329,32 +329,29 @@ class TokenAPI:
329329
- Clean data returns (no response unwrapping)
330330
- Smart defaults
331331
- Separated EVM/SVM methods
332+
- Async context manager support
332333
333334
Example:
334335
```python
335336
from thegraph_token_api import TokenAPI, SwapPrograms, Protocol
336337
338+
# Method 1: Direct usage (handles resource cleanup automatically)
337339
api = TokenAPI() # Auto-loads API key from .env
338340
339341
# EVM (Ethereum, Polygon, BSC, etc.)
340342
eth_balances = await api.evm.balances("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
341343
eth_nfts = await api.evm.nfts.ownerships("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
342-
nft_collection = await api.evm.nfts.collection("0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb")
343-
nft_activities = await api.evm.nfts.activities("0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb")
344344
eth_swaps = await api.evm.swaps(protocol=Protocol.UNISWAP_V3, limit=10)
345345
346346
# SVM (Solana)
347347
sol_balances = await api.svm.balances(mint="So11111111111111111111111111111111111111112")
348348
sol_swaps = await api.svm.swaps(program_id=SwapPrograms.RAYDIUM, limit=10)
349-
sol_transfers = await api.svm.transfers(mint="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") # pragma: allowlist secret
350349
351-
# Unified Price API
352-
eth_price = await api.price.get(Currency.ETH) # Get current ETH price
353-
sol_price = await api.price.get(Currency.SOL) # Get current SOL price
354-
eth_stats = await api.price.get(Currency.ETH, include_stats=True) # With confidence metrics
355-
356-
# Utility
357-
health = await api.health()
350+
# Method 2: Context manager usage (recommended for long-lived instances)
351+
async with TokenAPI() as api:
352+
eth_price = await api.price.get(Currency.ETH)
353+
sol_price = await api.price.get(Currency.SOL)
354+
health = await api.health()
358355
```
359356
"""
360357

@@ -389,6 +386,15 @@ def __init__(
389386
self.svm = SVMWrapper(self)
390387
self.price = UnifiedPriceAPI(self)
391388

389+
async def __aenter__(self) -> "TokenAPI":
390+
"""Async context manager entry."""
391+
await self._api.__aenter__()
392+
return self
393+
394+
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
395+
"""Async context manager exit."""
396+
await self._api.__aexit__(exc_type, exc_val, exc_tb)
397+
392398
def _extract_data(self, response: Any) -> list[dict[str, Any]]:
393399
"""Extract clean data from API response."""
394400
if hasattr(response, "data") and isinstance(response.data, dict):

0 commit comments

Comments
 (0)