Skip to content

Conversation

@mukundkumarjha
Copy link
Contributor

@mukundkumarjha mukundkumarjha commented Jan 28, 2026

Description:

Related issue(s):

Fixes #1512

Notes for reviewer:

Checklist

  • Documented (Code comments, README, etc.)
  • Tested (unit, integration, etc.)

@github-actions
Copy link

[commit-verification-bot]
Hi, this is VerificationBot.
Your pull request cannot be merged as it has unverified commits.
View your commit verification status: Commits Tab.

To achieve verified status, please read:

Remember, you require a GPG key and each commit must be signed with:
git commit -S -s -m "Your message here"

Thank you for contributing!

From the Hiero Python SDK Team

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 28, 2026

Walkthrough

Adds support for including child transaction records in queries by adding an include_children flag to TransactionRecordQuery, mapping proto child records to TransactionRecord instances, exposing a children field on TransactionRecord, and providing an example and unit test demonstrating the feature.

Changes

Cohort / File(s) Summary
Query Implementation
src/hiero_sdk_python/query/transaction_record_query.py
Added include_children constructor param and set_include_children() method; set transactionGetRecord.include_child_records in _make_request(); added _map_record_list() to convert proto records; updated execute() to map and pass children to TransactionRecord._from_proto(); signature/formats adjusted for status/error mapping.
Data Model
src/hiero_sdk_python/transaction/transaction_record.py
Added public children: List[TransactionId] field; extended _from_proto() to accept and propagate children; minor formatting adjustments in (de)serialization methods.
Examples
examples/transaction/transaction_record_with_children.py
New example demonstrating setting include_children=True, executing TransactionRecordQuery, and iterating over child records.
Tests
tests/unit/transaction_record_query_test.py
Added test_transaction_record_query_with_children_mapping to verify _map_record_list() maps proto child records into TransactionRecord objects.
Changelog
CHANGELOG.md
Added entry under Unreleased noting include_children support and updated maintainer link.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Query as TransactionRecordQuery
    participant Network as Network/Service
    participant Model as TransactionRecord

    Client->>Query: set_transaction_id(id)
    Client->>Query: set_include_children(true)
    Client->>Query: execute(client)

    Query->>Query: _make_request()
    Query->>Network: getTxRecordByTxID(id, include_child_records=true)
    Network-->>Query: response (parent + child records)

    Query->>Query: _map_record_list(child_records)
    Query->>Model: _from_proto(parent_proto, children=[...])
    Model-->>Query: TransactionRecord(with children)
    Query-->>Client: TransactionRecord (parent with children)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The linked issue #512 is about creating a documentation guide for common SDK issues, but this PR implements a feature for include_children support in TransactionRecordQuery—completely unrelated objectives. Either link to the correct issue related to include_children support or update the PR to match the issue #512 documentation requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 78.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The PR description is missing and does not describe any part of the changeset. The feature adds include_children support to TransactionRecordQuery, but the provided description template is incomplete and off-topic. Provide a clear description of the include_children feature, why it's needed, and list the specific changes made (e.g., new parameter, methods, example code).
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and specifically describes the main change: adding support for the include_children feature to TransactionRecordQuery.
Out of Scope Changes check ✅ Passed All code changes focus on implementing include_children feature for TransactionRecordQuery and related transaction record handling, aligning with the stated PR objective of supporting include_children.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

🧪 Unit Test Generation v2 is now available!

We have significantly improved our unit test generation capabilities.

To enable: Add this to your .coderabbit.yaml configuration:

reviews:
  finishing_touches:
    unit_tests:
      enabled: true

Try it out by using the @coderabbitai generate unit tests command on your code files or under ✨ Finishing Touches on the walkthrough!

Have feedback? Share your thoughts on our Discord thread!


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.

Copy link
Contributor

@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: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/hiero_sdk_python/transaction/transaction_record.py (1)

174-185: Critical bug: children parameter is ignored.

The children parameter passed to _from_proto (line 123) is completely overwritten by the local variable at line 174. This means child records passed from TransactionRecordQuery.execute() are never actually stored in the resulting TransactionRecord.

-        children: Optional[List["TransactionRecord"]] = None
         return cls(
             transaction_id=transaction_id,
             ...
-            children=children,
+            children=children,  # Use the parameter, not a new local variable

The fix should remove line 174 entirely so that the children parameter from line 123 is used:

🐛 Proposed fix
         for pending_airdrop in proto.new_pending_airdrops:
             new_pending_airdrops.append(
                 PendingAirdropRecord._from_proto(pending_airdrop)
             )

-        children: Optional[List["TransactionRecord"]] = None
         return cls(
             transaction_id=transaction_id,
             transaction_hash=proto.transactionHash,
src/hiero_sdk_python/query/transaction_record_query.py (1)

90-92: Avoid print() statements in production code.

Using print() for error logging is not appropriate for library code. This can cause unexpected output for SDK users and doesn't integrate with their logging configuration.

Consider using Python's logging module or removing the print statement entirely since the exception is re-raised anyway.

         except Exception as e:
-            print(f"Exception in _make_request: {e}")
             raise

- Formatted client_test.py using Black.

### Added
- Added support for include_children to the TransactionRecordQuery class
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding the issue reference for traceability.

Other entries in this section include issue references (e.g., (#1570), (#1484)). Adding the related issue number would improve traceability.

-- Added support for include_children to the TransactionRecordQuery class
+- Added support for include_children to the TransactionRecordQuery class (`#1512`)
📝 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
- Added support for include_children to the TransactionRecordQuery class
- Added support for include_children to the TransactionRecordQuery class (`#1512`)

Copy link
Contributor

Choose a reason for hiding this comment

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

@mukundkumarjha please add the issue reference in the CHANGELOG entry to keep it consistent and easy to read.

@@ -0,0 +1,33 @@
import os
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 | 🟡 Minor

Unused import.

The os module is imported but never used in this example.

-import os
📝 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
import os

Comment on lines +5 to +23
def main():
# Setup client
client = Client.for_testnet()
# ... (add operator credentials) ...

# 1. Execute a transaction that is likely to have child records
# (e.g., a complex Smart Contract call)
print("Executing transaction...")

# 2. Query the record and explicitly request children
tx_id = "..." # your transaction id

query = (
TransactionRecordQuery()
.set_transaction_id(tx_id)
.set_include_children(True) # The new feature!
)

record = query.execute(client)
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 | 🟠 Major

Example is incomplete and will fail if copy-pasted.

Per coding guidelines, examples must work verbatim for users who copy-paste them. This example has several issues:

  1. Missing operator credentials: Client.for_testnet() without set_operator() will fail on paid queries.
  2. Invalid transaction ID type: Line 15 uses a string "...", but set_transaction_id() expects a TransactionId object.
  3. Missing imports: TransactionId is not imported.
💡 Suggested fix
 import os
+from dotenv import load_dotenv
 from hiero_sdk_python.client import Client
 from hiero_sdk_python.query.transaction_record_query import TransactionRecordQuery
+from hiero_sdk_python.transaction.transaction_id import TransactionId
+from hiero_sdk_python.account.account_id import AccountId
+from hiero_sdk_python.crypto.private_key import PrivateKey

 def main():
+    load_dotenv()
+    
     # Setup client
     client = Client.for_testnet()
-    # ... (add operator credentials) ...
+    operator_id = AccountId.from_string(os.getenv("OPERATOR_ID"))
+    operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY"))
+    client.set_operator(operator_id, operator_key)

     # 1. Execute a transaction that is likely to have child records
     # (e.g., a complex Smart Contract call)
     print("Executing transaction...")
     
     # 2. Query the record and explicitly request children
-    tx_id = "..." # your transaction id
+    # Replace with an actual transaction ID from a previous transaction
+    tx_id = TransactionId.from_string("[email protected]")
     
     query = (
         TransactionRecordQuery()
         .set_transaction_id(tx_id)
         .set_include_children(True) # The new feature!
     )

Comment on lines +196 to +204
def _map_record_list(
self,
proto_records: List[transaction_get_record_pb2.TransactionGetRecordResponse],
) -> List[TransactionRecord]:
records: List[TransactionRecord] = []
for record in proto_records:
records.append(TransactionRecord._from_proto(record, self.transaction_id))

return records
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 | 🟠 Major

Incorrect type hint for proto_records parameter.

The type hint specifies List[transaction_get_record_pb2.TransactionGetRecordResponse], but child_transaction_records from the protobuf response contains TransactionRecord protos, not TransactionGetRecordResponse.

This mismatch is misleading and could cause confusion for future maintainers.

     def _map_record_list(
         self,
-        proto_records: List[transaction_get_record_pb2.TransactionGetRecordResponse],
+        proto_records: List[transaction_record_pb2.TransactionRecord],
     ) -> List[TransactionRecord]:

Also need to add the import:

 from hiero_sdk_python.hapi.services import (
     query_header_pb2,
     transaction_get_record_pb2,
     query_pb2,
+    transaction_record_pb2,
 )


prng_number: Optional[int] = None
prng_bytes: Optional[bytes] = None
children: List[TransactionId] = None
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 | 🔴 Critical

Type annotation inconsistency.

The field is declared as List[TransactionId], but based on the usage in the example (child.receipt.status) and the mapping logic in TransactionRecordQuery._map_record_list(), this should be List[TransactionRecord].

Additionally, per Ruff UP035, typing.List is deprecated in favor of list.

-    children: List[TransactionId] = None
+    children: list["TransactionRecord"] = None
📝 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
children: List[TransactionId] = None
children: list["TransactionRecord"] = None

assert result.transaction_memo == "Test transaction"


from hiero_sdk_python.hapi.services import query_header_pb2, transaction_get_record_pb2
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 | 🟡 Minor

Remove duplicate imports.

This line redefines query_header_pb2 and transaction_get_record_pb2 that were already imported at lines 10 and 14. This will cause linter errors (Ruff F811) and is unnecessary.

-from hiero_sdk_python.hapi.services import query_header_pb2, transaction_get_record_pb2
📝 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
from hiero_sdk_python.hapi.services import query_header_pb2, transaction_get_record_pb2
🧰 Tools
🪛 Ruff (0.14.14)

97-97: Redefinition of unused query_header_pb2 from line 14: query_header_pb2 redefined here

Remove definition: query_header_pb2

(F811)


97-97: Redefinition of unused transaction_get_record_pb2 from line 10: transaction_get_record_pb2 redefined here

Remove definition: transaction_get_record_pb2

(F811)

Comment on lines +98 to +118
def test_transaction_record_query_with_children_mapping(transaction_id):

child_proto = transaction_record_pb2.TransactionRecord(
memo="Child Record"
)
child_proto.transactionID.CopyFrom(transaction_id._to_proto())

record_response = transaction_get_record_pb2.TransactionGetRecordResponse()

record_response.header.nodeTransactionPrecheckCode = ResponseCode.OK

record_response.transactionRecord.memo = "Parent Record"
record_response.transactionRecord.transactionID.CopyFrom(transaction_id._to_proto())

record_response.child_transaction_records.extend([child_proto, child_proto])

query = TransactionRecordQuery(transaction_id)
children = query._map_record_list(record_response.child_transaction_records)

assert len(children) == 2
assert children[0].transaction_memo == "Child Record"
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 | 🟠 Major

Test coverage gaps for the new include_children feature.

Per the coding guidelines, unit tests should verify:

  1. Fluent setters return self: Missing test for set_include_children returning self for chaining.
  2. Backward-compatible defaults: Missing test that include_children defaults to False.
  3. Constructor behavior: Missing test for TransactionRecordQuery(transaction_id, include_children=True).
  4. Request construction: Missing test that _make_request() correctly sets include_child_records on the protobuf.
💚 Suggested additional tests
def test_set_include_children_returns_self(transaction_id):
    """Test that set_include_children returns self for method chaining."""
    query = TransactionRecordQuery(transaction_id)
    result = query.set_include_children(True)
    assert result is query  # Fluent interface check

def test_include_children_default_is_false():
    """Test that include_children defaults to False."""
    query = TransactionRecordQuery()
    assert query.include_children is False

def test_constructor_with_include_children(transaction_id):
    """Test constructor accepts include_children parameter."""
    query = TransactionRecordQuery(transaction_id, include_children=True)
    assert query.include_children is True
    assert query.transaction_id == transaction_id

def test_make_request_includes_children_flag(transaction_id):
    """Test that _make_request sets include_child_records correctly."""
    query = TransactionRecordQuery(transaction_id, include_children=True)
    request = query._make_request()
    assert request.transactionGetRecord.include_child_records is True

Based on learnings: "Assert fluent setters return self", "Assert backward-compatible defaults are maintained", "Test constructor behavior with valid inputs".

record_response.child_transaction_records.extend([child_proto, child_proto])

query = TransactionRecordQuery(transaction_id)
children = query._map_record_list(record_response.child_transaction_records)
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find the transaction_record_query.py file and examine _map_record_list definition
fd "transaction_record_query.py" --type f | head -5

Repository: hiero-ledger/hiero-sdk-python

Length of output: 170


🏁 Script executed:

# Search for _map_record_list definition with context
rg -n "_map_record_list" --type=py -A5 -B2

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2355


🏁 Script executed:

# Search for child_transaction_records definition and usage
rg -n "child_transaction_records" --type=py -C3

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1857


🏁 Script executed:

# Find protobuf files in the repository
fd -e "proto" --type f | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Look at the test file to understand what child_proto is
sed -n '100,115p' tests/unit/transaction_record_query_test.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 766


🏁 Script executed:

# Search for imports in transaction_record_query.py to understand where types come from
head -30 src/hiero_sdk_python/query/transaction_record_query.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1157


🏁 Script executed:

# Search for TransactionRecord proto definition or where transaction_get_record_pb2 comes from
rg -n "transaction_get_record_pb2" --type=py | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1203


🏁 Script executed:

# Find where transaction_record_pb2 and its definitions are
fd -n "transaction_record_pb2" --type f

Repository: hiero-ledger/hiero-sdk-python

Length of output: 303


🏁 Script executed:

# Look for protobuf Python files to understand the field definitions
find . -name "*pb2.py" -type f | grep -E "(transaction_record|transaction_get_record)" | head -10

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Let's check the generated protobuf definitions to see what type child_transaction_records actually is
rg -n "child_transaction_records" --type=py -B5 -A2 | head -50

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2025


🏁 Script executed:

# Look at the full implementation of _map_record_list to see what it actually does with proto_records
sed -n '196,210p' src/hiero_sdk_python/query/transaction_record_query.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 591


🏁 Script executed:

# Search for TransactionRecord._from_proto to understand what it expects
rg -n "_from_proto" --type=py -B2 -A5 | grep -A5 "class TransactionRecord"

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Check the imports in transaction_record_query.py to see what transaction_record_pb2 is
rg -n "transaction_record_pb2\|transaction_get_record_pb2" src/hiero_sdk_python/query/transaction_record_query.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Find the TransactionRecord class definition to see what _from_proto expects
fd "transaction_record.py" --type f

Repository: hiero-ledger/hiero-sdk-python

Length of output: 127


🏁 Script executed:

# Get the signature of TransactionRecord._from_proto
rg -n "def _from_proto" src/hiero_sdk_python/transaction/transaction_record.py -A3

Repository: hiero-ledger/hiero-sdk-python

Length of output: 235


🏁 Script executed:

# Check what imports transaction_record_pb2 in the test
sed -n '1,15p' tests/unit/transaction_record_query_test.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 570


Fix type hint for _map_record_list parameter in production code.

The type annotation for _map_record_list in src/hiero_sdk_python/query/transaction_record_query.py (lines 196-199) is incorrect. The parameter proto_records should be List[transaction_record_pb2.TransactionRecord], not List[transaction_get_record_pb2.TransactionGetRecordResponse].

The implementation passes each record directly to TransactionRecord._from_proto, which expects transaction_record_pb2.TransactionRecord objects. The actual field child_transaction_records in TransactionGetRecordResponse contains TransactionRecord protos, as the test correctly demonstrates. Update the type hint to match the actual implementation.

Copy link
Contributor

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/hiero_sdk_python/account/account_info.py (2)

12-109: Fix staking_info wiring (wrong class + unused variable).
StakingInfo is imported from the protobuf module and then used with .from_proto(), which doesn’t exist. Additionally, the computed staking_info is never assigned to account_info, so it’s always lost. This will either raise at runtime or silently drop staking data.

🐛 Proposed fix
-from hiero_sdk_python.hapi.services.basic_types_pb2 import StakingInfo
+from hiero_sdk_python.staking_info import StakingInfo
...
-        account_info: "AccountInfo" = cls(
+        account_info: "AccountInfo" = cls(
             account_id=AccountId._from_proto(proto.accountID) if proto.accountID else None,
             contract_account_id=proto.contractAccountID,
             is_deleted=proto.deleted,
             proxy_received=Hbar.from_tinybars(proto.proxyReceived),
             key=PublicKey._from_proto(proto.key) if proto.key else None,
             balance=Hbar.from_tinybars(proto.balance),
             receiver_signature_required=proto.receiverSigRequired,
             expiration_time=(
                 Timestamp._from_protobuf(proto.expirationTime) if proto.expirationTime else None
             ),
             auto_renew_period=(
                 Duration._from_proto(proto.autoRenewPeriod) if proto.autoRenewPeriod else None
             ),
             token_relationships=[
                 TokenRelationship._from_proto(relationship)
                 for relationship in proto.tokenRelationships
             ],
             account_memo=proto.memo,
             owned_nfts=proto.ownedNfts,
             max_automatic_token_associations=proto.max_automatic_token_associations,
+            staking_info=(
+                StakingInfo._from_proto(proto.staking_info)
+                if proto.HasField("staking_info")
+                else None
+            ),
         )
-
-        staking_info=(
-           StakingInfo.from_proto(proto.staking_info)
-           if proto.HasField("staking_info")
-           else None
-         )

And in _to_proto:

-            staking_info=(
-            self.staking_info.to_proto()
-            if self.staking_info is not None
-            else None
-          ),
+            staking_info=(
+                self.staking_info._to_proto()
+                if self.staking_info is not None
+                else None
+            ),

161-199: Fix staking_info labels in str/repr.
Current output prints the whole staking_info object for “Staked Account ID”, “Staked Node ID”, and “Decline Staking Reward”. This is misleading.

💡 Suggested adjustment
-            (self.staking_info, "Staked Account ID"),
-            (self.staking_info, "Staked Node ID"),
+            (self.staking_info.staked_account_id if self.staking_info else None, "Staked Account ID"),
+            (self.staking_info.staked_node_id if self.staking_info else None, "Staked Node ID"),
...
-        if self.staking_info is not None:
-            lines.append(f"Decline Staking Reward: {self.staking_info}")
+        if self.staking_info is not None:
+            lines.append(
+                f"Decline Staking Reward: {self.staking_info.decline_reward}"
+            )
...
-            f"staked_node_id={self.staking_info!r}, "
-            f"staked_account_id={self.staking_info!r}"
+            f"staking_info={self.staking_info!r}"
src/hiero_sdk_python/transaction/transaction_record.py (1)

119-186: Children are discarded in _from_proto.
The method accepts children but immediately overwrites it with None, so include‑children never surfaces in returned records.

🐛 Proposed fix
-    def _from_proto(
+    def _from_proto(
         cls,
         proto: transaction_record_pb2.TransactionRecord,
         transaction_id: Optional[TransactionId] = None,
-        children=None,
+        children: Optional[list["TransactionRecord"]] = None,
     ) -> "TransactionRecord":
...
-        children: Optional[List["TransactionRecord"]] = None
         return cls(
             transaction_id=transaction_id,
             transaction_hash=proto.transactionHash,
             transaction_memo=proto.memo,
             transaction_fee=proto.transactionFee,
             receipt=TransactionReceipt._from_proto(proto.receipt, transaction_id),
             token_transfers=token_transfers,
             nft_transfers=nft_transfers,
             transfers=transfers,
             new_pending_airdrops=new_pending_airdrops,
-            children=children,
+            children=children,
             call_result=(
                 ContractFunctionResult._from_proto(proto.contractCallResult)
                 if proto.HasField("contractCallResult")
                 else None
             ),
             prng_number=proto.prng_number,
             prng_bytes=proto.prng_bytes,
         )
src/hiero_sdk_python/query/transaction_record_query.py (1)

90-92: Remove print statement from exception handler.

The print statement introduces a side effect that could clutter logs or leak sensitive information. Exception handling should rely on the caller or logging framework, not direct prints. As per coding guidelines (REVIEW FOCUS 6), side effects like logging/prints should be flagged.

Suggested fix
         except Exception as e:
-            print(f"Exception in _make_request: {e}")
             raise

CHANGELOG.md Outdated
Comment on lines 132 to 136
<<<<<<< HEAD
- Refactored AccountInfo class to use the staking_info
=======
- chore: format tests/unit/mock_server.py with black (#1542)
>>>>>>> upstream
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 | 🔴 Critical

Resolve the merge conflict block before release.
The changelog contains conflict markers, which will break rendering and automation. Please remove the markers and keep the correct entries.

🔧 Suggested resolution
-<<<<<<< HEAD
-- Refactored AccountInfo class to use the staking_info
-=======
-- chore: format tests/unit/mock_server.py with black (`#1542`)
->>>>>>> upstream
+- Refactored AccountInfo class to use the staking_info
+- chore: format tests/unit/mock_server.py with black (`#1542`)
📝 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
<<<<<<< HEAD
- Refactored AccountInfo class to use the staking_info
=======
- chore: format tests/unit/mock_server.py with black (#1542)
>>>>>>> upstream
- Refactored AccountInfo class to use the staking_info
- chore: format tests/unit/mock_server.py with black (`#1542`)

Copy link
Contributor

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/hiero_sdk_python/transaction/transaction_record.py (1)

174-186: Preserve provided child records (currently overwritten to None).

Line 174 resets children to None, discarding the list passed from TransactionRecordQuery.execute(). This breaks the new include_children feature because the parent record will never retain its child records.

🐛 Proposed fix
-        children: Optional[List["TransactionRecord"]] = None
+        if children is None:
+            children = []
         return cls(
             transaction_id=transaction_id,
             transaction_hash=proto.transactionHash,
             transaction_memo=proto.memo,
             transaction_fee=proto.transactionFee,
             receipt=TransactionReceipt._from_proto(proto.receipt, transaction_id),
             token_transfers=token_transfers,
             nft_transfers=nft_transfers,
             transfers=transfers,
             new_pending_airdrops=new_pending_airdrops,
-            children=children,
+            children=children,
             call_result=(
                 ContractFunctionResult._from_proto(proto.contractCallResult)
                 if proto.HasField("contractCallResult")
                 else None
             ),
             prng_number=proto.prng_number,
             prng_bytes=proto.prng_bytes,
         )

@exploreriii exploreriii requested a review from a team January 28, 2026 12:27
return self

def set_include_children(self, include_children):
self.include_children = include_children
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor suggestion consider adding a docstring

self.transaction_id : Optional[TransactionId] = transaction_id

self.transaction_id: Optional[TransactionId] = transaction_id
self.include_children = include_children
Copy link
Contributor

Choose a reason for hiding this comment

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

missing type hint

Suggested change
self.include_children = include_children
self.include_children: Optional[bool] = include_children

def __init__(
self,
transaction_id: Optional[TransactionId] = None,
include_children: bool = False,
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be include_children: Optional[bool] = False


def _map_record_list(
self,
proto_records: List[transaction_get_record_pb2.TransactionGetRecordResponse],
Copy link
Contributor

Choose a reason for hiding this comment

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

must be

Suggested change
proto_records: List[transaction_get_record_pb2.TransactionGetRecordResponse],
proto_records: List[transaction_record_pb2.TransactionRecord],


prng_number: Optional[int] = None
prng_bytes: Optional[bytes] = None
children: List[TransactionId] = None
Copy link
Contributor

Choose a reason for hiding this comment

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

must be

Suggested change
children: List[TransactionId] = None
children: list["TransactionRecord"] = None

cls,
proto: transaction_record_pb2.TransactionRecord,
transaction_id: Optional[TransactionId] = None,
children=None,
Copy link
Contributor

Choose a reason for hiding this comment

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

add type hinting children: Optional[List["TransactionRecord"]]=[]

PendingAirdropRecord._from_proto(pending_airdrop)
)

children: Optional[List["TransactionRecord"]] = None
Copy link
Contributor

Choose a reason for hiding this comment

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

this line can be romove

Copy link
Contributor

@manishdait manishdait left a comment

Choose a reason for hiding this comment

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

@mukundkumarjha, Thanks for PR added some required changes

Copy link
Contributor

@manishdait manishdait left a comment

Choose a reason for hiding this comment

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

@mukundkumarjha, Thanks for PR added some required changes

Copy link
Contributor

@aceppaluni aceppaluni left a comment

Choose a reason for hiding this comment

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

@mukundkumarjha Thank you for your contribution!

I concur with @manishdait with the suggested changes.
If you need assistance please reach out.

@github-actions
Copy link

Hi, this is MergeConflictBot.
Your pull request cannot be merged because it contains merge conflicts.

Please resolve these conflicts locally and push the changes.

To assist you, please read:

Thank you for contributing!


def main():
# Setup client
client = Client.for_testnet()
Copy link
Contributor

Choose a reason for hiding this comment

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

our for testnet mehod does not set the credentials
@classmethod
def for_testnet(cls) -> "Client":
"""
Create a Client configured for Hedera Testnet.

    Note: Operator must be set manually using set_operator().

    Returns:
        Client: A Client instance configured for testnet.
    """
    return cls(Network("testnet"))

I would recommend you use

@classmethod
def from_env(cls, network: Optional[NetworkName] = None) -> "Client":
    """
    Initialize client from environment variables.
    Automatically loads .env file if present.

    Args:
        network (str, optional): Override the network ("testnet", "mainnet", "previewnet").
                                 If not provided, checks 'NETWORK' env var. 
                                 Defaults to 'testnet' if neither is set.

    Raises:
        ValueError: If OPERATOR_ID or OPERATOR_KEY environment variables are not set.

    Example:
        # Defaults to testnet if no env vars set
        client = Client.from_env()
    """

# ... (add operator credentials) ...

# 1. Execute a transaction that is likely to have child records
# (e.g., a complex Smart Contract call)
Copy link
Contributor

Choose a reason for hiding this comment

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

can we add the example, so we can run it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure how to do that, can you please co author

@mukundkumarjha mukundkumarjha marked this pull request as ready for review January 30, 2026 09:18
Copy link
Contributor

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/hiero_sdk_python/transaction/transaction_record.py (1)

123-186: ⚠️ Potential issue | 🔴 Critical

children is discarded, so include_children always yields None.
Line 174 overwrites the children parameter with None, so TransactionRecordQuery.execute() can never populate children and the example will crash when it calls len(record.children).

🔧 Proposed fix
-        children: Optional[List["TransactionRecord"]] = None
+        if children is None:
+            children = []
         return cls(
@@
-            children=children,
+            children=children,

Comment on lines +23 to +31
record = query.execute(client)

# 3. Demonstrate accessing the children
print(f"Parent Transaction ID: {record.transaction_id}")
print(f"Number of child records found: {len(record.children)}")

for i, child in enumerate(record.children):
print(f"Child {i+1} Status: {child.receipt.status}")

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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, find and read the file in question
fd "transaction_record_with_children.py" --type f

Repository: hiero-ledger/hiero-sdk-python

Length of output: 129


🏁 Script executed:

# Check if the file exists and read its content
if [ -f "examples/transaction/transaction_record_with_children.py" ]; then
  wc -l examples/transaction/transaction_record_with_children.py
  echo "---"
  cat -n examples/transaction/transaction_record_with_children.py
else
  echo "File not found"
fi

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1383


🏁 Script executed:

# Verify ResponseCode exists in hiero_sdk_python
find . -type f -name "*.py" | xargs grep -l "class ResponseCode" | head -5

Repository: hiero-ledger/hiero-sdk-python

Length of output: 112


🏁 Script executed:

# Check how ResponseCode is imported in other example files
find examples -type f -name "*.py" -exec grep -l "ResponseCode" {} \; | head -5

Repository: hiero-ledger/hiero-sdk-python

Length of output: 3862


🏁 Script executed:

# Look for patterns of receipt.status usage in examples
rg "receipt\.status" examples --type py -B 2 -A 2 | head -40

Repository: hiero-ledger/hiero-sdk-python

Length of output: 3540


🏁 Script executed:

# Check how ResponseCode is imported in those example files
head -20 examples/tokens/token_fee_schedule_update_transaction_fungible.py | grep -E "^(import|from)" | head -10

Repository: hiero-ledger/hiero-sdk-python

Length of output: 498


🏁 Script executed:

# Check if there's a general pattern for error handling in examples
head -30 examples/tokens/token_create_transaction_token_fee_schedule_key.py | grep -E "^(import|from)" | head -10

Repository: hiero-ledger/hiero-sdk-python

Length of output: 454


🏁 Script executed:

# Verify the ResponseCode import path can be used as suggested
head -5 src/hiero_sdk_python/response_code.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 154


🏁 Script executed:

# Check other transaction_record examples for patterns
find examples -name "*transaction_record*" -type f

Repository: hiero-ledger/hiero-sdk-python

Length of output: 172


🏁 Script executed:

# Look at how examples handle query results without receipt checks (queries vs transactions)
rg "\.execute\(client\)" examples/query --type py -A 3 | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 988


🏁 Script executed:

# Check the other transaction_record query example
cat -n examples/query/transaction_record_query.py | head -40

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1536


🏁 Script executed:

# Verify ResponseCode is used consistently in query examples
rg "ResponseCode" examples/query --type py -B 1 -A 1 | head -30

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2088


Validate child receipt status using ResponseCode enum.

Line 30 prints the raw numeric status without converting to ResponseCode, making it unclear to users whether children succeeded or failed. This contradicts the pattern used throughout examples where all receipt statuses are validated against ResponseCode.SUCCESS.

✅ Suggested improvement
 from hiero_sdk_python.query.transaction_record_query import TransactionRecordQuery
+from hiero_sdk_python.response_code import ResponseCode
@@
     for i, child in enumerate(record.children):
-        print(f"Child {i+1} Status: {child.receipt.status}")
+        status = ResponseCode(child.receipt.status)
+        print(f"Child {i+1} Status: {status.name}")
+        if status != ResponseCode.SUCCESS:
+            print(f"Warning: Child {i+1} failed with status {status.name}")

Comment on lines +196 to +203
def _map_record_list(
self,
proto_records: List[transaction_get_record_pb2.TransactionGetRecordResponse],
) -> List[TransactionRecord]:
records: List[TransactionRecord] = []
for record in proto_records:
records.append(TransactionRecord._from_proto(record, self.transaction_id))

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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, examine the file to understand the context
cat -n src/hiero_sdk_python/query/transaction_record_query.py | head -220 | tail -50

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2151


🏁 Script executed:

# Find the TransactionRecord._from_proto method to understand its signature
fd -e py -path "*/transaction_record*" | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 241


🏁 Script executed:

# Search for TransactionRecord class and _from_proto method
rg -A 10 "def _from_proto" --type py -B 2 | grep -A 10 "TransactionRecord"

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1387


🏁 Script executed:

# Look at the protobuf definition for TransactionGetRecordResponse
fd -e proto | xargs rg -l "TransactionGetRecordResponse" | head -5

Repository: hiero-ledger/hiero-sdk-python

Length of output: 171


🏁 Script executed:

# Get the full TransactionRecord._from_proto method implementation
rg -B 5 -A 30 "def _from_proto" src/hiero_sdk_python/transaction/transaction_record.py | head -60

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1636


🏁 Script executed:

# Check what fields are in the protobuf TransactionGetRecordResponse
fd -name "*.proto" | xargs rg "TransactionGetRecordResponse" -A 10 2>/dev/null | head -40

Repository: hiero-ledger/hiero-sdk-python

Length of output: 3834


🏁 Script executed:

# Look for test file to understand intended behavior
cat -n tests/unit/transaction_record_query_test.py | head -100

Repository: hiero-ledger/hiero-sdk-python

Length of output: 4438


🏁 Script executed:

# Search for how transaction_id is used in TransactionRecord class
rg "transaction_id" src/hiero_sdk_python/transaction/transaction_record.py -B 2 -A 2 | head -50

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2216


🏁 Script executed:

# Find proto files with transaction record definitions
find . -name "*.proto" -type f | xargs grep -l "TransactionGetRecordResponse\|child_transaction_records" 2>/dev/null

Repository: hiero-ledger/hiero-sdk-python

Length of output: 57


🏁 Script executed:

# Search for TransactionGetRecordResponse definition
find . -name "*.proto" -type f -exec grep -l "TransactionGetRecordResponse" {} \; | head -5

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Look for the actual proto definitions in generated Python code
grep -r "child_transaction_records" --include="*.py" | head -10

Repository: hiero-ledger/hiero-sdk-python

Length of output: 461


🏁 Script executed:

# Check what type child_transaction_records actually is
rg "child_transaction_records" -B 3 -A 3 --type py | head -50

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1789


🏁 Script executed:

# Look at the full test to understand the structure
cat tests/unit/transaction_record_query_test.py | sed -n '98,130p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1424


🏁 Script executed:

# Read more of the test file to see if there's verification of child transaction IDs
cat tests/unit/transaction_record_query_test.py | sed -n '98,150p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2312


🏁 Script executed:

# Check the protobuf message structure - look at generated Python code
find . -name "*transaction_record_pb2.py" -o -name "*transaction_get_record_pb2.py" | head -3

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Look at the generated protobuf to understand child_transaction_records structure
rg "class TransactionRecord|child_transaction_records" --type py -A 2 -B 1 | grep -A 5 "child_transaction_records"

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1097


🏁 Script executed:

# Check how child records are used elsewhere in the codebase
rg "child_transaction_records\|children" src/hiero_sdk_python/query/transaction_record_query.py -B 2 -A 2

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Let's look at the full _get_query_response method to see how _map_record_list is called
cat -n src/hiero_sdk_python/query/transaction_record_query.py | sed -n '145,210p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2799


🏁 Script executed:

# Check what the actual type of child_transaction_records is in the protobuf
python3 << 'EOF'
import sys
sys.path.insert(0, '/root')

from hiero_sdk_python.hapi.services import transaction_get_record_pb2

# Inspect the TransactionGetRecordResponse structure
msg = transaction_get_record_pb2.TransactionGetRecordResponse()
# Check field descriptors
for field in msg.DESCRIPTOR.fields:
    if 'child' in field.name.lower():
        print(f"Field: {field.name}")
        print(f"  Type: {field.message_type.name if field.message_type else 'scalar'}")
        print(f"  Label: {field.label}")
EOF

Repository: hiero-ledger/hiero-sdk-python

Length of output: 201


🏁 Script executed:

# Now let's verify if child records actually have their own transactionID
python3 << 'EOF'
import sys
sys.path.insert(0, '/root')

from hiero_sdk_python.hapi.services import transaction_record_pb2

# Check if TransactionRecord has transactionID field
msg = transaction_record_pb2.TransactionRecord()
print("TransactionRecord fields:")
for field in msg.DESCRIPTOR.fields:
    if 'transaction' in field.name.lower():
        print(f"  {field.name}: {field.message_type.name if field.message_type else field.type}")
EOF

Repository: hiero-ledger/hiero-sdk-python

Length of output: 201


🏁 Script executed:

# Check what happens when TransactionRecord._from_proto receives a transaction_id parameter
rg -A 50 "def _from_proto" src/hiero_sdk_python/transaction/transaction_record.py | head -80

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2543


🏁 Script executed:

# Look at proto files to understand the structure
find . -path "*hapi*" -name "*.proto" | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Search for child_transaction_records definition in proto
find . -path "*hapi*" -name "*.proto" -exec grep -l "child_transaction_records" {} \;

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Check generated protobuf to see field structure
grep -r "child_transaction_records" src/hiero_sdk_python/hapi --include="*.py" -B 2 -A 2 | head -30

Repository: hiero-ledger/hiero-sdk-python

Length of output: 131


🏁 Script executed:

# Most importantly, look at what the test expects - check if child records preserve their own transaction IDs
cat tests/unit/transaction_record_query_test.py | sed -n '98,120p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 996


🏁 Script executed:

# Check the actual implementation of TransactionRecord._from_proto to see how it handles transaction_id parameter
rg -A 100 "def _from_proto" src/hiero_sdk_python/transaction/transaction_record.py | grep -A 10 "transaction_id" | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 954


🏁 Script executed:

# Let's check what the actual transaction_id of child records would be after mapping
# by examining if there's any assertion about transaction_id in the test
cat tests/unit/transaction_record_query_test.py | sed -n '98,130p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1424


🏁 Script executed:

# Check the full _from_proto implementation to understand how it handles the transaction_id parameter
cat src/hiero_sdk_python/transaction/transaction_record.py | grep -A 200 "def _from_proto" | head -100

Repository: hiero-ledger/hiero-sdk-python

Length of output: 4644


🏁 Script executed:

# Look for the return statement in _from_proto to see how transaction_id is assigned
rg -A 150 "def _from_proto" src/hiero_sdk_python/transaction/transaction_record.py | grep -B 5 "return cls"

Repository: hiero-ledger/hiero-sdk-python

Length of output: 275


🏁 Script executed:

# Check if there's an assertion about transaction_id in the child mapping test that we might have missed
cat tests/unit/transaction_record_query_test.py | sed -n '98,125p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1275


🏁 Script executed:

# Look at what proto type child_transaction_records actually holds - check the protobuf structure
grep -r "child_transaction_records" . --include="*.py" | grep -v ".pyc" | grep -v "test" | head -10

Repository: hiero-ledger/hiero-sdk-python

Length of output: 213


🏁 Script executed:

# Search for TransactionGetRecordResponse in generated protobuf to see its actual fields
find . -name "*.py" -exec grep -l "class TransactionGetRecordResponse" {} \;

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Let's check the actual behavior by looking at what happens when _from_proto is called without explicit transaction_id
rg "if proto.HasField\(\"transactionID\"\)|proto.transactionID" src/hiero_sdk_python/transaction/transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 153


🏁 Script executed:

# Verify if TransactionRecord._from_proto actually extracts transaction_id from proto when not provided
cat src/hiero_sdk_python/transaction/transaction_record.py | grep -B 5 "transaction_id=transaction_id" | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 277


🏁 Script executed:

# Let's check if the test actually verifies the transaction_id of child records
cat tests/unit/transaction_record_query_test.py | sed -n '98,130p' | grep -i "transaction_id\|assert"

Repository: hiero-ledger/hiero-sdk-python

Length of output: 440


🏁 Script executed:

# Check if there are any assertions about transaction_id in child records
rg "assert.*transaction_id" tests/unit/transaction_record_query_test.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 267


🏁 Script executed:

# Look at the entire test to see all assertions
cat tests/unit/transaction_record_query_test.py | sed -n '98,125p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1275


🏁 Script executed:

# Check if proto.HasField works on the child records and what fields are available
rg "HasField" src/hiero_sdk_python/transaction/transaction_record.py | head -10

Repository: hiero-ledger/hiero-sdk-python

Length of output: 128


🏁 Script executed:

# Let's check the actual type annotation issue - is it TransactionRecord or TransactionGetRecordResponse?
cat src/hiero_sdk_python/query/transaction_record_query.py | sed -n '196,210p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 591


🏁 Script executed:

# Critical check: Does TransactionRecord._from_proto actually extract transaction_id from proto when None?
cat src/hiero_sdk_python/transaction/transaction_record.py | sed -n '150,250p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 4742


🏁 Script executed:

# Let me verify the exact test setup - what are the child_proto transaction IDs before mapping?
cat tests/unit/transaction_record_query_test.py | sed -n '98,125p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1275


🏁 Script executed:

# Most importantly, check what the test asserts about child transaction IDs after mapping
rg "children\[0\]\.transaction_id|assert.*transaction" tests/unit/transaction_record_query_test.py | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 527


🏁 Script executed:

# Check if there are other tests that validate child record transaction IDs
rg -C 5 "child.*transaction_id\|transaction_id.*child" tests/

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Final verification: check if proto records actually have their own transactionID field
cat src/hiero_sdk_python/transaction/transaction_record.py | grep -A 5 "def _from_proto" | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 272


🏁 Script executed:

# Look for any extraction of transactionID from proto in the _from_proto method
rg "proto\.transactionID|HasField.*transactionID" src/hiero_sdk_python/transaction/transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 153


🏁 Script executed:

# Check what the test file setup shows - each child has transactionID set on proto
cat tests/unit/transaction_record_query_test.py | sed -n '98,110p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 621


🏁 Script executed:

# Confirm: the type annotation says TransactionGetRecordResponse but should be TransactionRecord
cat src/hiero_sdk_python/query/transaction_record_query.py | sed -n '196,205p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 427


🏁 Script executed:

# Let me verify the type annotation issue - what is actually in child_transaction_records?
cat tests/unit/transaction_record_query_test.py | sed -n '100,113p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 634


🏁 Script executed:

# Search for how the Hedera SDK JavaScript or other implementations handle child records
rg -i "child.*transaction.*record\|_map_record" --type py -B 2 -A 5 | head -50

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Check the complete context around where _map_record_list is called
cat src/hiero_sdk_python/query/transaction_record_query.py | sed -n '130,160p'

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1105


🏁 Script executed:

# Critical: verify the exact type by looking at the proto definitions
find . -name "*transaction_get_record_pb2.py" | xargs grep -A 10 "class TransactionGetRecordResponse" | head -30

Repository: hiero-ledger/hiero-sdk-python

Length of output: 55


🏁 Script executed:

# Also check if there's a way to extract transactionID from the child record proto
grep -r "transactionID" src/hiero_sdk_python/transaction/transaction_record.py | head -5

Repository: hiero-ledger/hiero-sdk-python

Length of output: 153


🏁 Script executed:

# Let's create a simple test to understand the behavior
python3 << 'EOF'
# Check if the docstring promise in _from_proto is actually implemented
import re

with open('src/hiero_sdk_python/transaction/transaction_record.py', 'r') as f:
    content = f.read()
    
# Find the _from_proto method
match = re.search(r'def _from_proto\((.*?)\) -> "TransactionRecord":(.*?)return cls\(', content, re.DOTALL)
if match:
    method_body = match.group(2)
    # Check if it extracts transaction_id from proto
    if 'proto.transactionID' in method_body or 'HasField("transactionID")' in method_body:
        print("FOUND: extraction of transactionID from proto")
    else:
        print("NOT FOUND: extraction of transactionID from proto")
        print("The _from_proto does NOT extract transaction_id from proto when parameter is None")
EOF

Repository: hiero-ledger/hiero-sdk-python

Length of output: 204


Type annotation incorrect; child records lose their own transaction IDs.
Line 198's type annotation should reflect that proto_records contains TransactionRecord protobuf messages, not TransactionGetRecordResponse. More importantly, line 202 passes self.transaction_id to every child record, which overwrites each child's own transactionID field. Extract each child's ID from the protobuf instead, falling back to the parent ID only if the child lacks one.

🔧 Proposed fix
     records: List[TransactionRecord] = []
     for record in proto_records:
-        records.append(TransactionRecord._from_proto(record, self.transaction_id))
+        record_tx_id = (
+            TransactionId._from_proto(record.transactionID)
+            if record.HasField("transactionID")
+            else self.transaction_id
+        )
+        records.append(TransactionRecord._from_proto(record, record_tx_id))

Comment on lines +72 to +74
nft_transfers: defaultdict[TokenId, list[TokenNftTransfer]] = field(
default_factory=lambda: defaultdict(list[TokenNftTransfer])
)
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cd src/hiero_sdk_python/transaction && wc -l transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 98


🏁 Script executed:

cd src/hiero_sdk_python/transaction && sed -n '70,80p' transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 524


🏁 Script executed:

cd src/hiero_sdk_python/transaction && sed -n '172,180p' transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 437


🏁 Script executed:

# Check imports and type definitions
cd src/hiero_sdk_python/transaction && head -50 transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 2821


🏁 Script executed:

# Verify if list[TokenNftTransfer] is callable in Python
python3 << 'EOF'
from typing import List

class TokenNftTransfer:
    pass

# Test if list[TokenNftTransfer] is callable
type_alias = list[TokenNftTransfer]
print(f"Type of list[TokenNftTransfer]: {type(type_alias)}")
print(f"Is it callable? {callable(type_alias)}")

# Try to call it
try:
    result = type_alias()
    print(f"Success: {result}")
except TypeError as e:
    print(f"Error when calling: {e}")

# Compare with list
print(f"\nIs list callable? {callable(list)}")
print(f"Calling list(): {list()}")
EOF

Repository: hiero-ledger/hiero-sdk-python

Length of output: 209


🏁 Script executed:

# Check more context around the nft_transfers field and how it's used
cd src/hiero_sdk_python/transaction && sed -n '60,90p' transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1417


🏁 Script executed:

# Search for usages of nft_transfers to understand intended behavior
cd src/hiero_sdk_python/transaction && grep -n "nft_transfers" transaction_record.py | head -20

Repository: hiero-ledger/hiero-sdk-python

Length of output: 606


🏁 Script executed:

# Check Python version requirements
fd -t f pyproject.toml setup.py setup.cfg | head -5

Repository: hiero-ledger/hiero-sdk-python

Length of output: 224


🏁 Script executed:

# Read project config to see Python version requirement
cat pyproject.toml | grep -A 5 "python"

Repository: hiero-ledger/hiero-sdk-python

Length of output: 839


🏁 Script executed:

# Check if there are any tests showing expected behavior
grep -r "nft_transfers" --include="*.py" | grep -E "test|spec" | head -10

Repository: hiero-ledger/hiero-sdk-python

Length of output: 1132


🏁 Script executed:

# Check actual test to understand expected behavior
cat tests/unit/token_airdrop_transaction_test.py | grep -A 10 "nft_transfer = airdrop_tx.nft_transfers"

Repository: hiero-ledger/hiero-sdk-python

Length of output: 910


🏁 Script executed:

# Check the _from_proto method implementation to see what type it expects
cd src/hiero_sdk_python/transaction && sed -n '150,165p' transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 925


🏁 Script executed:

# Verify runtime behavior by testing the actual field initialization
python3 << 'EOF'
from collections import defaultdict
from typing import List

class TokenNftTransfer:
    def __repr__(self):
        return "TokenNftTransfer()"

# Simulate the current code
nft_transfers = defaultdict(lambda: defaultdict(list[TokenNftTransfer]))

# Access a key that doesn't exist
token_id = "token_123"
result = nft_transfers[token_id]
print(f"Type returned: {type(result)}")
print(f"Is it a defaultdict? {isinstance(result, defaultdict)}")
print(f"Can iterate? {hasattr(result, '__iter__')}")

# Try to append like it's a list
try:
    result.append(TokenNftTransfer())
    print("ERROR: append succeeded on defaultdict")
except AttributeError as e:
    print(f"AttributeError (expected): {e}")

# Try to assign like current code does at line 161
test_list = [TokenNftTransfer(), TokenNftTransfer()]
nft_transfers[token_id] = test_list
print(f"After direct assignment, type: {type(nft_transfers[token_id])}")
print(f"Can iterate? {list(nft_transfers[token_id])}")
EOF

Repository: hiero-ledger/hiero-sdk-python

Length of output: 351


🏁 Script executed:

# Verify what _from_proto returns
cd src/hiero_sdk_python/tokens && grep -A 20 "def _from_proto" token_nft_transfer.py | head -25

Repository: hiero-ledger/hiero-sdk-python

Length of output: 829


🏁 Script executed:

# Double-check the field initialization and usage pattern
cd src/hiero_sdk_python/transaction && sed -n '239,245p' transaction_record.py

Repository: hiero-ledger/hiero-sdk-python

Length of output: 468


Fix type mismatch in nft_transfers factory: should return list, not defaultdict.

The field is declared as defaultdict[TokenId, list[TokenNftTransfer]], so values must be lists. However, the factory creates a defaultdict(list[TokenNftTransfer]), which returns a nested defaultdict instead of a list. While _from_proto directly assigns lists (bypassing the factory), accessing an uninitialized key would return a defaultdict, causing a runtime type mismatch with code expecting a list (e.g., indexing or iteration).

🔧 Proposed fix
     nft_transfers: defaultdict[TokenId, list[TokenNftTransfer]] = field(
-        default_factory=lambda: defaultdict(list[TokenNftTransfer])
+        default_factory=list
     )

Copy link
Contributor

@prajeeta15 prajeeta15 left a comment

Choose a reason for hiding this comment

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

@mukundkumarjha please address all the coderabbitai issues before pushing code.

- Formatted client_test.py using Black.

### Added
- Added support for include_children to the TransactionRecordQuery class
Copy link
Contributor

Choose a reason for hiding this comment

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

@mukundkumarjha please add the issue reference in the CHANGELOG entry to keep it consistent and easy to read.

@aceppaluni
Copy link
Contributor

@mukundkumarjha
Thank you for your work!
If you have any questions on coderabbit suggestions please let us know so we may assist. We are happy to help!

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.

Add support for include_children to the TransactionRecordQuery class

6 participants