diff --git a/Lib/functools.py b/Lib/functools.py index b1f1fe8d9a6f27..5867f78610fbee 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -911,6 +911,16 @@ def register(self, cls, method=None): def __get__(self, obj, cls=None): def _method(*args, **kwargs): + funcname = getattr( + self.func, + '__name__', + 'singledispatchmethod' + ) + + if not args: + raise TypeError(f'{funcname!r} requires' + ' at least 1 positional argument') + method = self.dispatcher.dispatch(args[0].__class__) return method.__get__(obj, cls)(*args, **kwargs) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index bee9f9112bf183..ec0e2d79becbdf 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -2449,6 +2449,15 @@ def f(*args): with self.assertRaisesRegex(TypeError, msg): f() + class _: + @functools.singledispatchmethod + def f(self, *args): + pass + + msg = '\'f\' requires at least 1 positional argument' + with self.assertRaisesRegex(TypeError, msg): + _().f() + class CachedCostItem: _cost = 1 diff --git a/Misc/NEWS.d/next/Library/2020-11-10-06-27-54.bpo-41122.dFW3eC.rst b/Misc/NEWS.d/next/Library/2020-11-10-06-27-54.bpo-41122.dFW3eC.rst new file mode 100644 index 00000000000000..b33adab8250921 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-10-06-27-54.bpo-41122.dFW3eC.rst @@ -0,0 +1,3 @@ +singledispatchmethod decorated methods now raise TypeError with an appropriate +message when called without the required positional argument, previously a +confusing IndexError was propagated to the user.