Skip to content

Commit 3b976da

Browse files
authored
fix: restore hashability of status enums that define custom __eq__ (hiero-ledger#2470)
Signed-off-by: exploreriii <133720349+exploreriii@users.noreply.github.com>
1 parent 4a1f8df commit 3b976da

6 files changed

Lines changed: 77 additions & 0 deletions

File tree

src/hiero_sdk_python/system/freeze_type.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,7 @@ def __eq__(self, other: object) -> bool:
7979
if isinstance(other, int):
8080
return self.value == other
8181
return False
82+
83+
def __hash__(self) -> int:
84+
"""Hash by value, consistent with the int-accepting __eq__."""
85+
return hash(self.value)

src/hiero_sdk_python/tokens/token_freeze_status.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@ def __eq__(self, other: Any) -> bool:
4040
if isinstance(other, int):
4141
return self.value == other
4242
return False
43+
44+
def __hash__(self) -> int:
45+
"""Hash by value, consistent with the int-accepting __eq__."""
46+
return hash(self.value)

src/hiero_sdk_python/tokens/token_key_validation.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ def __eq__(self, other: Any) -> bool:
4949
if isinstance(other, int):
5050
return self.value == other
5151
return False
52+
53+
def __hash__(self) -> int:
54+
"""Hash by value, consistent with the int-accepting __eq__."""
55+
return hash(self.value)

src/hiero_sdk_python/tokens/token_kyc_status.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,7 @@ def __eq__(self, other: Any) -> bool:
4545
if isinstance(other, int):
4646
return self.value == other
4747
return False
48+
49+
def __hash__(self) -> int:
50+
"""Hash by value, consistent with the int-accepting __eq__."""
51+
return hash(self.value)

src/hiero_sdk_python/tokens/token_pause_status.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,7 @@ def __eq__(self, other: Any) -> bool:
6565
if isinstance(other, int):
6666
return self.value == other
6767
return False
68+
69+
def __hash__(self) -> int:
70+
"""Hash by value, consistent with the int-accepting __eq__."""
71+
return hash(self.value)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
Hashability tests for status enums that define a custom __eq__.
3+
4+
Defining __eq__ in a class body sets __hash__ = None unless __hash__ is
5+
also defined — which had silently made these Enum members unhashable:
6+
natural user code like `status in {TokenFreezeStatus.FROZEN}` raised
7+
TypeError. These tests pin that every such enum is hashable and that its
8+
hash is consistent with its int-accepting __eq__ (equal objects must hash
9+
equally, so hash(MEMBER) == hash(MEMBER.value)).
10+
"""
11+
12+
from __future__ import annotations
13+
14+
import pytest
15+
16+
from hiero_sdk_python.system.freeze_type import FreezeType
17+
from hiero_sdk_python.tokens.token_freeze_status import TokenFreezeStatus
18+
from hiero_sdk_python.tokens.token_key_validation import TokenKeyValidation
19+
from hiero_sdk_python.tokens.token_kyc_status import TokenKycStatus
20+
from hiero_sdk_python.tokens.token_pause_status import TokenPauseStatus
21+
22+
23+
pytestmark = pytest.mark.unit
24+
25+
STATUS_ENUMS = [
26+
TokenFreezeStatus,
27+
TokenKycStatus,
28+
TokenPauseStatus,
29+
FreezeType,
30+
TokenKeyValidation,
31+
]
32+
33+
_IDS = [cls.__name__ for cls in STATUS_ENUMS]
34+
35+
36+
@pytest.mark.parametrize("enum_cls", STATUS_ENUMS, ids=_IDS)
37+
def test_members_are_hashable(enum_cls):
38+
"""Every member must be hashable — usable in sets and as dict keys."""
39+
members = list(enum_cls)
40+
41+
assert set(members) == set(members)
42+
assert members[0] in set(members)
43+
44+
lookup = {member: member.name for member in members}
45+
assert lookup[members[0]] == members[0].name
46+
47+
48+
@pytest.mark.parametrize("enum_cls", STATUS_ENUMS, ids=_IDS)
49+
def test_hash_is_consistent_with_int_equality(enum_cls):
50+
"""__eq__ equates members with their int value, so their hashes must
51+
match too — otherwise `member.value in {member}` would be False while
52+
`member.value == member` is True."""
53+
for member in enum_cls:
54+
assert member == member.value
55+
assert hash(member) == hash(member.value)
56+
assert member.value in {member}
57+
assert member in {member.value}

0 commit comments

Comments
 (0)