Tuple/List get_item to fallible#1733
Conversation
There was a problem hiding this comment.
Thanks for kicking this off!
Another way to design this which is potentially better for migration is to deprecate .get_item() and to introduce two new methods:
.get() -> PyResult<&PyAny>.get_unchecked() -> &PyAny, doesn't do checking and only available on#[cfg(not(Py_LIMITED_API))]
Or .get() -> Option<&PyAny>, if handling the error internally feels appropriate. I'd be open to opinions on this.
Regarding the .extract() error, you should check for uses of .get_item() inside pyo3-macros-backend. TBH this is an example why deprecating get_item might be the better idea - the compilation will still go through and you'll just get warnings of where it's used, which can be fixed instead.
|
@davidhewitt |
8e5484e to
c4216a1
Compare
davidhewitt
left a comment
There was a problem hiding this comment.
Thanks, this is taking shape!
@birkenfeld as you came up with the proposals in #1667 I'd be really interested for your opinion on this.
c598465 to
996b677
Compare
mejrs
left a comment
There was a problem hiding this comment.
Thanks :)
I do have some suggestions..
src/types/list.rs
Outdated
| } | ||
|
|
||
| /// Gets the list item at the specified index. | ||
| pub fn get(&self, index: usize) -> PyResult<&PyAny> { |
There was a problem hiding this comment.
We should consider using isize rather than usize for this, if we still want negative indexing per #1667 (?).
There was a problem hiding this comment.
We want negative indexing, but when using index (slicing). There's no real sense in implementing it at this function level.
There was a problem hiding this comment.
Personally I'm leaning towards using usize everywhere, anyway 👍
There was a problem hiding this comment.
I don't see why this should only be relevant for slicing. Python allows negative indices for single item access as well as for slices. IMO either we allow negative indices for both, or none.
birkenfeld
left a comment
There was a problem hiding this comment.
I'm happy with returning PyResult. The new name makes the API asymmetric (get vs set_item, and btw why is there is no del_item or remove...) Are we still allowed to break APIs if the result is a clear compile error?
usize vs isize needs to be discussed still.
A follow-up to this is the implementation of Index traits.
src/types/list.rs
Outdated
| } | ||
|
|
||
| /// Gets the list item at the specified index. | ||
| pub fn get(&self, index: usize) -> PyResult<&PyAny> { |
There was a problem hiding this comment.
I don't see why this should only be relevant for slicing. Python allows negative indices for single item access as well as for slices. IMO either we allow negative indices for both, or none.
src/types/list.rs
Outdated
| let item = self.list.get_item(self.index); | ||
| if self.index < self.list.len() { | ||
| #[cfg(any(Py_LIMITED_API, PyPy))] | ||
| let item = self.list.get(self.index).expect("tuple.get failed"); |
Yes, we could change Sorry @aviramha you picked a ticket which has a lot of open design questions 🙃 I definitely think if we call it |
That's OK. the get_item of Python is actually usize, so it might be more confusing that it works with negative indices. I guess it's a question whether you want the API to feel like a Rust wrapper to the CPython or a rust wrapper to the Python API. |
|
That's a fair question. I think I'm now leaning towards this matching the C API, so would vote for |
Goes without saying that I am too. How do we make this call? 🙃 |
|
If it looks like a majority of us agree, I'm happy for us to commit to this plan (cc @birkenfeld @mejrs @messense). |
|
Where would |
|
To be clear, I'm not opposed to doing away with |
|
@birkenfeld I understand your concern but I believe that's CPython inconsistency issue. It depends on what we value more - being consistent with it or improving it. |
|
To make myself more clear (previous comment was from mobile) - when coding in PyO3 I often use the CPython docs to understand how stuff works - having different API (i.e get_item of PyO3 accepts negative indices vs CPython not) can easily cause confusion for anyone. |
|
The expectation of each PyO3 method mapping exactly to one Python C-API call is misguided, though. If you are missing info from the PyO3 docs which is integral to understanding the API in question, it is a bug and should be fixed; please report that here. And of course, in the case we're discussing here, the documentation would need to state that negative indices are supported and how they are interpreted. (That this is not documented currently is one of the points of #1667.) |
|
I definitely agree that we should go for all- Here's the arguments I can see either way: usizeGood:
Bad:
isizeGood:
Bad:
An alternative... what if we made I think this "mixed-mode" would match the C-API in every way except |
|
@davidhewitt thanks for the recap Indexing and slicing with negative numbers doesn't seem like a good idea to me:
|
|
Cool. @davidhewitt Waiting for your review : |
|
👍 will try to give a full read within the next few days! |
davidhewitt
left a comment
There was a problem hiding this comment.
Thanks for pushing forward on this! I'm afraid there's a few bits and pieces which still need tidying up. Comments scattered below.
@davidhewitt should I change get_slice to also use usize?
Before we release 0.15 we'll need to change all these tuple / list / sequence APIs which currently take isize to take usize. This PR is already big enough, so maybe it's better to make a list of what still needs to change in #1667 and then make follow-up PRs.
9880cb4 to
8cbf9f9
Compare
|
Thanks for the review. I think I fixed all of the comments :) |
davidhewitt
left a comment
There was a problem hiding this comment.
The changes are looking reasonable to me... but CI has a segfault?
|
Oopsie, I thought the CI failure was main's fault |
davidhewitt
left a comment
There was a problem hiding this comment.
Ahh I think I've found another cause of segfault... Fingers crossed CI green after 🤞
davidhewitt
left a comment
There was a problem hiding this comment.
👍 looks brilliant! Thanks again for your patience and many iterations as we worked out the design for this.
I'll merge this shortly (just going to cherry-pick some fixes for a 0.14.3 bugfix release first).
|
(See #1796 - as soon as that release is live I'll merge this. It just makes my life easier if I try to cherry-pick other stuff and there's no more breaking changes 😉) |
You're welcome! Glad to contribute to an awesome framework. |
🚀 If you want to own this, that would be awesome! The easiest way might be to create a new issue where you can own a list of checkboxes and close them as we make progress? |
|
Since 0.14.x is going to be in a branch, can we merge this? |
|
Ok 👍 I'm getting more used to doing the cherry-picking onto the 0.14.3 branch now, so let's proceed with this. I see I created a merge conflict by merging #1802, so I'll fixup this quickly now... |
e32641a to
33b056b
Compare
…`usize` indices instead of `isize`. - `PyList` and `PyTuple`'s `get_item` now always uses the safe API. See `get_item_unchecked` for retrieving index without checks.
33b056b to
c6255e6
Compare
Hey, trying to help with:
#1667
specifically:
make PyTuple::get_item and PyList::get_item fallible
I'm not quite sure about the extract thingy, any guidance or feedback will be welcome.