This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Add an 'attr' attribute to AttributeError
Type: enhancement Stage: test needed
Components: Interpreter Core Versions: Python 3.4
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: ag6502, alex, benjamin.peterson, brett.cannon, eric.araujo, ezio.melotti, flying sheep, kermit666, serhiy.storchaka, vstinner, xiang.zhang
Priority: normal Keywords: patch

Created on 2013-06-07 15:31 by brett.cannon, last changed 2022-04-11 14:57 by admin.

Files
File name Uploaded Description Edit
attributeerror-attr.patch kermit666, 2013-07-06 16:56 review
client.py Shubham Dash, 2015-10-12 16:30
Repositories containing patches
https://bitbucket.org/kermit666/cpython/src/0fa84b73a4e5f09846327d90041ba9c645cf11a3?at=attr
Messages (15)
msg190754 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-06-07 15:31
Much like ImportError now has 'name' and 'path', AttributeError should get an 'attr' attribute that can only be set through a keyword argument or after creating an instance. That would make the common ``try/except AttributeError`` uses much more robust by not accidentally swallowing an AttributeError that has nothing to do with the attribute in question::

 try:
   cls.meth()
 except AttributeError as exc:
   if exc.attr != 'meth':
     raise
msg190783 - (view) Author: Alex Gaynor (alex) * (Python committer) Date: 2013-06-08 00:03
+1 on this, but it's worth noting that that fix is not 100% correct (though it's obviously better than most existing equivilants), it's potentially wrong with custom __getattr__, __getattribute__, descriptors.
msg190787 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2013-06-08 01:47
Such custom implementations should be updated to support this wonderful new attr. :)
msg190788 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-06-08 01:54
What Benjamin said.

Adding something like this is mostly about a nicer constructor (``AttributeError(attr='meth')``) and automatically creating the message for the exception (although that would require another argument like 'object' or something to be able to do e.g. "'dict' object has no attribute 'asdfdsff'" or "type object 'dict' has no attribute 'asdfdsf'").
msg190789 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-06-08 01:54
And standardizing on an attribute name, of course. =)
msg192466 - (view) Author: Dražen Lučanin (kermit666) * Date: 2013-07-06 16:56
I've been working on this at the EuroPython sprint today and it seems the change requires editing >20 files that call PyExc_AttributeError. This means it would be quite a big and dangerous change, so for now I just attach the optional argument addition - without it actually being used by the rest of the codebase.

What is your oppinion on it?
msg192468 - (view) Author: Andrea Griffini (ag6502) * Date: 2013-07-06 17:08
Even porting to the new wonderful 'attr' field is not going to make the code correct... (the exception could be bubbling up from code down ten frames about a different unrelated attribute that happens to have the same name in a different object). BTW cpython has a lot of those "except AttributeError" fragments coded in C with PyErr_ExceptionMatches.
msg192470 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-07-06 17:22
Dražen: didn't do a deep review, but a cursory look suggests the patch is fine.

As for having to change a ton of files to start using the attribute, that's part of the effect of changing something as basic as an exception. If you would rather break it up into separate patches that's fine. But I would caution you from doing more than this patch as I have gotten some push back from other core devs on my proposed new attributes on exceptions so I don't want you spending your time on something that might get sunk (although if you are enjoying it then go for it since if it gets accepted this work will be needed).

Also please sign the contributor agreement form (http://python.org/psf/contrib/contrib-form/) so that we can actually use your code.

Andrea: While the attribute might coincidentally name an attribute that is the same as some other attribute which is not the actual trigger, the traceback on the exception provides the proper context to know what attribute in what code did the actual triggering. The point is that the exception can be considered better than nothing and is still an improvement over not having the information at all.
msg192555 - (view) Author: Dražen Lučanin (kermit666) * Date: 2013-07-07 13:34
OK, thanks for the feedback. I signed the CLA.

I'll then wait with the remaining work, until a final decision has been made. We have a rough idea of how it could be implemented if it comes to this - adding a wrapper function in Python/errors.c:

    PyErr_SetAttributeError(PyObject *attr, const char *format, ...)

that would replace all the PyErr_SetObject, PyErr_SetString and PyErr_Format calls (in around 50 files), create the kwargs object, format the message (if provided) and call PyErr_SetObject or PyErr_SetFormat.

I put the last patch as a commit in the attr bookmark on BitBucket (took me quite some time to figure out that's the alternative to git branches), so that subsequent changes go more easily.
msg229928 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-10-24 15:10
In issue22716 proposed to add a reference to the object missing an attribute.
msg230501 - (view) Author: Ezio Melotti (ezio.melotti) * (Python committer) Date: 2014-11-02 16:09
I closed #22716 in favor of this, since I think both should be tackled together.
msg230504 - (view) Author: (flying sheep) * Date: 2014-11-02 16:34
yeah, exactly: my idea was to add a reference to the original object (AttributeError.target). together with this bug, that would be the AttributeError part of PEP 473, which i really like!
msg261307 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-03-07 17:31
I'd like to ping this channel.

I post a question on https://groups.google.com/forum/#!topic/comp.lang.python/y8yDAAJJ9Sc to ask if it is possible to directly get the attribute from AttributeError, which leads me here.
msg261355 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2016-03-08 12:36
> try:
>   cls.meth()
> except AttributeError as exc:
>   if exc.attr != 'meth':
>     raise

What if cls.__getattr__('meth') calls a completly unrelated function which also raises AttributeError(attr='meth') but on a different object? I would also expect an "obj" attribute, a reference to the object which doesn't have attribute.

But AttributeError can be raised manually without setting attr and/or obj attribute. So the best test would look to something like:

if exc.obj is cls and exc.attr is not None and exc.attr != 'meth':
    raise

The test is much more complex than expected :-/ Maybe it's simpler to split the code to first get the bounded method?

try:
   meth = cls.meth
except AttributeError:
   ...
meth()

Or check first if cls has the attribute 'meth' with hasattr(cls, 'meth')?

--

About attr/obj attribute not set, an alternative is to add a new BetterAttributeError(obj, attr) exception which requires obj and attr to be set, it inherits from AttributeError.

class BetterAttributeError(AttributeError):
   def __init__(self, obj, attr):
       super().__init__('%r has no attribute %r' % (obj, attr)
       self.obj = obj
       self.attr = attr

It would allow a smoother transition from "legacy" AttributeError to the new BetterAttributeError.

The major issue with keeping a strong reference to the object is that Python 3 introduced Exception.__traceback__ which can create a reference cycle if an exception is stored in a local variable somewhere in the traceback. It's a major pain point in asyncio. In asyncio, the problem is more likely since exceptions are stored in Future objects to be used later.
msg261394 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-03-09 02:00
The concerns mentioned by haypo seems to have existed in PEP473.
History
Date User Action Args
2022-04-11 14:57:46adminsetgithub: 62356
2017-08-18 16:16:17brett.cannonsetkeywords: - easy
2016-03-09 02:00:40xiang.zhangsetmessages: + msg261394
2016-03-08 12:36:33vstinnersetnosy: + vstinner
messages: + msg261355
2016-03-07 17:31:24xiang.zhangsetnosy: + xiang.zhang
messages: + msg261307
2015-10-12 16:30:54Shubham Dashsetfiles: + client.py
2014-11-02 16:34:06flying sheepsetnosy: + flying sheep
messages: + msg230504
2014-11-02 16:09:54ezio.melottisetmessages: + msg230501
2014-10-25 15:26:33r.david.murrayunlinkissue22716 superseder
2014-10-24 15:10:31serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg229928
2014-10-24 15:07:45serhiy.storchakalinkissue22716 superseder
2013-07-07 13:34:34kermit666sethgrepos: + hgrepo203
messages: + msg192555
2013-07-06 17:22:44brett.cannonsetmessages: + msg192470
2013-07-06 17:08:18ag6502setmessages: + msg192468
2013-07-06 16:56:12kermit666setfiles: + attributeerror-attr.patch

nosy: + ag6502, kermit666
messages: + msg192466

keywords: + patch
2013-06-08 17:51:30ezio.melottisetkeywords: + easy
nosy: + ezio.melotti
2013-06-08 01:54:37brett.cannonsetmessages: + msg190789
2013-06-08 01:54:05brett.cannonsetmessages: + msg190788
2013-06-08 01:47:09benjamin.petersonsetnosy: + benjamin.peterson
messages: + msg190787
2013-06-08 00:03:34alexsetnosy: + alex
messages: + msg190783
2013-06-07 18:27:56eric.araujosetnosy: + eric.araujo
2013-06-07 15:31:50brett.cannoncreate