From a5828a6b6ddf8e73b59447753e79a6f62afef13d Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Wed, 28 Feb 2024 13:10:22 -0800 Subject: [PATCH 1/2] fix by-value calls when second value is falsey; e.g. Cardinal(1, 0) --- Lib/enum.py | 15 +++++++++++---- Lib/test/test_enum.py | 9 +++++++++ ...2024-02-28-13-10-17.gh-issue-116040.wDidHd.rst | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-02-28-13-10-17.gh-issue-116040.wDidHd.rst diff --git a/Lib/enum.py b/Lib/enum.py index d10b99615981ba..432f6c2701f4ba 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -162,6 +162,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' @@ -677,7 +684,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. @@ -706,18 +713,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 cf3e042de1a4b4..3c8f9c6a97cbd9 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -3409,6 +3409,15 @@ def __new__(cls, int_value, *value_aliases): self.assertIs(Types(2), Types.NetList) self.assertIs(Types('nl'), Types.NetList) + def test_second_tuple_item_is_falsey(self): + class Cardinal(Enum): + RIGHT = (1, 0) + UP = (0, 1) + LEFT = (-1, 0) + DOWN = (0, -1) + Cardinal(1, 0) + Cardinal(-1, 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) From 248bd2c43298b6f39c0bcfe3bff572e3ed997fbe Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Mon, 4 Mar 2024 12:40:29 -0800 Subject: [PATCH 2/2] address review comments --- Lib/test/test_enum.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 68d1e2ec20fa01..0a44b61e9049ed 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -3415,8 +3415,8 @@ class Cardinal(Enum): UP = (0, 1) LEFT = (-1, 0) DOWN = (0, -1) - Cardinal(1, 0) - Cardinal(-1, 0) + self.assertIs(Cardinal(1, 0), Cardinal.RIGHT) + self.assertIs(Cardinal(-1, 0), Cardinal.LEFT) def test_no_members(self): with self.assertRaisesRegex( @@ -3430,6 +3430,20 @@ def test_no_members(self): ): 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"