Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
- Replaced the docstring in `entity_id_helper.py` with one that is correct. (#1623)

### Changed
- Refactored AccountInfo class to use the staking_info(#1366)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Minor formatting inconsistency: missing space before issue reference.

Other entries in this file follow the pattern description (#issue) with a space before the parenthesis. This entry has staking_info(hiero-ledger#1366) without a space.

Suggested fix
-- Refactored AccountInfo class to use the staking_info(`#1366`)
+- Refactored AccountInfo class to use the staking_info (`#1366`)
📝 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
- Refactored AccountInfo class to use the staking_info(#1366)
- Refactored AccountInfo class to use the staking_info (`#1366`)

- Refactored `setup_client()` in all `examples/query/` files to use `Client.from_env()` for simplified client initialization (#1449)
- Updated return of to_bytes function in `src/hiero_sdk_python/transaction/transaction.py`. (#1631)
- Added missing return type `src/hiero_sdk_python/utils/entity_id_helper.py`. (#1622)
Expand Down
44 changes: 16 additions & 28 deletions src/hiero_sdk_python/account/account_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from hiero_sdk_python.account.account_id import AccountId
from hiero_sdk_python.crypto.public_key import PublicKey
from hiero_sdk_python.Duration import Duration
from hiero_sdk_python.hapi.services.basic_types_pb2 import StakingInfo
from hiero_sdk_python.staking_info import StakingInfo
from hiero_sdk_python.hapi.services.crypto_get_info_pb2 import CryptoGetInfoResponse
from hiero_sdk_python.hbar import Hbar
from hiero_sdk_python.timestamp import Timestamp
Expand Down Expand Up @@ -56,9 +56,8 @@ class AccountInfo:
account_memo: Optional[str] = None
owned_nfts: Optional[int] = None
max_automatic_token_associations: Optional[int] = None
staked_account_id: Optional[AccountId] = None
staked_node_id: Optional[int] = None
decline_staking_reward: Optional[bool] = None
staking_info: Optional[StakingInfo] = None


@classmethod
def _from_proto(cls, proto: CryptoGetInfoResponse.AccountInfo) -> "AccountInfo":
Expand Down Expand Up @@ -100,20 +99,14 @@ def _from_proto(cls, proto: CryptoGetInfoResponse.AccountInfo) -> "AccountInfo":
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 = proto.staking_info if proto.HasField('staking_info') else None

if staking_info:
account_info.staked_account_id = (
AccountId._from_proto(staking_info.staked_account_id)
if staking_info.HasField('staked_account_id') else None
)
account_info.staked_node_id = (
staking_info.staked_node_id
if staking_info.HasField('staked_node_id') else None
)
account_info.decline_staking_reward = staking_info.decline_reward


return account_info

Expand Down Expand Up @@ -147,11 +140,11 @@ def _to_proto(self) -> CryptoGetInfoResponse.AccountInfo:
memo=self.account_memo,
ownedNfts=self.owned_nfts,
max_automatic_token_associations=self.max_automatic_token_associations,
staking_info=StakingInfo(
staked_account_id=self.staked_account_id._to_proto() if self.staked_account_id else None,
staked_node_id=self.staked_node_id if self.staked_node_id else None,
decline_reward=self.decline_staking_reward
),
staking_info=(
self.staking_info._to_proto()
if self.staking_info is not None
else None
),
)

def __str__(self) -> str:
Expand All @@ -166,8 +159,7 @@ def __str__(self) -> str:
(self.account_memo, "Memo"),
(self.owned_nfts, "Owned NFTs"),
(self.max_automatic_token_associations, "Max Automatic Token Associations"),
(self.staked_account_id, "Staked Account ID"),
(self.staked_node_id, "Staked Node ID"),
(self.staking_info, "Staked Info"),
(self.proxy_received, "Proxy Received"),
(self.expiration_time, "Expiration Time"),
(self.auto_renew_period, "Auto Renew Period"),
Expand All @@ -182,9 +174,6 @@ def __str__(self) -> str:

if self.receiver_signature_required is not None:
lines.append(f"Receiver Signature Required: {self.receiver_signature_required}")

if self.decline_staking_reward is not None:
lines.append(f"Decline Staking Reward: {self.decline_staking_reward}")

if self.token_relationships:
lines.append(f"Token Relationships: {len(self.token_relationships)}")
Expand All @@ -202,7 +191,6 @@ def __repr__(self) -> str:
f"receiver_signature_required={self.receiver_signature_required!r}, "
f"owned_nfts={self.owned_nfts!r}, "
f"account_memo={self.account_memo!r}, "
f"staked_node_id={self.staked_node_id!r}, "
f"staked_account_id={self.staked_account_id!r}"
f"staked_info={self.staking_info!r}, "
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent field name in __repr__: uses staked_info instead of staking_info.

The field is named staking_info but the __repr__ output uses staked_info=. This inconsistency could cause confusion during debugging.

Proposed fix
-            f"staked_info={self.staking_info!r}, "
+            f"staking_info={self.staking_info!r}, "
📝 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
f"staked_info={self.staking_info!r}, "
f"staking_info={self.staking_info!r}, "

f")"
)
57 changes: 57 additions & 0 deletions tests/unit/account_info_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from hiero_sdk_python.tokens.token_relationship import TokenRelationship
from hiero_sdk_python.tokens.token_id import TokenId
from hiero_sdk_python.hapi.services.crypto_get_info_pb2 import CryptoGetInfoResponse
from hiero_sdk_python.staking_info import StakingInfo

pytestmark = pytest.mark.unit

Expand All @@ -28,6 +29,8 @@ def account_info():
token_relationships=[],
account_memo="Test account memo",
owned_nfts=5,
max_automatic_token_associations=10,
staking_info=None
)


Expand All @@ -47,6 +50,8 @@ def proto_account_info():
tokenRelationships=[],
memo="Test account memo",
ownedNfts=5,
max_automatic_token_associations=10,
staking_info=None
)
return proto

Expand All @@ -65,6 +70,32 @@ def test_account_info_initialization(account_info):
assert account_info.token_relationships == []
assert account_info.account_memo == "Test account memo"
assert account_info.owned_nfts == 5
assert account_info.max_automatic_token_associations == 10
assert account_info.staking_info is None

def test_from_proto_with_staking_info():
"""Test the from_proto method of the AccountInfo class with staking info"""
public_key = PrivateKey.generate_ed25519().public_key()

staking_info={
"decline_reward": True,
"staked_node_id": 3,
"staked_account_id": None
}

proto = CryptoGetInfoResponse.AccountInfo(
accountID=AccountId(0, 0, 100)._to_proto(),
key=public_key._to_proto(),
balance=5000000,


)

account_info = AccountInfo._from_proto(proto)

assert account_info.staking_info is not None
assert account_info.staking_info.decline_reward is True
assert account_info.staking_info.staked_node_id == 3


def test_account_info_default_initialization():
Expand All @@ -82,7 +113,25 @@ def test_account_info_default_initialization():
assert account_info.token_relationships == []
assert account_info.account_memo is None
assert account_info.owned_nfts is None
assert account_info.max_automatic_token_associations is None
assert account_info.staking_info is None

def test_staking_info_persistence(account_info):
"""Ensure staking info is preserved through proto conversion"""

account_info.staking_info = StakingInfo(
decline_reward=True,
staked_node_id=5,
staked_account_id=None
)

proto = account_info._to_proto()
converted_info = AccountInfo._from_proto(proto)

assert converted_info.staking_info is not None
assert converted_info.staking_info.decline_reward is True
assert converted_info.staking_info.staked_node_id == 5
assert converted_info.staking_info.staked_account_id is None

def test_from_proto(proto_account_info):
"""Test the from_proto method of the AccountInfo class"""
Expand All @@ -100,6 +149,8 @@ def test_from_proto(proto_account_info):
assert account_info.token_relationships == []
assert account_info.account_memo == "Test account memo"
assert account_info.owned_nfts == 5
assert account_info.max_automatic_token_associations == 10
assert account_info.staking_info == None
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use is None instead of == None for None comparisons.

Per PEP 8 and the static analysis hint, comparisons to None should use is None.

Proposed fix
-    assert account_info.staking_info == None
+    assert account_info.staking_info is 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
assert account_info.staking_info == None
assert account_info.staking_info is None
🧰 Tools
🪛 Ruff (0.14.14)

[error] 153-153: Comparison to None should be cond is None

Replace with cond is None

(E711)



def test_from_proto_with_token_relationships():
Expand Down Expand Up @@ -141,6 +192,11 @@ def test_to_proto(account_info):
assert proto.tokenRelationships == []
assert proto.memo == "Test account memo"
assert proto.ownedNfts == 5
assert proto.max_automatic_token_associations == 10
assert not proto.HasField("staking_info")





def test_to_proto_with_none_values():
Expand Down Expand Up @@ -192,6 +248,7 @@ def test_proto_conversion(account_info):
)
assert converted_account_info.account_memo == account_info.account_memo
assert converted_account_info.owned_nfts == account_info.owned_nfts
assert converted_account_info.staking_info == account_info.staking_info


def test_str_and_repr(account_info):
Expand Down
5 changes: 3 additions & 2 deletions tests/unit/topic_info_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def test_repr_and_str(topic_info):
assert "memo='Test topic memo'" in repr_output
assert "sequence_number=42" in repr_output
assert "running_hash=0x0102030405060708" in repr_output
assert "expiration_time=2021-07-01 00:00:00" in repr_output
assert "expiration_time=2021-07-01" in str_output
assert "auto_renew_period=7776000" in repr_output

def test_str_formatting(topic_info):
Expand All @@ -264,7 +264,8 @@ def test_str_formatting(topic_info):
assert "memo='Test topic memo'" in str_output
assert "running_hash=0x0102030405060708" in str_output
assert "sequence_number=42" in str_output
assert "expiration_time=2021-07-01 00:00:00" in str_output
# Instead of the full date-time string
assert "expiration_time=2021-07-01" in str_output
assert "admin_key=ed25519(" in str_output
assert "submit_key=ed25519(" in str_output
assert "auto_renew_period=7776000" in str_output
Expand Down
Loading