Skip to content
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
40 changes: 33 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,41 @@ ENV/
env.bak/
venv.bak/

# IDE specific files
.idea/
.vscode/
*.swp
*.swo

# macOS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Temporary files
*.tmp
*.temp
*~

# Logs
*.log

# API keys and secrets (just in case)
.env.local
.env.production
config/secrets.json
secrets.json

# OpenAPI files
openapi_new.yml
openapi_old.yml
openapi_new.yml

# SDK update instructions
#internal files
SDK_UPDATE_INSTRUCTIONS.md

# IDE specific files
.idea/
.vscode/
*.swp
*.swo
# Note: OpenAPI files and SDK instructions are kept in the repository
# for documentation and development reference purposes
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@ All notable changes to the DexPaprika SDK for Python will be documented in this
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.0] - 2025-01-27

### Breaking Changes
- **DEPRECATED**: Global pools method `pools.list()` due to DexPaprika API v1.3.0 changes
- **MIGRATION REQUIRED**: The global `/pools` endpoint now returns `410 Gone`
- All pool operations now require network specification for better performance

### Added
- Automatic fallback for deprecated `pools.list()` method to Ethereum network
- New `reorder` parameter in `tokens.get_pools()` method for reordering pool metrics
- Comprehensive deprecation warnings with migration guidance
- Enhanced error handling for `410 Gone` responses

### Changed
- Updated SDK version to 0.3.0 to reflect API compatibility with DexPaprika v1.3.0
- Improved documentation with migration examples
- Updated user agent string to match new SDK version

### Migration Guide
```python
# Before (deprecated):
pools = client.pools.list()

# After (recommended):
pools = client.pools.list_by_network('ethereum')
pools = client.pools.list_by_network('solana')
pools = client.pools.list_by_network('fantom')

# Token pools with reordering (new feature):
pools = client.tokens.get_pools(
network_id="ethereum",
token_address="0x...",
reorder=True # Makes the specified token primary for all metrics
)
```

## [0.2.0] - 2024-07-01

### Added
Expand Down
54 changes: 51 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,54 @@ A Python client for the DexPaprika API. This SDK provides easy access to real-ti
pip install dexpaprika-sdk

# Or install from source
git clone https://github.com/donbagger/dexpaprika-sdk-python.git
git clone https://github.com/coinpaprika/dexpaprika-sdk-python.git
cd dexpaprika-sdk-python
pip install -e .
```

## Migration Guide (v0.3.0)

**Important:** Version 0.3.0 includes breaking changes due to DexPaprika API v1.3.0 updates.

### Global Pools Endpoint Deprecation

The global `/pools` endpoint has been removed. If you were using `client.pools.list()`, you need to update your code:

**Before (deprecated):**
```python
# This method is deprecated and will show warnings
pools = client.pools.list(limit=10)
```

**After (recommended):**
```python
# Use network-specific methods instead
eth_pools = client.pools.list_by_network("ethereum", limit=10)
solana_pools = client.pools.list_by_network("solana", limit=10)
```

### New Token Pools Features

The `tokens.get_pools()` method now supports a new `reorder` parameter:

```python
# Reorder pools so the specified token becomes primary for all metrics
pools = client.tokens.get_pools(
network_id="ethereum",
token_address="0xa0b86a33e6441b8466395bf92e8aa0cb53ad20aa", # USDC
reorder=True # Makes USDC the primary token for calculations
)
```

### Backward Compatibility

For backward compatibility, the deprecated `pools.list()` method will:
- Show deprecation warnings
- Automatically fall back to Ethereum network
- Continue working until a future version

We strongly recommend updating your code to use network-specific methods for better performance and future compatibility.

## Usage

### Basic Example
Expand All @@ -49,8 +92,13 @@ for network in networks:
stats = client.utils.get_stats()
print(f"DexPaprika stats: {stats.chains} chains, {stats.pools} pools")

# Get top pools by volume
pools = client.pools.list(limit=5, order_by="volume_usd", sort="desc")
# Get top pools by volume (network-specific)
pools = client.pools.list_by_network(
network_id="ethereum",
limit=5,
order_by="volume_usd",
sort="desc"
)
for pool in pools.pools:
token_pair = f"{pool.tokens[0].symbol}/{pool.tokens[1].symbol}" if len(pool.tokens) >= 2 else "Unknown Pair"
print(f"- {token_pair} on {pool.dex_name} ({pool.chain}): ${pool.volume_usd:.2f} volume")
Expand Down
2 changes: 1 addition & 1 deletion dexpaprika_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
Stats
)

__version__ = "0.2.0"
__version__ = "0.3.0"
__all__ = [
"DexPaprikaClient",
# Models
Expand Down
54 changes: 46 additions & 8 deletions dexpaprika_sdk/api/pools.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import List, Optional, Dict, Any, Set
import warnings

from .base import BaseAPI
from ..models.pools import (
Expand All @@ -22,7 +23,12 @@ def list(
order_by: str = "volume_usd"
) -> PoolsResponse:
"""
Get a list of top pools across all networks.
DEPRECATED: Get a list of top pools across all networks.

This method is deprecated due to API changes. The global /pools endpoint
has been removed. Use list_by_network(network_id, ...) instead.

For backward compatibility, this method now defaults to Ethereum network.

Args:
page: Page number for pagination
Expand All @@ -35,21 +41,53 @@ def list(

Raises:
ValueError: If any parameter is invalid

Migration Examples:
# Before (deprecated):
pools = client.pools.list()

# After (recommended):
pools = client.pools.list_by_network('ethereum')
pools = client.pools.list_by_network('solana')
"""
# Issue deprecation warning
warnings.warn(
"The pools.list() method is deprecated. The global /pools endpoint has been "
"removed in API v1.3.0. Use pools.list_by_network(network_id) instead. "
"This method now defaults to Ethereum network for backward compatibility. "
"Examples: client.pools.list_by_network('ethereum'), "
"client.pools.list_by_network('solana')",
DeprecationWarning,
stacklevel=2
)

# Validate parameters
self._validate_range("page", page, min_val=0)
self._validate_range("limit", limit, min_val=1, max_val=100)
self._validate_enum("sort", sort, self.VALID_SORT_VALUES)
self._validate_enum("order_by", order_by, self.VALID_ORDER_BY_VALUES)

# Get top pools
params = {"page": page, "limit": limit, "sort": sort, "order_by": order_by}
data = self._get("/pools", params=params)

# ensure pools exists
if 'pools' not in data: data['pools'] = []
try:
# Attempt to call the deprecated endpoint first for debugging/testing
params = {"page": page, "limit": limit, "sort": sort, "order_by": order_by}
data = self._get("/pools", params=params)

return PoolsResponse(**data)
# ensure pools exists
if 'pools' not in data: data['pools'] = []

return PoolsResponse(**data)

except Exception as e:
# If we get a 410 Gone or any other error, fall back to Ethereum
# Check if it's a 410 Gone status specifically
if hasattr(e, 'response') and hasattr(e.response, 'status_code') and e.response.status_code == 410:
# Provide a more specific error message for 410 Gone
print("WARNING: The global /pools endpoint has been permanently removed (410 Gone). "
"Falling back to Ethereum network. Please update your code to use "
"pools.list_by_network(network_id) instead.")

# Fall back to Ethereum network for backward compatibility
return self.list_by_network("ethereum", page=page, limit=limit, sort=sort, order_by=order_by)

def list_by_network(
self,
Expand Down
5 changes: 5 additions & 0 deletions dexpaprika_sdk/api/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def get_pools(
sort: str = "desc",
order_by: str = "volume_usd",
address: Optional[str] = None,
reorder: Optional[bool] = None,
) -> PoolsResponse:
"""
Get a list of top liquidity pools for a specific token on a network.
Expand All @@ -58,6 +59,9 @@ def get_pools(
order_by: Field to order by ("volume_usd", "price_usd", "transactions",
"last_price_change_usd_24h", "created_at")
address: Filter pools that contain this additional token address
reorder: If true, reorders the pool so that the specified token becomes
the primary token for all metrics and calculations. Useful when
the provided token is not the first token in the pool.

Returns:
Response containing a list of pools for the given token
Expand All @@ -79,6 +83,7 @@ def get_pools(
"sort": sort,
"order_by": order_by,
"address": address,
"reorder": reorder,
}
params = self._clean_params(params)

Expand Down
2 changes: 1 addition & 1 deletion dexpaprika_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(
self,
base_url: str = "https://api.dexpaprika.com",
session: Optional[requests.Session] = None,
user_agent: str = "DexPaprika-SDK-Python/0.1.0",
user_agent: str = "DexPaprika-SDK-Python/0.3.0",
max_retries: int = 4,
backoff_times: List[float] = None,
):
Expand Down
41 changes: 31 additions & 10 deletions tests/test_all_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,25 @@ def test_utils_get_stats(client):
assert hasattr(stats, 'tokens')

# Pools API tests
def test_pools_list(client):
pools_response = client.pools.list(limit=5)
assert pools_response is not None
assert hasattr(pools_response, 'pools')
assert len(pools_response.pools) > 0

def test_pools_list_by_network(client, test_data):
def test_pools_list_deprecated(client):
"""Test the deprecated global pools method with deprecation warning."""
import warnings
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
pools_response = client.pools.list(limit=5)
assert pools_response is not None
assert hasattr(pools_response, 'pools')
assert len(pools_response.pools) > 0
# Check that a deprecation warning was issued
assert len(w) > 0
assert any("deprecated" in str(warning.message).lower() for warning in w)

def test_pools_list_by_network_primary(client, test_data):
"""Test the primary pools list method using network-specific endpoint."""
pools_response = client.pools.list_by_network(test_data["ethereum_network"], limit=5)
assert pools_response is not None
assert hasattr(pools_response, 'pools')
assert len(pools_response.pools) > 0

def test_dexes_list(client, test_data):
dexes_response = client.dexes.list(test_data["ethereum_network"])
Expand Down Expand Up @@ -121,6 +130,17 @@ def test_tokens_get_pools(client, test_data):
assert token_pools is not None
assert hasattr(token_pools, 'pools')

def test_tokens_get_pools_with_reorder(client, test_data):
"""Test the tokens.get_pools method with the new reorder parameter."""
token_pools = client.tokens.get_pools(
test_data["test_pool_network"],
test_data["test_token_address"],
limit=5,
reorder=True
)
assert token_pools is not None
assert hasattr(token_pools, 'pools')

# Search API tests
def test_search_search(client):
search_results = client.search.search("Jockey")
Expand Down Expand Up @@ -149,15 +169,16 @@ def test_search_search(client):
test_networks_list,
test_networks_list_dexes,
test_utils_get_stats,
test_pools_list,
test_pools_list_by_network,
test_pools_list_deprecated,
test_pools_list_by_network_primary,
test_dexes_list,
test_pools_list_by_dex,
test_pools_get_details,
test_pools_get_ohlcv,
test_pools_get_transactions,
test_tokens_get_details,
test_tokens_get_pools,
test_tokens_get_pools_with_reorder,
test_search_search
]

Expand All @@ -167,7 +188,7 @@ def test_search_search(client):
for test_func in test_functions:
print(f"Testing {test_func.__name__}...")
try:
if test_func.__name__ == "test_networks_list" or test_func.__name__ == "test_utils_get_stats" or test_func.__name__ == "test_pools_list" or test_func.__name__ == "test_search_search":
if test_func.__name__ in ["test_networks_list", "test_utils_get_stats", "test_pools_list_deprecated", "test_search_search"]:
test_func(client)
else:
test_func(client, test_data)
Expand Down
Loading