Skip to content

Conversation

@danieljrc888
Copy link
Contributor

@danieljrc888 danieljrc888 commented Sep 26, 2025

Related #57

Fixes: DXP-687

What

  • Add payload to genlayer exception to improve debugging capabilities
  • Raise with additional payload in make request method

Example: Accessing the payload

try:
  print(f"Calling sim_getTransactionsForAddress with wallet: {wallet_address}")
  response = client.provider.make_request(
    method="sim_getTransactionsForAddress", params=[wallet_address]
  )

except GenLayerError as e:
  payload = e.payload
  if payload is not None and "response" in payload:
    response = e.payload["response"]
    print(f"Response: {response.text}")

Summary by CodeRabbit

  • New Features

    • Errors now carry optional contextual payloads for easier troubleshooting.
    • “Finalized” is recognized as a decided transaction state, improving status handling.
  • Refactor

    • Consolidated resource loading and response preview construction; no functional changes.
  • Style

    • Minor formatting and line-wrapping cleanups across modules.
  • Tests

    • Reformatted unit tests for readability; no changes to test behavior or coverage.

@coderabbitai
Copy link

coderabbitai bot commented Sep 26, 2025

Walkthrough

Consolidates ABI file resource loading, introduces a payload-capable GenLayerError, updates provider to attach the raw response in JSON decode errors, adds TransactionStatus.FINALIZED to decided states, and reformats several unit tests without changing behavior.

Changes

Cohort / File(s) Summary
Consensus ABI resource loading
genlayer_py/consensus/abi/__init__.py
Combined two importlib.resources as_file context managers into a single multi-binding block; no behavioral changes.
Exceptions enhancement
genlayer_py/exceptions.py
Expanded GenLayerError to accept an optional payload dict and store it on the instance; added initializer and attribute.
Provider error payload on JSON decode
genlayer_py/provider/provider.py
On invalid JSON, now raises GenLayerError with payload={"response": response}; minor formatting change for response preview construction.
Transaction decided states
genlayer_py/types/transactions.py
Added TransactionStatus.FINALIZED to DECIDED_STATES; reformatted list and helper without semantic change beyond the added status.
Tests formatting only
tests/unit/transactions/test_wait_for_transaction_receipt.py
Reflowed lists and assertions; spacing/line-break tweaks only, no logic changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client Code
  participant P as GenLayerProvider
  participant S as Remote Service

  C->>P: make_request(payload)
  P->>S: HTTP POST payload
  S-->>P: HTTP response
  alt JSON parse success
    P-->>C: parsed JSON result
  else JSON parse fails
    note over P: Build response_preview<br/>Attach payload={"response": response}
    P-->>C: raise GenLayerError(message, payload)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • cristiam86

Poem

A whisk of bytes, a hop through logs,
I carry payloads past the fogs.
FINALIZED now joins the queue—
A tidy burrow, errors too.
With ABI paths neatly aligned,
I thump approval, code refined. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly captures the primary change of the pull request by stating that a payload is being added to exceptions to improve debugging, which directly aligns with the core code modifications and PR objectives. It is clear, specific, and omits extraneous details, making it easily understandable when scanning the project history.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dxp-687-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@danieljrc888 danieljrc888 self-assigned this Sep 26, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
genlayer_py/exceptions.py (1)

25-27: Preserve GenLayerError’s backward-compatible signature

GenLayerError used to accept any positional args. Tightening the signature to just (message, payload=None) risks breaking existing call sites that passed extra context positionally. Please continue to forward any additional args to Exception while still capturing payload.

-    def __init__(self, message: str, payload: Optional[dict[str, Any]] = None):
-        super().__init__(message)
-        self.payload = payload
+    def __init__(
+        self,
+        message: str,
+        payload: Optional[dict[str, Any]] = None,
+        *args: Any,
+    ):
+        if payload is None:
+            super().__init__(message, *args)
+        else:
+            super().__init__(message, payload, *args)
+        self.payload = payload
tests/unit/transactions/test_wait_for_transaction_receipt.py (3)

225-228: Drop the explicit comparison to True

Ruff flags this pattern (E712), and it’s cleaner to assert the predicate directly.

-        for status_num in decided_status_numbers:
-            assert (
-                is_decided_state(status_num) == True
-            ), f"Status {status_num} should be decided"
+        for status_num in decided_status_numbers:
+            assert is_decided_state(
+                status_num
+            ), f"Status {status_num} should be decided"

243-246: Invert the predicate without comparing to False

Same Ruff E712 warning here—prefer not predicate over == False.

-        for status_num in non_decided_status_numbers:
-            assert (
-                is_decided_state(status_num) == False
-            ), f"Status {status_num} should not be decided"
+        for status_num in non_decided_status_numbers:
+            assert not is_decided_state(
+                status_num
+            ), f"Status {status_num} should not be decided"

254-256: Same clean-up for the invalid-status branch

Applying the same simplification keeps the test consistent and quiets Ruff.

             if status is not None:
-                assert (
-                    is_decided_state(status) == False
-                ), f"Invalid status {status} should not be decided"
+                assert not is_decided_state(
+                    status
+                ), f"Invalid status {status} should not be decided"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7d012a and c1d287a.

📒 Files selected for processing (5)
  • genlayer_py/consensus/abi/__init__.py (1 hunks)
  • genlayer_py/exceptions.py (1 hunks)
  • genlayer_py/provider/provider.py (1 hunks)
  • genlayer_py/types/transactions.py (1 hunks)
  • tests/unit/transactions/test_wait_for_transaction_receipt.py (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
genlayer_py/provider/provider.py (1)
genlayer_py/exceptions.py (1)
  • GenLayerError (4-27)
tests/unit/transactions/test_wait_for_transaction_receipt.py (3)
tests/unit/conftest.py (1)
  • mock_client (23-80)
genlayer_py/transactions/actions.py (2)
  • get_transaction (108-137)
  • wait_for_transaction_receipt (68-105)
genlayer_py/types/transactions.py (2)
  • TransactionStatus (14-28)
  • is_decided_state (75-78)
🪛 Ruff (0.13.1)
tests/unit/transactions/test_wait_for_transaction_receipt.py

227-227: Avoid equality comparisons to True; use is_decided_state(status_num): for truth checks

Replace with is_decided_state(status_num)

(E712)


245-245: Avoid equality comparisons to False; use not is_decided_state(status_num): for false checks

Replace with not is_decided_state(status_num)

(E712)


255-255: Avoid equality comparisons to False; use not is_decided_state(status): for false checks

Replace with not is_decided_state(status)

(E712)

🔇 Additional comments (1)
genlayer_py/types/transactions.py (1)

65-78: LGTM — FINALIZED belongs in DECIDED_STATES.

Including TransactionStatus.FINALIZED in the decided bucket makes sense and keeps the number/name lookups consistent. No further action needed.

Comment on lines +4 to +21
with (
importlib.resources.as_file(
importlib.resources.files("genlayer_py.consensus.abi").joinpath(
"consensus_data_abi.json"
)
) as path,
open(path, "r", encoding="utf-8") as f,
):
CONSENSUS_DATA_ABI = json.load(f)

with importlib.resources.as_file(
importlib.resources.files("genlayer_py.consensus.abi").joinpath(
"consensus_main_abi.json"
)
) as path, open(path, "r", encoding="utf-8") as f:
with (
importlib.resources.as_file(
importlib.resources.files("genlayer_py.consensus.abi").joinpath(
"consensus_main_abi.json"
)
) as path,
open(path, "r", encoding="utf-8") as f,
):
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Avoid Python 3.10-only with (...) syntax unless you’ve dropped 3.9 support.

Using parentheses around multiple context managers (Line 4) is only valid starting in Python 3.10. If the package still supports Python 3.9 (or earlier), this will raise a SyntaxError at import time and break every consumer. Please stick to the nested with form or otherwise confirm that requires-python has been bumped to >=3.10 across the project before landing this.

🤖 Prompt for AI Agents
In genlayer_py/consensus/abi/__init__.py around lines 4 to 21, the code uses the
Python 3.10-only "with (a, b):" multiple-context-manager syntax which will raise
SyntaxError on Python 3.9; change these to nested with statements (open the
resource with importlib.resources.as_file(...) as path: then inside that block
open(path, "r", encoding="utf-8") as f:) for each file load, or alternatively
ensure the project's requires-python metadata has been raised to >=3.10 before
keeping the current syntax.

Comment on lines +41 to 49
response_preview = (
response.text[:500]
if len(response.text) <= 500
else f"{response.text[:500]}..."
)
raise GenLayerError(
f"{method} returned invalid JSON: {err}. Response content: {response_preview}"
f"{method} returned invalid JSON: {err}. Response content: {response_preview}",
payload={"response": response},
) from err
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid storing the raw Response object in payload

Keeping the requests.Response instance in GenLayerError.payload makes the payload non‑serializable and exposes request headers (often containing credentials) when downstream tooling logs or forwards the payload. That breaks observability pipelines and increases leakage risk. Please persist only primitive, serializable fields (status code, headers copy, truncated body) so callers can safely inspect the data.

         except ValueError as err:
             response_preview = (
                 response.text[:500]
                 if len(response.text) <= 500
                 else f"{response.text[:500]}..."
             )
+            response_payload = {
+                "status_code": response.status_code,
+                "headers": dict(response.headers),
+                "body_preview": response_preview,
+            }
             raise GenLayerError(
                 f"{method} returned invalid JSON: {err}. Response content: {response_preview}",
-                payload={"response": response},
+                payload=response_payload,
             ) from err
📝 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
response_preview = (
response.text[:500]
if len(response.text) <= 500
else f"{response.text[:500]}..."
)
raise GenLayerError(
f"{method} returned invalid JSON: {err}. Response content: {response_preview}"
f"{method} returned invalid JSON: {err}. Response content: {response_preview}",
payload={"response": response},
) from err
except ValueError as err:
response_preview = (
response.text[:500]
if len(response.text) <= 500
else f"{response.text[:500]}..."
)
response_payload = {
"status_code": response.status_code,
"headers": dict(response.headers),
"body_preview": response_preview,
}
raise GenLayerError(
f"{method} returned invalid JSON: {err}. Response content: {response_preview}",
payload=response_payload,
) from err
🧰 Tools
🪛 Ruff (0.13.1)

46-49: Avoid specifying long messages outside the exception class

(TRY003)

🤖 Prompt for AI Agents
In genlayer_py/provider/provider.py around lines 41 to 49, the GenLayerError
currently stores the raw requests.Response in payload which is non-serializable
and can leak sensitive headers; instead build a serializable payload with
primitive fields only — e.g., include response.status_code,
dict(response.headers) (a shallow copy), a truncated body (use the existing
response_preview), and optionally response.url or reason — and pass that dict as
payload to GenLayerError; remove the raw Response object from the payload.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants