Skip to content

Generate AttributeError messages from their context #153785

Description

@johnslavik

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 (+):

importtracebackclassFoo1:
def__getattr__(self, name):
raiseAttributeError(name)
try:
Foo1().missing1exceptAttributeErrorasa:
print(f"-{traceback.format_exc().splitlines()[-1]}")
print(f"+AttributeError: {a.obj} has no attribute {a.name!r}\n")
classFoo2:
def__getattr__(self, name):
raiseAttributeErrortry:
Foo2().missing2exceptAttributeErrorasa:
print(f"-{traceback.format_exc().splitlines()[-1]}")
print(f"+AttributeError: {a.obj} has no attribute {a.name!r}\n")
importmod1# def __getattr__(name): raise AttributeError(name)try:
mod1.missing3exceptAttributeErrorasa:
print(f"-{traceback.format_exc().splitlines()[-1]}")
print(f"+AttributeError: {a.obj} has no attribute {a.name!r}\n")
importmod2# def __getattr__(name): raise AttributeErrortry:
mod2.missing4exceptAttributeErrorasa:
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:

fromfunctoolsimportsingledispatchmethodclassC:
@singledispatchmethoddefsdm(self, a):
passC().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

Linked PRs

Metadata

Metadata

Assignees

Labels

interpreter-core(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancement

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions