classification
Title: Add a 'key' attribute to KeyError
Type: enhancement Stage: test needed
Components: Versions:
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: aroberge, barry, brett.cannon, cvrebert, ezio.melotti, p4m-dev, r.david.murray, rhettinger, sblondon, zingero
Priority: normal Keywords:

Created on 2013-06-07 20:51 by brett.cannon, last changed 2021-02-18 18:52 by aroberge.

Messages (12)
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:
	d['roger']
except KeyError as e:
	print(e.args)

	
('roger',)
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'"
msg378075 - (view) Author: Orian Zinger (zingero) Date: 2020-10-05 20:39
Hi all,

As a Python developer, I encountered lots of blurry exception messages in the product logs such as:
<time and date> <process name> <log severity> Failed to do something. Exception: 'some key'

I believe printing the key name without explaining the exception itself is bad (explicit is better than implicit).

Thus, after forking the repository, I added a short explanation about the Exception.
Now, it looks like:

>>> try:
...     {}['some key']
... except Exception as e:
...     print(e)
... 
Missing key: some key

I'm a newbie in a contribution to CPython, so please let me know if the idea behind my commit is good. If not, please explain how can I improve my commit so it'll be pulled later to the main branch.

https://github.com/zingero/cpython/commit/8c9e5d9e16296cee1f3ec05638dd6989dae8b811

Regards,
Orian.
msg378253 - (view) Author: Anatoliy Platonov (p4m-dev) * Date: 2020-10-08 15:54
I agree with Mark. I will be useful to provide ability to specify custom long message for error. And logically it would be better to do not allow users change key field in error so easy.
msg383445 - (view) Author: St├ęphane Blondon (sblondon) * Date: 2020-12-20 20:39
Orian: your patch formats the error message but the original suggested  solution is to store the missing key in a new attribute. 

I don't know if you go in the good direction.

Adding an attribute is also suggested by issue #614557.
msg386890 - (view) Author: St├ęphane Blondon (sblondon) * Date: 2021-02-12 23:10
I'm interested by such feature.

I see examples of versions of the message provided by KeyError:
- sometimes with a message (for example `PyErr_SetString(PyExc_KeyError, "name too long");` at [1])
- sometimes with the missing key (for example `PyErr_SetObject(PyExc_KeyError, key);` at [2])

It explains why there is a difference in the messages in KeyError (as said in previous messages).

PyErr_SetString(), PyErr_Format(), PyErr_FormatV() (implemented in Python/errors.c) don't have a parameter to set the missing key. So I think it would be easier to set the missing attribute before calling thoses functions.


According to [3], the C PyExc_KeyError matches the Python KeyError exception.

So I think to:
- Add a 'missing_key' attribute to KeyError_str (in [4])
- Add the missing key to PyExc_KeyError instance before the call of PyErr_SetString(), PyErr_SetObject(), etc.

Do you think such strategy is doable?
What do you think about it? Is it the way you think about it? If not, do you have some hint?


I already made some minor patches to cpython but only in the Python part, never in C one.


1: https://github.com/python/cpython/blob/master/Modules/unicodedata.c#L1398
2: https://github.com/python/cpython/blob/master/Python/hamt.c#L2767
3: https://docs.python.org/3/c-api/exceptions.html?highlight=pyerr_format#standard-exceptions
4: https://github.com/python/cpython/blob/master/Objects/exceptions.c#L1569
History
Date User Action Args
2021-02-18 18:52:19arobergesetnosy: + aroberge
2021-02-18 18:11:01mark.dickinsonsetnosy: - mark.dickinson
2021-02-12 23:10:10sblondonsetmessages: + msg386890
2020-12-20 20:39:21sblondonsetnosy: + sblondon

messages: + msg383445
versions: - Python 3.4
2020-10-08 15:54:35p4m-devsetnosy: + p4m-dev
messages: + msg378253
2020-10-05 20:40:25zingerosetcomponents: - Library (Lib)
2020-10-05 20:39:11zingerosetnosy: + zingero
messages: + msg378075
components: + Library (Lib), - Interpreter Core
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