Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this project will be documented in this file.

## [1.11.1] - 2025-08-20
### Changed
- Marked the v1 AsyncClient as deprecated

### Fixed
- Fixed the Indexer orderbooks queries in the v1 AsyncClient to include the depth parameter

## [1.11.0] - 2025-07-29
### Added
- Added support for Exchange V2 proto queries and types
Expand Down
24 changes: 16 additions & 8 deletions pyinjective/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ def __init__(
self,
network: Network,
):
warn(
Copy link

Copilot AI Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing import statement for the warn function. The code uses warn() but there's no corresponding import statement visible. This will cause a NameError at runtime.

Copilot uses AI. Check for mistakes.

"AsyncClient from pyinjective.async_client is deprecated. "
"Please use AsyncClient from pyinjective.async_client_v2 instead.",
DeprecationWarning,
stacklevel=2,
)
self.addr = ""
self.number = 0
self.sequence = 0
Expand Down Expand Up @@ -1337,11 +1343,11 @@ async def listen_spot_markets_updates(
market_ids=market_ids,
)

async def fetch_spot_orderbook_v2(self, market_id: str) -> Dict[str, Any]:
return await self.indexer_client.fetch_spot_orderbook_v2(market_id=market_id)
async def fetch_spot_orderbook_v2(self, market_id: str, depth: Optional[int] = None) -> Dict[str, Any]:
return await self.indexer_client.fetch_spot_orderbook_v2(market_id=market_id, depth=depth or 0)

async def fetch_spot_orderbooks_v2(self, market_ids: List[str]) -> Dict[str, Any]:
return await self.indexer_client.fetch_spot_orderbooks_v2(market_ids=market_ids)
async def fetch_spot_orderbooks_v2(self, market_ids: List[str], depth: Optional[int] = None) -> Dict[str, Any]:
return await self.indexer_client.fetch_spot_orderbooks_v2(market_ids=market_ids, depth=depth or 0)

async def fetch_spot_orders(
self,
Expand Down Expand Up @@ -1608,11 +1614,13 @@ async def listen_derivative_market_updates(
market_ids=market_ids,
)

async def fetch_derivative_orderbook_v2(self, market_id: str) -> Dict[str, Any]:
return await self.indexer_client.fetch_derivative_orderbook_v2(market_id=market_id)
async def fetch_derivative_orderbook_v2(self, market_id: str, depth: Optional[int] = None) -> Dict[str, Any]:
return await self.indexer_client.fetch_derivative_orderbook_v2(market_id=market_id, depth=depth or 0)

async def fetch_derivative_orderbooks_v2(self, market_ids: List[str]) -> Dict[str, Any]:
return await self.indexer_client.fetch_derivative_orderbooks_v2(market_ids=market_ids)
async def fetch_derivative_orderbooks_v2(
self, market_ids: List[str], depth: Optional[int] = None
) -> Dict[str, Any]:
return await self.indexer_client.fetch_derivative_orderbooks_v2(market_ids=market_ids, depth=depth or 0)

async def fetch_derivative_orders(
self,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "injective-py"
version = "1.11.0"
version = "1.11.1"
description = "Injective Python SDK, with Exchange API Client"
authors = ["Injective Labs <[email protected]>"]
license = "Apache-2.0"
Expand Down
57 changes: 57 additions & 0 deletions tests/test_async_client_deprecation_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import warnings
from unittest.mock import MagicMock, patch

from pyinjective.core.network import Network


class TestAsyncClientDeprecationWarnings:
@patch("pyinjective.async_client.asyncio.get_event_loop")
@patch("pyinjective.async_client.ChainGrpcChainStream")
@patch("pyinjective.async_client.ChainGrpcExchangeApi")
@patch("pyinjective.async_client.ChainGrpcDistributionApi")
@patch("pyinjective.async_client.ChainGrpcAuthZApi")
@patch("pyinjective.async_client.ChainGrpcAuthApi")
@patch("pyinjective.async_client.ChainGrpcBankApi")
@patch("pyinjective.async_client.IndexerClient")
def test_async_client_deprecation_warning(self, *mocks):
"""Test that creating an AsyncClient instance raises a deprecation warning with correct details."""
# Create a mock network to avoid actual network initialization
mock_network = MagicMock(spec=Network)
mock_network.chain_cookie_assistant = MagicMock()
mock_network.create_chain_grpc_channel = MagicMock()
mock_network.create_chain_stream_grpc_channel = MagicMock()
mock_network.official_tokens_list_url = "https://example.com/tokens.json"

# Import here to avoid early import issues
from pyinjective.async_client import AsyncClient

# Capture warnings
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always") # Ensure all warnings are captured

# Create AsyncClient instance - this should trigger the deprecation warning
client = AsyncClient(network=mock_network)

# Find the AsyncClient deprecation warning
async_client_warnings = [
w
for w in warning_list
if issubclass(w.category, DeprecationWarning)
and "AsyncClient from pyinjective.async_client is deprecated" in str(w.message)
]

# Should have exactly one warning
assert len(async_client_warnings) == 1

warning = async_client_warnings[0]
# Check warning message contains migration advice
assert "Please use AsyncClient from pyinjective.async_client_v2 instead" in str(warning.message)
# Check warning category
assert warning.category == DeprecationWarning
# Check stacklevel is working correctly (should point to this test file)
assert "test_async_client_deprecation_warnings.py" in warning.filename

# Verify the client was still created successfully
assert client is not None
assert hasattr(client, "network")
assert client.network == mock_network
81 changes: 81 additions & 0 deletions tests/test_indexer_client_deprecation_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import warnings
from unittest.mock import MagicMock, patch

from pyinjective.core.network import Network


class TestIndexerClientDeprecationWarnings:
@patch("pyinjective.indexer_client.IndexerGrpcSpotStream")
@patch("pyinjective.indexer_client.IndexerGrpcPortfolioStream")
@patch("pyinjective.indexer_client.IndexerGrpcOracleStream")
@patch("pyinjective.indexer_client.IndexerGrpcMetaStream")
@patch("pyinjective.indexer_client.IndexerGrpcExplorerStream")
@patch("pyinjective.indexer_client.IndexerGrpcDerivativeStream")
@patch("pyinjective.indexer_client.IndexerGrpcAuctionStream")
@patch("pyinjective.indexer_client.IndexerGrpcAccountStream")
@patch("pyinjective.indexer_client.IndexerGrpcSpotApi")
@patch("pyinjective.indexer_client.IndexerGrpcPortfolioApi")
@patch("pyinjective.indexer_client.IndexerGrpcOracleApi")
@patch("pyinjective.indexer_client.IndexerGrpcMetaApi")
@patch("pyinjective.indexer_client.IndexerGrpcInsuranceApi")
@patch("pyinjective.indexer_client.IndexerGrpcExplorerApi")
@patch("pyinjective.indexer_client.IndexerGrpcDerivativeApi")
@patch("pyinjective.indexer_client.IndexerGrpcAuctionApi")
@patch("pyinjective.indexer_client.IndexerGrpcAccountApi")
def test_listen_derivative_positions_updates_deprecation_warning(self, *mocks):
"""Test that calling listen_derivative_positions_updates raises a deprecation warning."""
# Create a mock network to avoid actual network initialization
mock_network = MagicMock(spec=Network)
mock_network.exchange_cookie_assistant = MagicMock()
mock_network.explorer_cookie_assistant = MagicMock()
mock_network.create_exchange_grpc_channel = MagicMock()
mock_network.create_explorer_grpc_channel = MagicMock()

# Import here to avoid early import issues
from pyinjective.indexer_client import IndexerClient

# Create IndexerClient instance
client = IndexerClient(network=mock_network)

# Mock the derivative_stream_api.stream_positions method to avoid actual streaming
client.derivative_stream_api.stream_positions = MagicMock()

# Capture warnings
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always") # Ensure all warnings are captured

# Mock callback function
mock_callback = MagicMock()

# Call the deprecated method - this should trigger the deprecation warning
client.listen_derivative_positions_updates(
callback=mock_callback, market_ids=["market_1"], subaccount_ids=["subaccount_1"]
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix: await the coroutine so the DeprecationWarning is actually emitted (matches CI failure).

IndexerClient.listen_derivative_positions_updates is async. The test currently calls it without awaiting, so the function body (and warning) never executes, causing the CI failure. Wrap the call in asyncio.run(...) (and make stream_positions an AsyncMock) to execute it.

+import asyncio
-from unittest.mock import MagicMock, patch
+from unittest.mock import MagicMock, patch, AsyncMock
@@
-        client.derivative_stream_api.stream_positions = MagicMock()
+        client.derivative_stream_api.stream_positions = AsyncMock()
@@
-            client.listen_derivative_positions_updates(
-                callback=mock_callback, market_ids=["market_1"], subaccount_ids=["subaccount_1"]
-            )
+            asyncio.run(
+                client.listen_derivative_positions_updates(
+                    callback=mock_callback, market_ids=["market_1"], subaccount_ids=["subaccount_1"]
+                )
+            )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Create IndexerClient instance
client = IndexerClient(network=mock_network)
# Mock the derivative_stream_api.stream_positions method to avoid actual streaming
client.derivative_stream_api.stream_positions = MagicMock()
# Capture warnings
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always") # Ensure all warnings are captured
# Mock callback function
mock_callback = MagicMock()
# Call the deprecated method - this should trigger the deprecation warning
client.listen_derivative_positions_updates(
callback=mock_callback, market_ids=["market_1"], subaccount_ids=["subaccount_1"]
)
import asyncio
from unittest.mock import MagicMock, patch, AsyncMock
# Create IndexerClient instance
client = IndexerClient(network=mock_network)
# Mock the derivative_stream_api.stream_positions method to avoid actual streaming
client.derivative_stream_api.stream_positions = AsyncMock()
# Capture warnings
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always") # Ensure all warnings are captured
# Mock callback function
mock_callback = MagicMock()
# Call the deprecated method - this should trigger the deprecation warning
asyncio.run(
client.listen_derivative_positions_updates(
callback=mock_callback, market_ids=["market_1"], subaccount_ids=["subaccount_1"]
)
)
🤖 Prompt for AI Agents
In tests/test_indexer_client_deprecation_warnings.py around lines 37 to 53, the
test calls the async IndexerClient.listen_derivative_positions_updates without
awaiting so the coroutine body (and its DeprecationWarning) never runs; change
the test to await the coroutine (e.g., wrap the call in asyncio.run(...) or use
the test event loop) and make client.derivative_stream_api.stream_positions an
AsyncMock so the awaited call executes correctly and the warning is emitted and
captured.


# Find the deprecation warning
deprecation_warnings = [
w
for w in warning_list
if issubclass(w.category, DeprecationWarning)
and "This method is deprecated. Use listen_derivative_positions_v2_updates instead" in str(w.message)
]

# Should have exactly one warning
assert len(deprecation_warnings) == 1

warning = deprecation_warnings[0]
# Check warning message contains migration advice
assert "Use listen_derivative_positions_v2_updates instead" in str(warning.message)
# Check warning category
assert warning.category == DeprecationWarning
# Check stacklevel is working correctly (should point to this test file)
assert "test_indexer_client_deprecation_warnings.py" in warning.filename

# Verify the underlying method was still called (functionality preserved)
client.derivative_stream_api.stream_positions.assert_called_once_with(
callback=mock_callback,
on_end_callback=None,
on_status_callback=None,
market_ids=["market_1"],
subaccount_ids=["subaccount_1"],
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Assert the awaited call on AsyncMock for accuracy.

Since stream_positions is awaited, assert the awaited call (not just called).

-            client.derivative_stream_api.stream_positions.assert_called_once_with(
+            client.derivative_stream_api.stream_positions.assert_awaited_once_with(
                 callback=mock_callback,
                 on_end_callback=None,
                 on_status_callback=None,
                 market_ids=["market_1"],
                 subaccount_ids=["subaccount_1"],
             )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Verify the underlying method was still called (functionality preserved)
client.derivative_stream_api.stream_positions.assert_called_once_with(
callback=mock_callback,
on_end_callback=None,
on_status_callback=None,
market_ids=["market_1"],
subaccount_ids=["subaccount_1"],
)
# Verify the underlying method was still called (functionality preserved)
client.derivative_stream_api.stream_positions.assert_awaited_once_with(
callback=mock_callback,
on_end_callback=None,
on_status_callback=None,
market_ids=["market_1"],
subaccount_ids=["subaccount_1"],
)
🤖 Prompt for AI Agents
In tests/test_indexer_client_deprecation_warnings.py around lines 74 to 81, the
test currently uses assert_called_once_with on an AsyncMock for stream_positions
even though the method is awaited; replace the call assertion with the
awaited-call assertion by using the AsyncMock's assert_awaited_once_with and
pass the same keyword args (callback=mock_callback, on_end_callback=None,
on_status_callback=None, market_ids=["market_1"],
subaccount_ids=["subaccount_1"]) so the test verifies the awaited invocation
rather than a plain call.

Loading