]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-39679: Add tests for classmethod/staticmethod singledispatchmethods (GH-29034)
authorAlex Waygood <Alex.Waygood@Gmail.com>
Tue, 19 Oct 2021 20:30:27 +0000 (21:30 +0100)
committerGitHub <noreply@github.com>
Tue, 19 Oct 2021 20:30:27 +0000 (22:30 +0200)
In Python 3.8 and 3.9, stacking `@functools.singledispatchmethod` on top of
`@classmethod` or `@staticmethod` caused an exception to be raised if the
method was registered using type-annotations rather than
`@method.register(int)`. This was not caught by unit tests, however, as the
tests only tested the `@method.register(int)` way of registering additional
implementations. The bug is no longer present in Python 3.10+, but
`test_functools.py` is still lacking regression tests for these cases. This
commit adds these test cases.

Lib/test/test_functools.py
Misc/NEWS.d/next/Tests/2021-10-18-16-18-41.bpo-39679.F18qcE.rst [new file with mode: 0644]

index fece8256a3e2619f485799b2a4ac42a7f3f81f97..bdb4ddcc60cac2b0c57207717e67185ae008a52f 100644 (file)
@@ -2437,6 +2437,48 @@ class TestSingleDispatch(unittest.TestCase):
         self.assertEqual(a.t(''), "str")
         self.assertEqual(a.t(0.0), "base")
 
+    def test_staticmethod_type_ann_register(self):
+        class A:
+            @functools.singledispatchmethod
+            @staticmethod
+            def t(arg):
+                return arg
+            @t.register
+            @staticmethod
+            def _(arg: int):
+                return isinstance(arg, int)
+            @t.register
+            @staticmethod
+            def _(arg: str):
+                return isinstance(arg, str)
+        a = A()
+
+        self.assertTrue(A.t(0))
+        self.assertTrue(A.t(''))
+        self.assertEqual(A.t(0.0), 0.0)
+
+    def test_classmethod_type_ann_register(self):
+        class A:
+            def __init__(self, arg):
+                self.arg = arg
+
+            @functools.singledispatchmethod
+            @classmethod
+            def t(cls, arg):
+                return cls("base")
+            @t.register
+            @classmethod
+            def _(cls, arg: int):
+                return cls("int")
+            @t.register
+            @classmethod
+            def _(cls, arg: str):
+                return cls("str")
+
+        self.assertEqual(A.t(0).arg, "int")
+        self.assertEqual(A.t('').arg, "str")
+        self.assertEqual(A.t(0.0).arg, "base")
+
     def test_invalid_registrations(self):
         msg_prefix = "Invalid first argument to `register()`: "
         msg_suffix = (
diff --git a/Misc/NEWS.d/next/Tests/2021-10-18-16-18-41.bpo-39679.F18qcE.rst b/Misc/NEWS.d/next/Tests/2021-10-18-16-18-41.bpo-39679.F18qcE.rst
new file mode 100644 (file)
index 0000000..b0d1b68
--- /dev/null
@@ -0,0 +1,2 @@
+Add more test cases for `@functools.singledispatchmethod` when combined with
+`@classmethod` or `@staticmethod`.