[Python-checkins] bpo-45678: Add more ``singledispatchmethod`` tests (GH-29412)
ambv
webhook-mailer at python.org
Fri Nov 5 06:06:27 EDT 2021
https://github.com/python/cpython/commit/32f55d1a5de66f9a86964fc0655d7a006a9d90b9
commit: 32f55d1a5de66f9a86964fc0655d7a006a9d90b9
branch: main
author: Alex Waygood <Alex.Waygood at Gmail.com>
committer: ambv <lukasz at langa.pl>
date: 2021-11-05T11:06:18+01:00
summary:
bpo-45678: Add more ``singledispatchmethod`` tests (GH-29412)
In order to fix a bug in the 3.9 branch in #29394, more tests were added to
``test_functools.py`` to ensure that ``singledispatchmethod`` still correctly
wrapped a target method, even if the target method had already been wrapped by
multiple other decorators. This PR brings the new tests into the 3.11 and 3.10
branches as well.
files:
A Misc/NEWS.d/next/Tests/2021-11-04-20-03-32.bpo-45678.1xNMjN.rst
M Lib/test/test_functools.py
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 1a3c921509d5e..7bc355ff7213e 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -2519,6 +2519,105 @@ def static_func(arg: int) -> str:
self.assertEqual(A.static_func.__name__, 'static_func')
self.assertEqual(A().static_func.__name__, 'static_func')
+ def test_double_wrapped_methods(self):
+ def classmethod_friendly_decorator(func):
+ wrapped = func.__func__
+ @classmethod
+ @functools.wraps(wrapped)
+ def wrapper(*args, **kwargs):
+ return wrapped(*args, **kwargs)
+ return wrapper
+
+ class WithoutSingleDispatch:
+ @classmethod
+ @contextlib.contextmanager
+ def cls_context_manager(cls, arg: int) -> str:
+ try:
+ yield str(arg)
+ finally:
+ return 'Done'
+
+ @classmethod_friendly_decorator
+ @classmethod
+ def decorated_classmethod(cls, arg: int) -> str:
+ return str(arg)
+
+ class WithSingleDispatch:
+ @functools.singledispatchmethod
+ @classmethod
+ @contextlib.contextmanager
+ def cls_context_manager(cls, arg: int) -> str:
+ """My function docstring"""
+ try:
+ yield str(arg)
+ finally:
+ return 'Done'
+
+ @functools.singledispatchmethod
+ @classmethod_friendly_decorator
+ @classmethod
+ def decorated_classmethod(cls, arg: int) -> str:
+ """My function docstring"""
+ return str(arg)
+
+ # These are sanity checks
+ # to test the test itself is working as expected
+ with WithoutSingleDispatch.cls_context_manager(5) as foo:
+ without_single_dispatch_foo = foo
+
+ with WithSingleDispatch.cls_context_manager(5) as foo:
+ single_dispatch_foo = foo
+
+ self.assertEqual(without_single_dispatch_foo, single_dispatch_foo)
+ self.assertEqual(single_dispatch_foo, '5')
+
+ self.assertEqual(
+ WithoutSingleDispatch.decorated_classmethod(5),
+ WithSingleDispatch.decorated_classmethod(5)
+ )
+
+ self.assertEqual(WithSingleDispatch.decorated_classmethod(5), '5')
+
+ # Behavioural checks now follow
+ for method_name in ('cls_context_manager', 'decorated_classmethod'):
+ with self.subTest(method=method_name):
+ self.assertEqual(
+ getattr(WithSingleDispatch, method_name).__name__,
+ getattr(WithoutSingleDispatch, method_name).__name__
+ )
+
+ self.assertEqual(
+ getattr(WithSingleDispatch(), method_name).__name__,
+ getattr(WithoutSingleDispatch(), method_name).__name__
+ )
+
+ for meth in (
+ WithSingleDispatch.cls_context_manager,
+ WithSingleDispatch().cls_context_manager,
+ WithSingleDispatch.decorated_classmethod,
+ WithSingleDispatch().decorated_classmethod
+ ):
+ with self.subTest(meth=meth):
+ self.assertEqual(meth.__doc__, 'My function docstring')
+ self.assertEqual(meth.__annotations__['arg'], int)
+
+ self.assertEqual(
+ WithSingleDispatch.cls_context_manager.__name__,
+ 'cls_context_manager'
+ )
+ self.assertEqual(
+ WithSingleDispatch().cls_context_manager.__name__,
+ 'cls_context_manager'
+ )
+ self.assertEqual(
+ WithSingleDispatch.decorated_classmethod.__name__,
+ 'decorated_classmethod'
+ )
+ self.assertEqual(
+ WithSingleDispatch().decorated_classmethod.__name__,
+ 'decorated_classmethod'
+ )
+
def test_invalid_registrations(self):
msg_prefix = "Invalid first argument to `register()`: "
msg_suffix = (
diff --git a/Misc/NEWS.d/next/Tests/2021-11-04-20-03-32.bpo-45678.1xNMjN.rst b/Misc/NEWS.d/next/Tests/2021-11-04-20-03-32.bpo-45678.1xNMjN.rst
new file mode 100644
index 0000000000000..736d5f65f961b
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2021-11-04-20-03-32.bpo-45678.1xNMjN.rst
@@ -0,0 +1,3 @@
+Add tests for scenarios in which :class:`functools.singledispatchmethod` is
+stacked on top of a method that has already been wrapped by two other
+decorators. Patch by Alex Waygood.
More information about the Python-checkins
mailing list