fix: include key in KeyError in map.__getitem__/__delitem__#5397
fix: include key in KeyError in map.__getitem__/__delitem__#5397rwgk merged 11 commits intopybind:masterfrom
Conversation
|
Looks useful, thanks. Could you please add tests? (Please tag me when it's ready for review with tests.) |
|
@rwgk Tests added, ready for review. |
include/pybind11/stl_bind.h
Outdated
| auto it = m.find(k); | ||
| if (it == m.end()) { | ||
| throw key_error(); | ||
| throw key_error(str(cast(k)).cast<std::string>()); |
There was a problem hiding this comment.
Looking at this more closely, there are a bunch of things that can go wrong:
cast(k)may fail,str(...)may fail,.cast<std::string>()may fail.
Any of those failures will be a secondary error, masking the desired KeyError. This can be extremely confusing.
Making this robust is not easy.
What's needed is something like (untested; only to give the idea):
str key_as_str;
try {
key_as_str = str(cast(k));
}
catch (const std::exception&) {
throw key_error();
}
set_error(PyExc_KeyError, key_as_tr);
throw error_already_set();
This would be implemented in a helper function.
Another thought: if str() fails, try repr().
Oh, there should also be a size limit. I.e. you don't want to produce a 1M numpy array as a str.
Sorry to make this difficult, but these things sure will bite, someone.
There was a problem hiding this comment.
@rwgk PTAL. I added a test for long keys. I don't know what kind of object would fail in str of cast - happy to add a test if you have a suggestion. What is the benefit of set_error + throw error_already_set() over throw key_error() ?
|
I added commit ef17743 to reduce the amount of templated code. Waiting for GitHub Actions to finish. |
|
LGTM, thank you! |
Also rename variable to `cut_length`, to not get into even/odd issues with the meaning of "half".
Description
When a C++ container is bound by
bind_mapand one accesses or deletes an element that does not exist, pybind11 currently raises an empty, uninformative message:KeyError: ''. This PR prints the key, which is the behavior of Python'sdict.Suggested changelog entry: