Skip to content

Commit 7c87d85

Browse files
authored
Merge branch 'main' into feat/beginner-issue-guard
2 parents f2395ad + 3890690 commit 7c87d85

File tree

6 files changed

+448
-2
lines changed

6 files changed

+448
-2
lines changed

.github/scripts/bot-pr-missing-linked-issue.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ module.exports = async ({ github, context }) => {
3535
}
3636

3737
const body = prData.body || "";
38-
const regex = /\bFixes\s*:?\s*(#\d+)(\s*,\s*#\d+)*/i;
38+
const regex = /\b(Fixes|Closes|Resolves)\s*:?\s*(#\d+)(\s*,\s*#\d+)*/i;
3939

4040
const comments = await github.rest.issues.listComments({
4141
owner: context.repo.owner,

.github/workflows/bot-community-calls.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ jobs:
3737
- name: Check Schedule and Notify
3838
env:
3939
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40-
DRY_RUN: "false" # will post when workflow is triggered by cron
40+
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || 'false' }}
4141
run: |
4242
bash .github/scripts/bot-community-calls.sh

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
106106
- Add GitHub Actions script and workflow for automatic spam list updates.
107107
- Added technical docstrings and hardening (set -euo pipefail) to the pr-check-test-files.sh script (#1336)
108108
- Added prompt for coderabbit to review `Query` and it's sub-classes.
109+
- Add StakingInfo class ([1364](https://github.com/hiero-ledger/hiero-sdk-python/issues/1364))
109110

110111
### Changed
111112

@@ -187,6 +188,8 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
187188
- Enhance TopicInfo `__str__` method and tests with additional coverage, and update the format_key function in `key_format.py` to handle objects with a _to_proto method.
188189

189190
### Fixed
191+
- Respect `dry-run` input in `bot-community-calls.yml` workflow (#1425)
192+
- Updated LinkBot regex in the GitHub Actions bot script to support "Closes" and "Resolves" keywords for improved PR body-link detection (#1465)
190193
- Fixed CodeRabbit plan trigger workflow running multiple times when issues are created with multiple labels by switching to labeled event trigger only. (#1427)
191194
- Prevent LinkBot from posting duplicate “missing linked issue” comments on pull requests. (#1475)
192195
- Refined intermediate assignment guard to validate Beginner issue completion with improved logging and GraphQL-based counting. (#1424)

src/hiero_sdk_python/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070

7171
# Timestamp
7272
from .timestamp import Timestamp
73+
from .staking_info import StakingInfo
7374

7475
# Duration
7576
from .Duration import Duration
@@ -245,6 +246,7 @@
245246
"ResponseCode",
246247
"Timestamp",
247248
"Duration",
249+
"StakingInfo",
248250

249251
# File
250252
"FileCreateTransaction",
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
"""
2+
StakingInfo class.
3+
"""
4+
5+
from dataclasses import dataclass
6+
from typing import Optional
7+
8+
from hiero_sdk_python.account.account_id import AccountId
9+
from hiero_sdk_python.hapi.services.basic_types_pb2 import StakingInfo as StakingInfoProto
10+
from hiero_sdk_python.hbar import Hbar
11+
from hiero_sdk_python.timestamp import Timestamp
12+
13+
14+
@dataclass(frozen=True)
15+
class StakingInfo:
16+
"""
17+
Represents staking-related information for an account.
18+
19+
Attributes:
20+
decline_reward (Optional[bool]): Whether rewards are declined.
21+
stake_period_start (Optional[Timestamp]): Start of the staking period.
22+
pending_reward (Optional[Hbar]): Pending staking reward in Hbar.
23+
staked_to_me (Optional[Hbar]): Amount staked to this account in Hbar.
24+
staked_account_id (Optional[AccountId]): Account ID this account is staked to.
25+
staked_node_id (Optional[int]): Node ID this account is staked to.
26+
"""
27+
28+
decline_reward: Optional[bool] = None
29+
stake_period_start: Optional[Timestamp] = None
30+
pending_reward: Optional[Hbar] = None
31+
staked_to_me: Optional[Hbar] = None
32+
staked_account_id: Optional[AccountId] = None
33+
staked_node_id: Optional[int] = None
34+
35+
def __post_init__(self) -> None:
36+
if self.staked_account_id is not None and self.staked_node_id is not None:
37+
raise ValueError("Only one of staked_account_id or staked_node_id can be set.")
38+
39+
@classmethod
40+
def _from_proto(cls, proto: StakingInfoProto) -> "StakingInfo":
41+
"""
42+
Creates a StakingInfo instance from its protobuf representation.
43+
"""
44+
if proto is None:
45+
raise ValueError("Staking info proto is None")
46+
47+
decline_reward = proto.decline_reward
48+
49+
stake_period_start = None
50+
if proto.HasField("stake_period_start"):
51+
stake_period_start = Timestamp._from_protobuf(proto.stake_period_start)
52+
53+
pending_reward=Hbar.from_tinybars(proto.pending_reward)
54+
staked_to_me=Hbar.from_tinybars(proto.staked_to_me)
55+
56+
staked_account_id = None
57+
if proto.HasField("staked_account_id"):
58+
staked_account_id = AccountId._from_proto(proto.staked_account_id)
59+
60+
staked_node_id = None
61+
if proto.HasField("staked_node_id"):
62+
staked_node_id = proto.staked_node_id
63+
64+
return cls(
65+
decline_reward=proto.decline_reward,
66+
stake_period_start=stake_period_start,
67+
pending_reward=pending_reward,
68+
staked_to_me=staked_to_me,
69+
staked_account_id=staked_account_id,
70+
staked_node_id=staked_node_id,
71+
)
72+
73+
def _to_proto(self) -> StakingInfoProto:
74+
"""
75+
Converts this StakingInfo instance to its protobuf representation.
76+
"""
77+
proto = StakingInfoProto()
78+
79+
if self.decline_reward is not None:
80+
proto.decline_reward = bool(self.decline_reward)
81+
if self.stake_period_start is not None:
82+
proto.stake_period_start.CopyFrom(self.stake_period_start._to_protobuf())
83+
if self.pending_reward is not None:
84+
proto.pending_reward = self.pending_reward.to_tinybars()
85+
if self.staked_to_me is not None:
86+
proto.staked_to_me = self.staked_to_me.to_tinybars()
87+
if self.staked_account_id is not None:
88+
proto.staked_account_id.CopyFrom(self.staked_account_id._to_proto())
89+
if self.staked_node_id is not None:
90+
proto.staked_node_id = self.staked_node_id
91+
92+
return proto
93+
94+
@classmethod
95+
def from_bytes(cls, data: bytes) -> "StakingInfo":
96+
"""
97+
Creates a StakingInfo instance from protobuf-encoded bytes.
98+
"""
99+
if not isinstance(data, bytes):
100+
raise TypeError("data must be bytes")
101+
if len(data) == 0:
102+
raise ValueError("data cannot be empty")
103+
104+
try:
105+
proto = StakingInfoProto.FromString(data)
106+
except Exception as exc:
107+
raise ValueError(f"Failed to parse StakingInfo bytes: {exc}") from exc
108+
109+
return cls._from_proto(proto)
110+
111+
def to_bytes(self) -> bytes:
112+
"""
113+
Serializes this StakingInfo instance to protobuf-encoded bytes.
114+
"""
115+
return self._to_proto().SerializeToString()
116+
117+
def __str__(self) -> str:
118+
return (
119+
"StakingInfo(\n"
120+
f" decline_reward={self.decline_reward},\n"
121+
f" stake_period_start={self.stake_period_start},\n"
122+
f" pending_reward={self.pending_reward},\n"
123+
f" staked_to_me={self.staked_to_me},\n"
124+
f" staked_account_id={self.staked_account_id},\n"
125+
f" staked_node_id={self.staked_node_id}\n"
126+
")"
127+
)
128+
129+
def __repr__(self) -> str:
130+
return (
131+
"StakingInfo("
132+
f"decline_reward={self.decline_reward!r}, "
133+
f"stake_period_start={self.stake_period_start!r}, "
134+
f"pending_reward={self.pending_reward!r}, "
135+
f"staked_to_me={self.staked_to_me!r}, "
136+
f"staked_account_id={self.staked_account_id!r}, "
137+
f"staked_node_id={self.staked_node_id!r}"
138+
")"
139+
)

0 commit comments

Comments
 (0)