From 8b776e0f41d7711f3e2be2435bf85f2d5fa6e009 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 16 Feb 2024 16:17:30 -0500 Subject: gh-85294: Handle missing arguments to @singledispatchmethod gracefully (GH-21471) Co-authored-by: Serhiy Storchaka --- Lib/functools.py | 5 ++++- Lib/test/test_functools.py | 17 ++++++++++++++++- .../Library/2020-07-13-23-59-42.bpo-41122.8P_Brh.rst | 3 +++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-07-13-23-59-42.bpo-41122.8P_Brh.rst diff --git a/Lib/functools.py b/Lib/functools.py index ee4197b..7045be5 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -918,7 +918,6 @@ def singledispatch(func): if not args: raise TypeError(f'{funcname} requires at least ' '1 positional argument') - return dispatch(args[0].__class__)(*args, **kw) funcname = getattr(func, '__name__', 'singledispatch function') @@ -968,7 +967,11 @@ class singledispatchmethod: return _method dispatch = self.dispatcher.dispatch + funcname = getattr(self.func, '__name__', 'singledispatchmethod method') def _method(*args, **kwargs): + if not args: + raise TypeError(f'{funcname} requires at least ' + '1 positional argument') return dispatch(args[0].__class__).__get__(obj, cls)(*args, **kwargs) _method.__isabstractmethod__ = self.__isabstractmethod__ diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 7c66b90..2c814d5 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -2867,11 +2867,26 @@ class TestSingleDispatch(unittest.TestCase): def test_invalid_positional_argument(self): @functools.singledispatch - def f(*args): + def f(*args, **kwargs): pass msg = 'f requires at least 1 positional argument' with self.assertRaisesRegex(TypeError, msg): f() + msg = 'f requires at least 1 positional argument' + with self.assertRaisesRegex(TypeError, msg): + f(a=1) + + def test_invalid_positional_argument_singledispatchmethod(self): + class A: + @functools.singledispatchmethod + def t(self, *args, **kwargs): + pass + msg = 't requires at least 1 positional argument' + with self.assertRaisesRegex(TypeError, msg): + A().t() + msg = 't requires at least 1 positional argument' + with self.assertRaisesRegex(TypeError, msg): + A().t(a=1) def test_union(self): @functools.singledispatch diff --git a/Misc/NEWS.d/next/Library/2020-07-13-23-59-42.bpo-41122.8P_Brh.rst b/Misc/NEWS.d/next/Library/2020-07-13-23-59-42.bpo-41122.8P_Brh.rst new file mode 100644 index 0000000..76568d4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-07-13-23-59-42.bpo-41122.8P_Brh.rst @@ -0,0 +1,3 @@ +Failing to pass arguments properly to :func:`functools.singledispatchmethod` +now throws a TypeError instead of hitting an index out of bounds +internally. -- cgit v0.12