Title: Add a 'key' attribute to KeyError
Type: enhancement Stage: test needed
Components: Interpreter Core Versions: Python 3.4
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: barry, brett.cannon, cvrebert, ezio.melotti, mark.dickinson, r.david.murray, rhettinger
Priority: normal Keywords:

Created on 2013-06-07 20:51 by brett.cannon, last changed 2013-06-15 21:05 by ezio.melotti.

Messages (8)
msg190778 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-06-07 20:51
KeyError could grow a 'key' attribute for the key that triggered the exception. Since keys are expected to be immutable (in order to be hashable) there is no GC issue to worry about.
msg190782 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-06-07 21:11
I don't see how the fact that keys are immutable implies there are no GC issues.  A tuple can be involved in a cycle, for example.
msg190786 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-06-08 01:43
So are you arguing it should be a weakref, or just saying you view the statement as false?
msg190791 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-06-08 02:18
I'm arguing that the statement is false.  I think that whether or not it should be a weakref in this and the other cases depends on whether you think an exception object should keep an object alive or not.  It is fairly unlikely that a key would get into a cycle with an error message, though certainly not impossible.

The "keep alive" question probably boils down to whether or not we want it to be the case that clearing the traceback attribute releases all the "extra" pointers an exception holds on to, or if it is acceptable that an arbitrary number of additional attributes might do so.

I'm inclined to think that using weakrefs would make using the attributes more complicated for relatively little gain.
msg190999 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2013-06-12 00:46
Since the key is already accessible via the "args" attribute, what is the point of a new attribute?

>>> d = {}
>>> try:
except KeyError as e:

msg191001 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-06-12 01:39
Making it unambiguous what piece of data is being retrieved, and allowing new code to have a more complex message than just 'Keyerror: xxxx' and still be able to get at only the missing key.
msg191038 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-06-12 17:36
What David said. =)

The fact that the key is the first value from args is almost happenstance as the exception message is customized in __str__() and not in what is passed to the exception. But what if I had defined __getattr__ or __getattribute__ and had some prefix requirement? It would be more helpful to say ``KeyError("{!r} does not start with py_".format(key))`` which breaks your args[0] usage but is a much more descriptive message and has no defined way to provide the key as an attribute.

It's basically "explicit is better than implicit" since there is no API guarantee that the first thing in 'args' for KeyError will in actuality be the key.
msg191083 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2013-06-13 15:47
+1.  I recently chastised a colleague for doing "raise KeyError(long_message)" instead of "raise KeyError(missing_item)".  When I went to the standard library to support my POV, I found (to my chagrin) a big mix of the two styles.

>>> from collections import ChainMap
>>> d = ChainMap({}, {})
>>> try:
...     d.pop('not there')
... except KeyError as e:
...     key, = e.args
>>> key
"Key not found in the first mapping: 'not there'"
Date User Action Args
2013-06-15 21:05:57ezio.melottisetnosy: + ezio.melotti
2013-06-14 16:20:42cvrebertsetnosy: + cvrebert
2013-06-13 15:47:53mark.dickinsonsetnosy: + mark.dickinson
messages: + msg191083
2013-06-12 17:36:23brett.cannonsetmessages: + msg191038
2013-06-12 01:39:51r.david.murraysetmessages: + msg191001
2013-06-12 00:46:23rhettingersetnosy: + rhettinger
messages: + msg190999
2013-06-08 02:18:37r.david.murraysetmessages: + msg190791
2013-06-08 01:43:43brett.cannonsetmessages: + msg190786
2013-06-07 21:23:14barrysetnosy: + barry
2013-06-07 21:11:01r.david.murraysetnosy: + r.david.murray
messages: + msg190782
2013-06-07 20:51:56brett.cannoncreate