From e44c0ca52f3283a38676c5318d7fdc1045a98a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?tonghuaroot=20=28=E7=AB=A5=E8=AF=9D=29?= Date: Sat, 24 Oct 2026 14:59:54 +0800 Subject: [PATCH] gh-158856: Fix enum membership for values of a different hashability Since _hashable_values_ became a set, `value in EnumClass` missed values equal to a member value but of a different hashability, including a set member's own value. Check the unhashable values on a miss and compare against the hashable values on TypeError. --- Lib/enum.py | 9 +++++++-- Lib/test/test_enum.py | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py index 8a6519e006515ab..6eb2d710b748f55 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -777,9 +777,14 @@ def __contains__(cls, value): except ValueError: pass try: - return value in cls._hashable_values_ # a set + if value in cls._hashable_values_: # a set + return True except TypeError: - return value in cls._unhashable_values_ # a list + # an unhashable value can equal a hashable one, e.g. bytearray + for v in cls._hashable_values_: + if v == value: + return True + return value in cls._unhashable_values_ # a list def __delattr__(cls, attr): # nicer error message when someone tries to delete an attribute diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 447f847f33da938..68a4820af1f437b 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -3530,6 +3530,23 @@ class Directions(Enum): UNRESTRICTED = frozenset({"sc", "cs"}) self.assertIs(Directions({"sc"}), Directions.DOWN_ONLY) + def test_contains_equal_value_of_other_hashability(self): + class Sets(Enum): + A = {1, 2} + class Magic(Enum): + PNG = b'\x89PNG' + class BytesMagic(bytes, Enum): + PNG = b'\x89PNG' + self.assertIn(Sets.A.value, Sets) + self.assertIn({1, 2}, Sets) + self.assertIn(frozenset({1, 2}), Sets) + self.assertNotIn({1, 3}, Sets) + self.assertNotIn(frozenset({1, 3}), Sets) + for enum_class in Magic, BytesMagic: + self.assertIn(bytearray(b'\x89PNG'), enum_class) + self.assertNotIn(bytearray(b'GIF8'), enum_class) + self.assertIs(enum_class(bytearray(b'\x89PNG')), enum_class.PNG) + class TestOrder(unittest.TestCase): "test usage of the `_order_` attribute"