Skip to content

Commit 59af4a3

Browse files
authored
Merge branch 'main' into phase2-final
Signed-off-by: Akshat8510 <akshat230405@gmail.com>
2 parents 2964a1a + baa212b commit 59af4a3

File tree

8 files changed

+119
-19
lines changed

8 files changed

+119
-19
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
88

99
### Added
1010
- Phase 2 of the inactivity-unassign bot:Automatically detects stale open pull requests (no commit activity for 21+ days), comments with a helpful InactivityBot message, closes the stale PR, and unassigns the contributor from the linked issue.
11+
- Added __str__() to CustomFixedFee and updated examples and tests accordingly.
1112
- Added a github template for good first issues
1213
- Added `.github/workflows/bot-assignment-check.yml` to limit non-maintainers to 2 concurrent issue assignments.
14+
- Added all missing fields to __str__() method and updated `test_tokem_info.py`
1315
- Add examples/tokens/token_create_transaction_pause_key.py example demonstrating token pause/unpause behavior and pause key usage (#833)
1416
- Added `docs/sdk_developers/training/transaction_lifecycle.md` to explain the typical lifecycle of executing a transaction using the Hedera Python SDK.
1517
- Add inactivity bot workflow to unassign stale issue assignees (#952)
@@ -20,6 +22,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
2022

2123
### Fixed
2224
- Fixed inactivity bot workflow not checking out repository before running (#964)
25+
- Fixed the topic_message_query integarion test
2326

2427
### Breaking Change
2528

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,4 @@ This project is licensed under the [Apache License 2.0](LICENSE).
134134

135135
---
136136

137-
**Latest release:** Check [PyPI](https://pypi.org/project/hiero-sdk-python/) or [GitHub Releases](https://github.com/hiero-ledger/hiero-sdk-python/releases)
137+
**Latest release:** Check [PyPI](https://pypi.org/project/hiero-sdk-python/) or [GitHub Releases](https://github.com/hiero-ledger/hiero-sdk-python/releases)

examples/tokens/custom_fixed_fee.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ def custom_fixed_fee():
1414
fee_collector_account_id=AccountId(0, 0, 456),
1515
all_collectors_are_exempt=False,
1616
)
17-
print("CustomFixedFee:")
18-
print(f"Amount: {fixed_fee.amount}")
19-
print(f"Denominating Token ID: {fixed_fee.denominating_token_id}")
20-
print(f"Fee Collector Account ID: {fixed_fee.fee_collector_account_id}")
21-
print(f"All Collectors Exempt: {fixed_fee.all_collectors_are_exempt}")
17+
print("\n--- Custom Fixed Fee ---")
18+
print(fixed_fee)
19+
2220
# Convert to protobuf
2321
fixed_fee_proto = fixed_fee._to_proto()
2422

src/hiero_sdk_python/tokens/custom_fixed_fee.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,30 @@ def __init__(
6161
super().__init__(fee_collector_account_id, all_collectors_are_exempt)
6262
self.amount = amount
6363
self.denominating_token_id = denominating_token_id
64+
65+
def __str__(self) -> str:
66+
"""Return a user-friendly string representation of the CustomFixedFee.
67+
68+
Displays all fields in insertion order with aligned formatting.
69+
TokenId and AccountId objects are displayed in Hedera notation (e.g., 0.0.123).
70+
"""
71+
72+
fields = {
73+
key.replace("_", " ").title(): value
74+
for key, value in self.__dict__.items()
75+
}
76+
77+
if not fields:
78+
return f"{self.__class__.__name__}()"
79+
80+
max_len = max(len(name) for name in fields)
81+
82+
lines = [f"{self.__class__.__name__}:"]
83+
for name, value in fields.items(): # preserves insertion order
84+
lines.append(f" {name:<{max_len}} = {value}") # uses __str__()
85+
86+
return "\n".join(lines)
87+
6488

6589
def set_amount_in_tinybars(self, amount: int) -> "CustomFixedFee":
6690
"""Sets the fee amount in tinybars.

src/hiero_sdk_python/tokens/token_info.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,25 @@ def __str__(self) -> str:
240240
f"is_deleted={self.is_deleted}",
241241
f"memo={self.memo!r}",
242242
f"token_type={self.token_type}",
243+
f"supply_type={self.supply_type}",
243244
f"max_supply={self.max_supply}",
244245
f"ledger_id={self.ledger_id!r}",
245246
f"metadata={self.metadata!r}",
247+
f"custom_fees={self.custom_fees!r}",
248+
f"admin_key={self.admin_key}",
249+
f"kyc_key={self.kyc_key}",
250+
f"freeze_key={self.freeze_key}",
251+
f"wipe_key={self.wipe_key}",
252+
f"supply_key={self.supply_key}",
253+
f"metadata_key={self.metadata_key}",
254+
f"fee_schedule_key={self.fee_schedule_key}",
255+
f"pause_key={self.pause_key}",
256+
f"default_freeze_status={self.default_freeze_status}",
257+
f"default_kyc_status={self.default_kyc_status}",
258+
f"pause_status={self.pause_status}",
259+
f"auto_renew_account={self.auto_renew_account}",
260+
f"auto_renew_period={self.auto_renew_period}",
261+
f"expiry={self.expiry}",
246262
]
263+
247264
return f"TokenInfo({', '.join(parts)})"

tests/integration/topic_message_query_e2e_test.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ def create_topic(client):
5858
def test_topic_message_query_receives_messages(env):
5959
"""Test that topic message query receives a message."""
6060
topic_id = create_topic(env.client)
61-
61+
62+
time.sleep(3)
63+
6264
messages: List[str] = []
6365

6466
def get_message(m: TopicMessage):
@@ -78,6 +80,8 @@ def on_error_handler(e):
7880
on_message=get_message,
7981
on_error=on_error_handler
8082
)
83+
84+
time.sleep(3)
8185

8286
message_receipt = (
8387
TopicMessageSubmitTransaction(
@@ -96,9 +100,9 @@ def on_error_handler(e):
96100
start = datetime.now()
97101

98102
while len(messages) == 0:
99-
if datetime.now() - start > timedelta(seconds=120):
103+
if datetime.now() - start > timedelta(seconds=180):
100104
raise TimeoutError("TopicMessage was not received in time")
101-
time.sleep(1)
105+
time.sleep(5)
102106

103107
assert messages[0] == "Hello, Python SDK!"
104108
handle.cancel()
@@ -113,6 +117,8 @@ def test_topic_message_query_limit(env):
113117
def on_message(m: TopicMessage):
114118
messages.append(m.contents.decode("utf-8"))
115119

120+
time.sleep(3)
121+
116122
query = TopicMessageQuery(
117123
topic_id=topic_id,
118124
start_time=datetime.now(timezone.utc),
@@ -121,6 +127,7 @@ def on_message(m: TopicMessage):
121127

122128
handle = query.subscribe(env.client, on_message=on_message)
123129

130+
time.sleep(3)
124131
# Submit 3 messages
125132
try:
126133
for i in range(3):
@@ -133,9 +140,9 @@ def on_message(m: TopicMessage):
133140
start = datetime.now()
134141

135142
while len(messages) != 2:
136-
if datetime.now() - start > timedelta(seconds=120):
143+
if datetime.now() - start > timedelta(seconds=180):
137144
raise TimeoutError("TopicMessage was not received in time")
138-
time.sleep(1)
145+
time.sleep(5)
139146

140147
# Should stop at limit=2
141148
assert messages == ["msg0", "msg1"]
@@ -149,6 +156,7 @@ def test_topic_message_query_large_message_chunking(env):
149156
"""Test that topic message query receives chunked message."""
150157
topic_id = create_topic(env.client)
151158
messages: List[str] = []
159+
time.sleep(3)
152160

153161
def get_message(m: TopicMessage):
154162
messages.append(m.contents.decode('utf-8'))
@@ -168,7 +176,9 @@ def on_error_handler(e):
168176
on_message=get_message,
169177
on_error=on_error_handler
170178
)
171-
179+
180+
time.sleep(3)
181+
172182
message_receipt = (
173183
TopicMessageSubmitTransaction(
174184
topic_id=topic_id,
@@ -187,9 +197,9 @@ def on_error_handler(e):
187197
start = datetime.now()
188198

189199
while len(messages) == 0:
190-
if datetime.now() - start > timedelta(seconds=120):
200+
if datetime.now() - start > timedelta(seconds=180):
191201
raise TimeoutError("TopicMessage was not received in time")
192-
time.sleep(1)
202+
time.sleep(5)
193203

194204
assert messages[0] == BIG_CONTENT
195205
handle.cancel()

tests/unit/test_custom_fee.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,60 @@
99

1010
pytestmark = pytest.mark.unit
1111

12-
def test_custom_fixed_fee():
12+
def test_custom_fixed_fee_proto_round_trip():
13+
"""Ensure CustomFixedFee protobuf serialization and deserialization behave correctly."""
1314
fee = CustomFixedFee(
1415
amount=100,
1516
denominating_token_id=TokenId(0, 0, 123),
1617
fee_collector_account_id=AccountId(0, 0, 456),
1718
all_collectors_are_exempt=True,
1819
)
1920

20-
proto = fee._to_proto() # Changed from _to_protobuf
21-
new_fee = CustomFixedFee._from_proto(proto) # Changed from CustomFee._from_protobuf
21+
proto = fee._to_proto()
22+
new_fee = CustomFixedFee._from_proto(proto)
2223

2324
assert isinstance(new_fee, CustomFixedFee)
2425
assert new_fee.amount == 100
2526
assert new_fee.denominating_token_id == TokenId(0, 0, 123)
2627
assert new_fee.fee_collector_account_id == AccountId(0, 0, 456)
2728
assert new_fee.all_collectors_are_exempt is True
2829

30+
def test_custom_fixed_fee_str():
31+
"""Test the string representation of CustomFixedFee."""
32+
fee = CustomFixedFee(
33+
amount=100,
34+
denominating_token_id=TokenId(0, 0, 123),
35+
fee_collector_account_id=AccountId(0, 0, 456),
36+
all_collectors_are_exempt=False,
37+
)
38+
39+
fee_str = fee.__str__()
40+
41+
# Basic checks
42+
assert "CustomFixedFee" in fee_str
43+
assert "Amount" in fee_str
44+
assert "Denominating Token Id" in fee_str
45+
assert "Fee Collector Account Id" in fee_str
46+
assert "All Collectors Are Exempt" in fee_str
47+
48+
# Key-value extraction
49+
kv = {}
50+
for ln in fee_str.splitlines()[1:]:
51+
if "=" in ln:
52+
key, val = ln.split("=", 1)
53+
kv[key.strip()] = val.strip()
54+
55+
expected = {
56+
"Amount": "100",
57+
"Denominating Token Id": "0.0.123",
58+
"Fee Collector Account Id": "0.0.456",
59+
"All Collectors Are Exempt": "False",
60+
}
61+
62+
for key, val in expected.items():
63+
assert kv[key] == val, f"{key} incorrect in string representation"
64+
65+
2966
def test_custom_fractional_fee_str():
3067
"""Test the string representation of CustomFractionalFee."""
3168
fee = CustomFractionalFee(

tests/unit/test_token_info.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,18 @@ def test_str_representation(token_info):
186186
f"symbol={token_info.symbol!r}, decimals={token_info.decimals}, "
187187
f"total_supply={token_info.total_supply}, treasury={token_info.treasury}, "
188188
f"is_deleted={token_info.is_deleted}, memo={token_info.memo!r}, "
189-
f"token_type={token_info.token_type}, max_supply={token_info.max_supply}, "
190-
f"ledger_id={token_info.ledger_id!r}, metadata={token_info.metadata!r})"
189+
f"token_type={token_info.token_type}, supply_type={token_info.supply_type}, "
190+
f"max_supply={token_info.max_supply}, ledger_id={token_info.ledger_id!r}, "
191+
f"metadata={token_info.metadata!r}, custom_fees={token_info.custom_fees!r}, "
192+
f"admin_key={token_info.admin_key}, kyc_key={token_info.kyc_key}, "
193+
f"freeze_key={token_info.freeze_key}, wipe_key={token_info.wipe_key}, "
194+
f"supply_key={token_info.supply_key}, metadata_key={token_info.metadata_key}, "
195+
f"fee_schedule_key={token_info.fee_schedule_key}, pause_key={token_info.pause_key}, "
196+
f"default_freeze_status={token_info.default_freeze_status}, "
197+
f"default_kyc_status={token_info.default_kyc_status}, "
198+
f"pause_status={token_info.pause_status}, "
199+
f"auto_renew_account={token_info.auto_renew_account}, "
200+
f"auto_renew_period={token_info.auto_renew_period}, "
201+
f"expiry={token_info.expiry})"
191202
)
192203
assert str(token_info) == expected

0 commit comments

Comments
 (0)