diff --git a/Lib/enum.py b/Lib/enum.py index 6d3bbdc31625f7..110fbda4ddf5ad 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -166,6 +166,13 @@ def _dedent(text): lines[j] = l[i:] return '\n'.join(lines) +class _not_given: + def __repr__(self): + return('') + def __bool__(self): + return False +_not_given = _not_given() + class _auto_null: def __repr__(self): return '_auto_null' @@ -718,7 +725,7 @@ def __bool__(cls): """ return True - def __call__(cls, value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None): + def __call__(cls, value, names=_not_given, *values, module=None, qualname=None, type=None, start=1, boundary=None): """ Either returns an existing member, or creates a new enum class. @@ -747,18 +754,18 @@ def __call__(cls, value, names=None, *values, module=None, qualname=None, type=N """ if cls._member_map_: # simple value lookup if members exist - if names: + if names is not _not_given: value = (value, names) + values return cls.__new__(cls, value) # otherwise, functional API: we're creating a new Enum type - if names is None and type is None: + if names is _not_given and type is None: # no body? no data-type? possibly wrong usage raise TypeError( f"{cls} has no members; specify `names=()` if you meant to create a new, empty, enum" ) return cls._create_( class_name=value, - names=names, + names=names or None, module=module, qualname=qualname, type=type, diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index c58dc36fe84134..d5e9444bdcb07b 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -3312,6 +3312,40 @@ def __new__(cls, value): member._value_ = Base(value) return member + def test_second_tuple_item_is_falsey(self): + class Cardinal(Enum): + RIGHT = (1, 0) + UP = (0, 1) + LEFT = (-1, 0) + DOWN = (0, -1) + self.assertIs(Cardinal(1, 0), Cardinal.RIGHT) + self.assertIs(Cardinal(-1, 0), Cardinal.LEFT) + + def test_no_members(self): + with self.assertRaisesRegex( + TypeError, + 'has no members', + ): + Enum(7) + with self.assertRaisesRegex( + TypeError, + 'has no members', + ): + Flag(7) + + def test_empty_names(self): + for nothing, e_type in ( + ('', None), + ('', int), + ([], None), + ([], int), + ({}, None), + ({}, int), + ): + empty_enum = Enum('empty_enum', nothing, type=e_type) + self.assertEqual(len(empty_enum), 0) + self.assertRaises(TypeError, 'has no members', empty_enum, 0) + class TestOrder(unittest.TestCase): "test usage of the `_order_` attribute" diff --git a/Misc/NEWS.d/next/Library/2024-02-28-13-10-17.gh-issue-116040.wDidHd.rst b/Misc/NEWS.d/next/Library/2024-02-28-13-10-17.gh-issue-116040.wDidHd.rst new file mode 100644 index 00000000000000..907b58b3a5c206 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-02-28-13-10-17.gh-issue-116040.wDidHd.rst @@ -0,0 +1 @@ +[Enum] fix by-value calls when second value is falsey; e.g. Cardinal(1, 0)