-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
bpo-31956: Add start and stop parameters to array.index() #4435
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just take list.index
as an example.
Modules/arraymodule.c
Outdated
@@ -1115,18 +1115,42 @@ array_array_count(arrayobject *self, PyObject *v) | |||
array.array.index | |||
|
|||
v: object | |||
start: Py_ssize_t = 0 | |||
stop: Py_ssize_t = 9223372036854775807 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this 9223372036854775807 mean? I have idea, but this looks totally confusing.
And there is an integer overflow on 32-bit platform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found it somewhere (in cpython), though I can't remember where. I'll try to readjust with clinic, taking list_index() as an example, and commit the updates asap.
EDIT: Updated.
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
I have made the requested changes; please review again. |
Thanks for making the requested changes! @serhiy-storchaka: please review the changes made to this pull request. |
Modules/arraymodule.c
Outdated
stop = len; | ||
} | ||
|
||
for (i = start; i < stop; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An arbitrary Python code can be executed in PyObject_RichCompareBool()
. It can change the size of the array. As result, the index can become out of the array limits.
Use the same loop condition as in list.index to prevent this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was able to reproduce this, using an object that contained a reference to the array, which in its __eq__
mutates the array, causing an assertion failure. At this point in time, my code has boiled down to an almost identical copy of list_index
, except I do not see the reason for truncating the stop index, as is done there.
|
||
for (i = 0; i < Py_SIZE(self); i++) { | ||
len = Py_SIZE(self); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove redundant empty lines.
Modules/arraymodule.c
Outdated
|
||
if (stop < 0) { | ||
stop += len; | ||
} else if (stop > len) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"else if" should be on a separate line (PEP 7). But actually this branch is not needed due to the comment below.
Doc/library/array.rst
Outdated
*x* in the array. | ||
*x* in the array. The optional arguments *start* and *stop* can be specified to | ||
search for *x* within a subsection of the array, but the returned index is | ||
still relative to the start of the array, not the subsection. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the words "but the returned index is still relative to the start of the array, not the subsection" are redundant since this directly follows from the first sentence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but somebody other should review the documentation.
Doc/library/array.rst
Outdated
Raises :exc:`ValueError` if *x* is not found. | ||
|
||
.. versionchanged:: 3.7 | ||
Added optional start and stop parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*start* and *stop*
@@ -0,0 +1,4 @@ | |||
array.index() now supports optional start and stop arguments. | |||
As with general sequences, they can be negative, and the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps this is redundant too. This is common behavior of index() methods.
…omatically confirm to the standard, no need to point that out
@@ -188,11 +188,16 @@ The following data items and methods are also supported: | |||
array of some other type. | |||
|
|||
|
|||
.. method:: array.index(x) | |||
.. method:: array.index(x[, start[, stop]]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can document the default start value:
array.index(x, start=0[, stop])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to specify start=0, stop=sys.maxsize
, but there were objections against this, because this looks like start and stop are keyword parameters. There were issues about changing the documentation back to [, start[, stop]]
.
@@ -1115,18 +1115,31 @@ array_array_count(arrayobject *self, PyObject *v) | |||
array.array.index | |||
|
|||
v: object | |||
start: slice_index(accept={int}) = 0 | |||
stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to not document the default value at Python level? Try to remove "= sys.maxsize".
Maybe you should put "/" (currently the following line) between start and stop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to not make stop the keyword argument until other index() methods accept keyword arguments.
The signature of array.index() matches the signature of list.index() and this is the best that we can to do now. Due to limitations of pydoc, inspect and Argument Clinic the default value for stop is displayed as a concrete number, but this is a separate issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right, I didn't notice that other methods don't accept keywords.
>>> "abc".index("c", stop=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: index() takes no keyword arguments
I like the idea of accepting keyword arguments in other index() methods :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is an open issue for this. But first I want unify the code for all index() methods. Currently index() methods of str/bytes/bytearray use slightly different code.
/ | ||
|
||
Return index of first occurrence of v in the array. | ||
|
||
Raises ValueError if the value is not present. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually we don't document the exact exception raised by a method. Please remove this addition.
Maybe we should start to document them, but I would prefer to have a discussion about that, before starting to document them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstrings of other index() methods document this.
start = 0; | ||
} | ||
if (stop < 0) { | ||
stop += Py_SIZE(self); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is stop is still negative here?
Maybe you can use PySlice_AdjustIndices() here with step=1? What do you think @serhiy-storchaka?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All correct if stop is still negative. The following loop just will not be executed.
if (stop < 0) { | ||
stop += Py_SIZE(self); | ||
} | ||
for (i = start; i < stop && i < Py_SIZE(self); i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that you kept the "< Py_SIZE()" check if the array is mutated during the PyObject_RichCompareBool() call? If yes, please add a short comment to explain that, since it can be surprising.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggested to do this. This is an exact copy from list.index(). Do you want to add a comment in list.index()?
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
Ping @Phaqui: do you still plan to work on this PR? https://bugs.python.org/issue31956#msg350405 cc @nanjekyejoannah |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vstinner @serhiy-storchaka , I think the author of this PR is waiting for consesus from either or both of you following the discussion from BPO here : https://bugs.python.org/issue31956#msg350405
@Phaqui @vstinner @serhiy-storchaka |
Sure, the code is mostly written. There were arguments about documentation, and details, and thus did not go in, but as far as I can remember, the code itself is pretty much list.index(), and should therefore in essence be ready to go. |
https://bugs.python.org/issue31956