diff --git a/Lib/enum.py b/Lib/enum.py index 8a6519e006515a..6eb2d710b748f5 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 447f847f33da93..68a4820af1f437 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"