New submission from Steven Barker:

When a method is called with incorrect arguments (too many or too few, for 
instance), a TypeError is raised. The message in the TypeError generally of the 
form:

    foo() takes 2 positional arguments but 3 were given

I think the message should include the class name along with the method name, 
so it would say `SomeClass.foo` instead of just `foo`. Since that is 
`SomeClass.foo`'s __qualname__, it should not be too hard to get the right name 
in most situations.

Here's an example showing how the current error messages can be ambiguous:

class A:
    def foo(self, x):
        pass

class B:
    def foo(self, x, y): # different method signature!
        pass

lst = [A(), B()]

for item in lst:
    item.foo(1)  # raises TypeError: foo() missing 1 required positional 
argument: 'y'"

for item in lst:
    item.foo(1, 2) # raises "TypeError: foo() takes 2 positional arguments but 
3 were given"

In neither loop is is clear which class's `foo` method is causing the exception 
(nor does the traceback help, since it only shows the `item.foo(...)` line). Of 
course, in this example it's easy to see the two classes have `foo` methods 
with different signatures, but if there were hundreds of objects in the list 
and they were instances of dozens of different classes it would be rather more 
annoying to figure out which class has the incorrect method signature.

I've looked through the code and the two exceptions above come from the 
`format_missing` and `too_many_positional` functions in Python/ceval.c . It's 
not obvious how to patch them to use `__qualname__` instead of `__name__`, 
since they are taking the name from a code object, rather than a function 
object or bound method object (and code objects don't have an equivalent to 
`__qualname__`, only `co_name` which is related to `__name__`).

Several other argument related TypeError exceptions are raised directly in 
_PyEval_EvalCodeWithName, which *does* have a `qualname` parameter, though the 
function doesn't use it for much. It's also where the other functions described 
above get called from, so it could probably pass the `qualname` along to them. 
Alas, it seems that in some common cases (such as calling a Python function 
with any kind of argument unpacking like `*foo` or `**foo`), the value of the 
`qualname` parameter is actually Null, so it may not be of much help.

A few extra TypeErrors related to function calls are raised directly in the 
gigantic `PyEval_EvalFrameEx` function. These seem to all use 
`PyEval_GetFuncName` to get the name, so perhaps we could modify its behavior 
to return the method's `__qualname__` rather than the `__name__`. (I have no 
idea what backwards compatibility issues this might cause. Perhaps a new 
function that returns the qualname would be better.)

----------
messages: 269274
nosy: Steven.Barker
priority: normal
severity: normal
status: open
title: When a TypeError is raised due to invalid arguments to a method, it 
should use __qualname__ to identify the class the method is in
type: enhancement
versions: Python 3.6

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue27389>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to