Feature or enhancement
Proposal:
People very often raise AttributeError(name) (~40 occurrences in CPython repo) or raise AttributeError (bare, this is rarer), but when displaying the traceback this misses either the object targeted or both the object and the attribute name.
That information is already there. AttributeError.obj and AttributeError.name is automatically set via _PyObject_SetAttributeErrorContext and now is only used to calculate attribute suggestions. Let's improve error messages with it too.
Consider a few examples where the user could raise a bare AttributeError or AttributeError("attr"), how we handle it (-), and how we could handle it (+):
import traceback class Foo1: def __getattr__(self, name): raise AttributeError(name) try: Foo1().missing1 except AttributeError as a: print(f"-{traceback.format_exc().splitlines()[-1]}") print(f"+AttributeError: {a.obj} has no attribute {a.name!r}\n") class Foo2: def __getattr__(self, name): raise AttributeError try: Foo2().missing2 except AttributeError as a: print(f"-{traceback.format_exc().splitlines()[-1]}") print(f"+AttributeError: {a.obj} has no attribute {a.name!r}\n") import mod1 # def __getattr__(name): raise AttributeError(name) try: mod1.missing3 except AttributeError as a: print(f"-{traceback.format_exc().splitlines()[-1]}") print(f"+AttributeError: {a.obj} has no attribute {a.name!r}\n") import mod2 # def __getattr__(name): raise AttributeError try: mod2.missing4 except AttributeError as a: print(f"-{traceback.format_exc().splitlines()[-1]}") print(f"+AttributeError: {a.obj} has no attribute {a.name!r}\n")
-AttributeError: missing1 +AttributeError: <__main__.Foo1 object at 0x109f2c8a0> has no attribute 'missing1' -AttributeError +AttributeError: <__main__.Foo2 object at 0x109f2c8a0> has no attribute 'missing2' -AttributeError: missing3 +AttributeError: <module 'mod1' from './Python/cpython/mod1.py'> has no attribute 'missing3' -AttributeError +AttributeError: <module 'mod2' from './Python/cpython/mod2.py'> has no attribute 'missing4'
If we generate messages from collected context, we'll also fix some edge cases in the stdlib and snake knows where else. Consider this functools.singledispatchmethod edge case:
from functools import singledispatchmethod class C: @singledispatchmethod def sdm(self, a): pass C().sdm.__code__
which currently fails with - but could be +:
-AttributeError: . Did you mean: '__call__'? +AttributeError: '_singledispatchmethod_get' object has no attribute '__code__'. Did you mean: '__call__'?
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response