New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PySequence_GetItem
adjusting negative indexes make it difficult to handle them properly
#96436
Comments
I would use PyObject_GetItem() for this purpose. That is the intended way to emulate the pure python call Ideally, we should add a recommendation to not use the |
Agreed it's fair to say that
I think this recommendation isn't quite correct, there are many cases in CPython where What I notice is that that every usage in CPython where I can find As you point out, users of the C/API are would already be aware of the |
These are part of the stable ABI and have been around for very long time. Deprecating them would be highly disruptive. I think it is sufficient to document that caller should use |
The point I am trying to get across is that in my eyes the issue here makes it impossible for me as a sequence implementor to handle negative indices correctly. Maybe documenting what a user of The status quo in the standard library sequences such as tuple is that I would still hope we can explore the solution space to see if there's a long-term resolution we can implement. Hence my proposal #96437 to add a flag to opt out of this behaviour.
I fully agree that deprecating them is highly disruptive, hence my proposal #96437 was my first suggestion. I would argue that the documentation you propose is equivalent to deprecating the use of these APIs with negative indices? |
ISTM that a flag doesn't really do anything for us. In any case where a user would set the flag, they should instead be calling |
With respect, I think focusing on users still misses my point. As a Python sequence implementor authoring A sequence user should never need to care about whether this proposed flag is set on the type. The flag's intended purpose is to allow sequence implementors to opt-out of this problematic part of (same for |
davidhewitt commentedAug 30, 2022
Bug report
Sequence types which attempt to handle negative indexes in
__getitem__
experience double-corrected indexes when native code accesses them viaPySequence_GetItem
.The same behaviour affects
PySequence_SetItem
andPySequence_DelItem
, although not discussed further here.See the
ERROR
comments in the snippet below:(If requested I can push this as a sample repository)
Your environment
macOS 12.4, Python 3.12 main branch
I believe this negative index correction has been a feature of every Python 3 build on all OS variants.
Further background
PyO3 is a project to write native Python modules in Rust. To make the experience as straightforward as possible for Python developers, we aim to offer an API to create classes which matches Python as closely as possible.
PyO3 provides a way to implement
__getitem__
which matches how user-defined Python classes work, like in the sample above. However,PySequence_GetItem
's use of negative indexing has been a source of confusion: PyO3/pyo3#2601 (comment)PyO3/pyo3#2392 (comment)
I am happy to be instructed that PyO3 should adopt a different design (ideas welcome). I would still defend it is reasonable to call the interaction demonstrated above for the Python class a bug.
I couldn't find any other discussion on this issue other than this comment from Guido in 2001, which implied that this behaviour was probably perceived as tricky even then: #34788 (comment)
Possible solutions
I believe it should be possible to add a new type flag, bikeshed it
Py_TPFLAGS_NO_SEQ_INDEX_ADJUST
, which disables this adjustment forPySequence_{Get,Set,Del}Item
methods. Python-defined classes can have this flag set, avoiding the problematic behaviour displayed above. Native types can also use it to opt-out so that they can handle the negative index themselves. The main upside for native classes is that (if desired) the indexing operator would be able to raise IndexError containing the out-of-range index. E.g.(1, 2, 3)[-10]
could raiseIndexError(-10)
instead ofIndexError("tuple index out of range")
.The text was updated successfully, but these errors were encountered: