Conversation
📝 WalkthroughWalkthroughAdds oracle streaming support and RFQ gateway RPC bindings, regenerates many protobuf descriptors to align with Injective v1.19.0, updates package/version metadata and Makefile clone target, adds example scripts and tests, and fixes a stub assignment bug in the indexer gRPC oracle stream implementation. Changes
Sequence Diagram(s)sequenceDiagram
participant Example as Example Script
participant Client as IndexerClient
participant StreamAPI as IndexerGrpcOracleStream
participant GRPC as InjectiveOracleRPC (gRPC Server)
participant Servicer as Test/Prod Servicer
Example->>Client: listen_oracle_list_updates(callback, filters)
Client->>StreamAPI: stream_oracle_list(callback, filters)
StreamAPI->>GRPC: StreamOracleList(request{oracle_type,symbols})
GRPC->>Servicer: deliver StreamOracleList request
Servicer-->>GRPC: yield StreamOracleListResponse (stream)
GRPC-->>StreamAPI: stream response frames
StreamAPI->>Client: invoke callback per event
Client->>Example: callback(event)
Note right of Example: Example prints/processes events
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
pyinjective/proto/google/rpc/context/attribute_context_pb2.py (1)
21-62: Add a generation consistency guard for protobuf artifacts.Given this file is generated and contains tightly coupled byte blobs plus offset constants, add a CI check that regenerates protos and fails on diff. This prevents release drift where descriptor bytes and
_serialized_*metadata get out of sync.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pyinjective/proto/google/rpc/context/attribute_context_pb2.py` around lines 21 - 62, The generated protobuf file (DESCRIPTOR and the _serialized_*/_loaded_options entries such as _globals['_ATTRIBUTECONTEXT'] and _globals['_ATTRIBUTECONTEXT_PEER_LABELSENTRY']) can drift from source protos; add a CI job that runs the project's proto regeneration script (the same command that produces attribute_context_pb2.py), diffs the regenerated output against the checked-in files, and fails the build if there are any differences so descriptor bytes and _serialized_* offsets cannot get out of sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/exchange_client/oracle_rpc/6_StreamPricesByMarkets.py`:
- Around line 22-43: The example calls client.all_derivative_markets() which
doesn't exist; replace that call with the actual method
fetch_derivative_markets() and adjust any handling if the return shape differs
(e.g., ensure you select the same market by the hex key and use market.id when
passing market_ids to client.listen_oracle_prices_by_markets_updates); update
the reference to the market variable only if fetch_derivative_markets() returns
a different mapping/sequence so the index/key lookup remains correct.
In `@Makefile`:
- Line 29: The Makefile's hardcoded git clone command referencing
"https://github.com/InjectiveLabs/injective-indexer.git -b v1.19.0" is failing
because that repository URL is not accessible; update the clone target to point
to the correct, accessible repository URL or make the repository URL and branch
configurable (e.g., via a MAKEVAR like
INJECTIVE_INDEXER_REPO/INJECTIVE_INDEXER_REF) so builds don't hard-fail—locate
the git clone line in the Makefile and replace the broken URL/branch with the
verified repository URL or a variable that can be overridden in CI, and add a
short comment or fallback to prevent silent failures.
In `@pyinjective/proto/google/rpc/context/attribute_context_pb2.py`:
- Around line 53-56: The nested descriptor offsets in
pyinjective/proto/google/rpc/context/attribute_context_pb2.py are inconsistent:
_ATTRIBUTECONTEXT_RESPONSE_HEADERSENTRY has serialized range 1734-1792 while its
parent _ATTRIBUTECONTEXT_RESPONSE is 1795-2107, indicating stale generated
metadata; regenerate this pb2 file from the original .proto using the same
protoc/runtime toolchain used for the project, replace the existing
attribute_context_pb2.py with the newly generated file, and confirm the
_serialized_start/_serialized_end values for _ATTRIBUTECONTEXT_RESPONSE and
_ATTRIBUTECONTEXT_RESPONSE_HEADERSENTRY (and any other nested descriptors) are
now coherent and nested properly.
In `@tests/client/indexer/stream_grpc/test_indexer_grpc_oracle_stream.py`:
- Around line 124-126: Replace the three inline lambda assignments (callback,
error_callback, end_callback) with small named def functions to satisfy lint
E731; implement def callback(update): updates.put_nowait(update), def
error_callback(exception): pytest.fail(str(exception)), and def end_callback():
end_event.set(), then assign those function names to the corresponding variables
(callback, error_callback, end_callback) so behavior is unchanged but
lint-clean.
---
Nitpick comments:
In `@pyinjective/proto/google/rpc/context/attribute_context_pb2.py`:
- Around line 21-62: The generated protobuf file (DESCRIPTOR and the
_serialized_*/_loaded_options entries such as _globals['_ATTRIBUTECONTEXT'] and
_globals['_ATTRIBUTECONTEXT_PEER_LABELSENTRY']) can drift from source protos;
add a CI job that runs the project's proto regeneration script (the same command
that produces attribute_context_pb2.py), diffs the regenerated output against
the checked-in files, and fails the build if there are any differences so
descriptor bytes and _serialized_* offsets cannot get out of sync.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9017ccbb-b4e0-4a7c-baa6-a2618a0498fd
📒 Files selected for processing (35)
CHANGELOG.mdMakefilebuf.gen.yamlexamples/exchange_client/oracle_rpc/5_StreamOracleList.pyexamples/exchange_client/oracle_rpc/6_StreamPricesByMarkets.pypyinjective/client/indexer/grpc_stream/indexer_grpc_oracle_stream.pypyinjective/indexer_client.pypyinjective/proto/exchange/injective_oracle_rpc_pb2.pypyinjective/proto/exchange/injective_oracle_rpc_pb2_grpc.pypyinjective/proto/exchange/injective_rfq_gw_rpc_pb2.pypyinjective/proto/exchange/injective_rfq_gw_rpc_pb2_grpc.pypyinjective/proto/exchange/injective_rfq_rpc_pb2.pypyinjective/proto/exchange/injective_tc_derivatives_rpc_pb2.pypyinjective/proto/google/api/expr/v1alpha1/checked_pb2.pypyinjective/proto/google/api/expr/v1alpha1/eval_pb2.pypyinjective/proto/google/api/expr/v1alpha1/explain_pb2.pypyinjective/proto/google/api/expr/v1alpha1/syntax_pb2.pypyinjective/proto/google/api/expr/v1alpha1/value_pb2.pypyinjective/proto/google/rpc/context/attribute_context_pb2.pypyinjective/proto/google/rpc/status_pb2.pypyinjective/proto/google/type/color_pb2.pypyinjective/proto/google/type/date_pb2.pypyinjective/proto/google/type/datetime_pb2.pypyinjective/proto/google/type/decimal_pb2.pypyinjective/proto/google/type/interval_pb2.pypyinjective/proto/google/type/latlng_pb2.pypyinjective/proto/google/type/localized_text_pb2.pypyinjective/proto/google/type/money_pb2.pypyinjective/proto/google/type/phone_number_pb2.pypyinjective/proto/google/type/postal_address_pb2.pypyinjective/proto/google/type/quaternion_pb2.pypyinjective/proto/google/type/timeofday_pb2.pypyproject.tomltests/client/indexer/configurable_oracle_query_servicer.pytests/client/indexer/stream_grpc/test_indexer_grpc_oracle_stream.py
| async def main() -> None: | ||
| network = Network.testnet() | ||
| client = IndexerClient(network) | ||
| market = (await client.all_derivative_markets())[ | ||
| "0x17ef48032cb24375ba7c2e39f384e56433bcab20cbee9a7357e4cba2eb00abe6" | ||
| ] | ||
|
|
||
| task = asyncio.get_event_loop().create_task( | ||
| client.listen_oracle_prices_by_markets_updates( | ||
| market_ids=[market.id], | ||
| callback=price_event_processor, | ||
| on_end_callback=stream_closed_processor, | ||
| on_status_callback=stream_error_processor, | ||
| ) | ||
| ) | ||
|
|
||
| await asyncio.sleep(delay=60) | ||
| task.cancel() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.get_event_loop().run_until_complete(main()) |
There was a problem hiding this comment.
Fix the example to call a real client method.
Line 25 calls client.all_derivative_markets(), but pyinjective/indexer_client.py only exposes fetch_derivative_markets(). As written, this script will raise AttributeError before the stream starts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/exchange_client/oracle_rpc/6_StreamPricesByMarkets.py` around lines
22 - 43, The example calls client.all_derivative_markets() which doesn't exist;
replace that call with the actual method fetch_derivative_markets() and adjust
any handling if the return shape differs (e.g., ensure you select the same
market by the hex key and use market.id when passing market_ids to
client.listen_oracle_prices_by_markets_updates); update the reference to the
market variable only if fetch_derivative_markets() returns a different
mapping/sequence so the index/key lookup remains correct.
|
|
||
| clone-injective-indexer: | ||
| git clone https://github.com/InjectiveLabs/injective-indexer.git -b v1.18.59 --depth 1 --single-branch | ||
| git clone https://github.com/InjectiveLabs/injective-indexer.git -b v1.19.0 --depth 1 --single-branch |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
git ls-remote --heads --tags https://github.com/InjectiveLabs/injective-indexer.git v1.19.0Repository: InjectiveLabs/sdk-python
Length of output: 186
Repository at the specified URL is not accessible—the build will fail immediately.
The clone target fails because https://github.com/InjectiveLabs/injective-indexer.git returns "Repository not found" (exit code 128). Verify the correct repository URL and ensure it is accessible before merging.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Makefile` at line 29, The Makefile's hardcoded git clone command referencing
"https://github.com/InjectiveLabs/injective-indexer.git -b v1.19.0" is failing
because that repository URL is not accessible; update the clone target to point
to the correct, accessible repository URL or make the repository URL and branch
configurable (e.g., via a MAKEVAR like
INJECTIVE_INDEXER_REPO/INJECTIVE_INDEXER_REF) so builds don't hard-fail—locate
the git clone line in the Makefile and replace the broken URL/branch with the
verified repository URL or a variable that can be overridden in CI, and add a
short comment or fallback to prevent silent failures.
| _globals['_ATTRIBUTECONTEXT_RESPONSE']._serialized_start=1795 | ||
| _globals['_ATTRIBUTECONTEXT_RESPONSE']._serialized_end=2107 | ||
| _globals['_ATTRIBUTECONTEXT_RESPONSE_HEADERSENTRY']._serialized_start=1734 | ||
| _globals['_ATTRIBUTECONTEXT_RESPONSE_HEADERSENTRY']._serialized_end=1792 |
There was a problem hiding this comment.
Fix inconsistent nested descriptor offsets.
Line 55–56 sets _ATTRIBUTECONTEXT_RESPONSE_HEADERSENTRY to 1734-1792, but its parent _ATTRIBUTECONTEXT_RESPONSE on Line 53–54 is 1795-2107. A nested descriptor range outside its parent indicates corrupted/stale generated metadata.
Please regenerate this pb2 file from the proto source (same protoc/runtime toolchain) so all _serialized_* offsets are recalculated coherently.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pyinjective/proto/google/rpc/context/attribute_context_pb2.py` around lines
53 - 56, The nested descriptor offsets in
pyinjective/proto/google/rpc/context/attribute_context_pb2.py are inconsistent:
_ATTRIBUTECONTEXT_RESPONSE_HEADERSENTRY has serialized range 1734-1792 while its
parent _ATTRIBUTECONTEXT_RESPONSE is 1795-2107, indicating stale generated
metadata; regenerate this pb2 file from the original .proto using the same
protoc/runtime toolchain used for the project, replace the existing
attribute_context_pb2.py with the newly generated file, and confirm the
_serialized_start/_serialized_end values for _ATTRIBUTECONTEXT_RESPONSE and
_ATTRIBUTECONTEXT_RESPONSE_HEADERSENTRY (and any other nested descriptors) are
now coherent and nested properly.
| callback = lambda update: updates.put_nowait(update) | ||
| error_callback = lambda exception: pytest.fail(str(exception)) | ||
| end_callback = lambda: end_event.set() |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ruff check tests/client/indexer/stream_grpc/test_indexer_grpc_oracle_stream.py --select E731Repository: InjectiveLabs/sdk-python
Length of output: 5999
Replace the inline callbacks to keep the test lint-clean.
Ruff flags these assigned lambdas with E731. Small def callbacks are clearer and avoid the lint failure.
♻️ Suggested fix
- callback = lambda update: updates.put_nowait(update)
- error_callback = lambda exception: pytest.fail(str(exception))
- end_callback = lambda: end_event.set()
+ def callback(update):
+ updates.put_nowait(update)
+
+ def error_callback(exception):
+ pytest.fail(str(exception))
+
+ def end_callback():
+ end_event.set()📝 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.
| callback = lambda update: updates.put_nowait(update) | |
| error_callback = lambda exception: pytest.fail(str(exception)) | |
| end_callback = lambda: end_event.set() | |
| def callback(update): | |
| updates.put_nowait(update) | |
| def error_callback(exception): | |
| pytest.fail(str(exception)) | |
| def end_callback(): | |
| end_event.set() |
🧰 Tools
🪛 Ruff (0.15.12)
[error] 124-124: Do not assign a lambda expression, use a def
Rewrite callback as a def
(E731)
[error] 125-125: Do not assign a lambda expression, use a def
Rewrite error_callback as a def
(E731)
[error] 126-126: Do not assign a lambda expression, use a def
Rewrite end_callback as a def
(E731)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/client/indexer/stream_grpc/test_indexer_grpc_oracle_stream.py` around
lines 124 - 126, Replace the three inline lambda assignments (callback,
error_callback, end_callback) with small named def functions to satisfy lint
E731; implement def callback(update): updates.put_nowait(update), def
error_callback(exception): pytest.fail(str(exception)), and def end_callback():
end_event.set(), then assign those function names to the corresponding variables
(callback, error_callback, end_callback) so behavior is unchanged but
lint-clean.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
examples/exchange_client/oracle_rpc/1_StreamPrices.py (1)
31-33: Harden oracle field extraction to avoid opaque runtime errors.Lines 31–33 assume all keys are always present and string-typed. If the payload is partial/unexpected, this can fail with
KeyError/attribute errors instead of a clear message.Proposed defensive extraction
- base_symbol = market["oracleBase"] - quote_symbol = market["oracleQuote"] - oracle_type = market["oracleType"].lower() + base_symbol = market.get("oracleBase") + quote_symbol = market.get("oracleQuote") + oracle_type_raw = market.get("oracleType") + + if not base_symbol or not quote_symbol or not oracle_type_raw: + raise ValueError("Missing oracle fields in derivative market response") + + oracle_type = str(oracle_type_raw).lower()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/exchange_client/oracle_rpc/1_StreamPrices.py` around lines 31 - 33, The extraction of base_symbol, quote_symbol and oracle_type from the market dict (currently using base_symbol = market["oracleBase"], quote_symbol = market["oracleQuote"], oracle_type = market["oracleType"].lower()) is brittle and can raise KeyError/AttributeError; change it to defensively fetch and validate these fields (use market.get("oracleBase"), market.get("oracleQuote"), market.get("oracleType")), verify they are non-empty strings, coerce oracle_type to str then .lower(), and raise a clear ValueError (or log and skip) with the market identifier if any are missing or not strings so runtime failures produce an actionable error message rather than opaque exceptions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@examples/exchange_client/oracle_rpc/1_StreamPrices.py`:
- Around line 31-33: The extraction of base_symbol, quote_symbol and oracle_type
from the market dict (currently using base_symbol = market["oracleBase"],
quote_symbol = market["oracleQuote"], oracle_type =
market["oracleType"].lower()) is brittle and can raise KeyError/AttributeError;
change it to defensively fetch and validate these fields (use
market.get("oracleBase"), market.get("oracleQuote"), market.get("oracleType")),
verify they are non-empty strings, coerce oracle_type to str then .lower(), and
raise a clear ValueError (or log and skip) with the market identifier if any are
missing or not strings so runtime failures produce an actionable error message
rather than opaque exceptions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6bdbad9f-e284-4c63-92f0-873944b5898c
📒 Files selected for processing (2)
examples/exchange_client/oracle_rpc/1_StreamPrices.pyexamples/exchange_client/oracle_rpc/6_StreamPricesByMarkets.py
✅ Files skipped from review due to trivial changes (1)
- examples/exchange_client/oracle_rpc/6_StreamPricesByMarkets.py
Summary by CodeRabbit
New Features
Bug Fixes
Chores
Examples
Tests