]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-125316: Fix using partial() as Enum member (GH-125361)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 21 Oct 2024 13:31:42 +0000 (16:31 +0300)
committerGitHub <noreply@github.com>
Mon, 21 Oct 2024 13:31:42 +0000 (16:31 +0300)
A FutureWarning with suggestion to use enum.member() is now emitted
when the partial instance is used as an enum member.

Lib/enum.py
Lib/test/test_enum.py
Misc/NEWS.d/next/Library/2024-10-12-15-49-17.gh-issue-125316.t15RnJ.rst [new file with mode: 0644]

index 0c2135f9040bac9d02e848fedef960f69e255a72..78df81d24a9adf376b8b9224c459692ffd597d8e 100644 (file)
@@ -1,5 +1,6 @@
 import sys
 import builtins as bltns
+from functools import partial
 from types import MappingProxyType, DynamicClassAttribute
 
 
@@ -37,7 +38,7 @@ def _is_descriptor(obj):
     """
     Returns True if obj is a descriptor, False otherwise.
     """
-    return (
+    return not isinstance(obj, partial) and (
             hasattr(obj, '__get__') or
             hasattr(obj, '__set__') or
             hasattr(obj, '__delete__')
@@ -402,6 +403,12 @@ class EnumDict(dict):
         elif isinstance(value, nonmember):
             # unwrap value here; it won't be processed by the below `else`
             value = value.value
+        elif isinstance(value, partial):
+            import warnings
+            warnings.warn('functools.partial will be a method descriptor '
+                          'in future Python versions; wrap it in '
+                          'enum.member() if you want to preserve the '
+                          'old behavior', FutureWarning, stacklevel=2)
         elif _is_descriptor(value):
             pass
         elif _is_internal_class(self._cls_name, value):
index 5b4a8070526fcf851ea9fe732b62b35fd3ac7f7e..46f57b2d9b641a94b801d6e6c1abb22b79479c8d 100644 (file)
@@ -11,6 +11,7 @@ import typing
 import builtins as bltns
 from collections import OrderedDict
 from datetime import date
+from functools import partial
 from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
 from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
 from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
@@ -1537,6 +1538,19 @@ class TestSpecial(unittest.TestCase):
             [Outer.a, Outer.b, Outer.Inner],
             )
 
+    def test_partial(self):
+        def func(a, b=5):
+            return a, b
+        with self.assertWarnsRegex(FutureWarning, r'partial.*enum\.member') as cm:
+            class E(Enum):
+                a = 1
+                b = partial(func)
+        self.assertEqual(cm.filename, __file__)
+        self.assertIsInstance(E.b, partial)
+        self.assertEqual(E.b(2), (2, 5))
+        with self.assertWarnsRegex(FutureWarning, 'partial'):
+            self.assertEqual(E.a.b(2), (2, 5))
+
     def test_enum_with_value_name(self):
         class Huh(Enum):
             name = 1
diff --git a/Misc/NEWS.d/next/Library/2024-10-12-15-49-17.gh-issue-125316.t15RnJ.rst b/Misc/NEWS.d/next/Library/2024-10-12-15-49-17.gh-issue-125316.t15RnJ.rst
new file mode 100644 (file)
index 0000000..07b642d
--- /dev/null
@@ -0,0 +1,3 @@
+Fix using :func:`functools.partial` as :class:`enum.Enum` member. A
+FutureWarning with suggestion to use :func:`enum.member` is now emitted when
+the ``partial`` instance is used as an enum member.