functools.singledispatchfunction has confusing error message if no positional arguments are passed in
| BPO | 41122 |
|---|---|
| Nosy | @rhettinger, @ambv, @mgrandi, @ammaraskar, @mental32, @AlexWaygood |
| PRs |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = None
closed_at = None
created_at = <Date 2020-06-26.03:29:31.194>
labels = ['type-bug', 'library', '3.9', '3.10', '3.11']
title = 'functools.singledispatchfunction has confusing error message if no positional arguments are passed in'
updated_at = <Date 2021-11-05.16:40:42.304>
user = 'https://github.com/mgrandi'
bugs.python.org fields:
activity = <Date 2021-11-05.16:40:42.304>
actor = 'AlexWaygood'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2020-06-26.03:29:31.194>
creator = 'markgrandi'
dependencies = []
files = []
hgrepos = []
issue_num = 41122
keywords = ['patch']
message_count = 1.0
messages = ['372406']
nosy_count = 6.0
nosy_names = ['rhettinger', 'lukasz.langa', 'markgrandi', 'ammar2', 'mental', 'AlexWaygood']
pr_nums = ['21471', '23212']
priority = 'normal'
resolution = None
stage = 'patch review'
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue41122'
versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']
this is with python 3.8:
PS C:\Users\mark> py -3 --version --version
Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)]
So when using functools.singledispatch or functools.singledispatchmethod, you need to provide at least 1 positional argument so it can dispatch based on the type of said argument
however, with functools.singledispatchmethod, you get an error message that is confusing and not obvious what the problem is.
Example with functools.singledispatchmethod:
class NegatorTwo:
@singledispatchmethod
def neg(arg):
raise NotImplementedError("Cannot negate a")
@neg.register
def _(self, arg: int):
return -arg
@neg.register
def _test(self, arg: bool):
return not arg
if __name__ == "__main__":
n = NegatorTwo()
print(n.neg(0))
print(n.neg(False))
print(n.neg(arg=0))
you end up getting:
PS C:\Users\mark> py -3 C:\Users\mark\Temp\singledisp.py
0
True
Traceback (most recent call last):
File "C:\Users\mark\Temp\singledisp.py", line 58, in <module>
print(n.neg(arg=0))
File "C:\Python38\lib\functools.py", line 910, in _method
method = self.dispatcher.dispatch(args[0].__class__)
IndexError: tuple index out of range
but with just regular functools.singledispatch:
@functools.singledispatch
def negate_func(arg):
raise NotImplementedError("can't negate")
@negate_func.register
def negate_int_func(arg:int):
return -arg
@negate_func.register
def negate_bool_func(arg:bool):
return not arg
if __name__ == "__main__":
print(negate_func(0))
print(negate_func(False))
print(negate_func(arg=0))
you get an error that tells you what actually is wrong:
PS C:\Users\mark> py -3 C:\Users\mark\Temp\singledisp.py
0
True
Traceback (most recent call last):
File "C:\Users\mark\Temp\singledisp.py", line 63, in <module>
print(negate_func(arg=0))
File "C:\Python38\lib\functools.py", line 871, in wrapper
raise TypeError(f'{funcname} requires at least '
TypeError: negate_func requires at least 1 positional argument
it seems that the code in functools.singledispatchmethod needs to check to see if args is empty, and throw a similar (if not the same) exception as functools.singledispatch
Any progress with this, I apparently found this by chance after having spent a good hour to understand the missing positional argument was the cause of my troubles.
I'm on Python 3.10.7