Skip to content
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

Bug in slice.indices() #47254

Closed
anakha mannequin opened this issue May 29, 2008 · 12 comments
Closed

Bug in slice.indices() #47254

anakha mannequin opened this issue May 29, 2008 · 12 comments
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error

Comments

@anakha
Copy link
Mannequin

anakha mannequin commented May 29, 2008

BPO 3004
Nosy @rhettinger, @mdickinson
Files
  • slice.patch: Patch to fix the problem
  • test_slice.patch: Patch to add tests
  • issue3004.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/mdickinson'
    closed_at = <Date 2008-06-20.14:57:17.815>
    created_at = <Date 2008-05-29.18:35:54.461>
    labels = ['interpreter-core', 'type-bug']
    title = 'Bug in slice.indices()'
    updated_at = <Date 2008-06-20.14:57:17.766>
    user = 'https://bugs.python.org/anakha'

    bugs.python.org fields:

    activity = <Date 2008-06-20.14:57:17.766>
    actor = 'mark.dickinson'
    assignee = 'mark.dickinson'
    closed = True
    closed_date = <Date 2008-06-20.14:57:17.815>
    closer = 'mark.dickinson'
    components = ['Interpreter Core']
    creation = <Date 2008-05-29.18:35:54.461>
    creator = 'anakha'
    dependencies = []
    files = ['10466', '10653', '10670']
    hgrepos = []
    issue_num = 3004
    keywords = ['patch']
    message_count = 12.0
    messages = ['67506', '67714', '67733', '67883', '68342', '68366', '68448', '68449', '68450', '68451', '68458', '68462']
    nosy_count = 3.0
    nosy_names = ['rhettinger', 'mark.dickinson', 'anakha']
    pr_nums = []
    priority = 'normal'
    resolution = 'accepted'
    stage = None
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue3004'
    versions = ['Python 2.6', 'Python 2.5']

    @anakha
    Copy link
    Mannequin Author

    anakha mannequin commented May 29, 2008

    When calling the indices method of a slice object with a negative stop
    larger in absolute value than the length passed, the returned stop value
    is always -1. It should be 0 when the step is positive.

    Current behavior:

    >>> slice(-10).indices(11)
    (0, 1, 1)
    >>> slice(-10).indices(10)
    (0, 0, 1)
    >>> slice(-10).indices(9)
    (0, -1, 1)
    >>> slice(-10).indices(8)
    (0, -1, 1)

    Expected behavior:

    >>> slice(-10).indices(11)
    (0, 1, 1)
    >>> slice(-10).indices(10)
    (0, 0, 1)
    >>> slice(-10).indices(9)
    (0, 0, 1)
    >>> slice(-10).indices(8)
    (0, 0, 1)

    The patch I submit trivially fixes this while preserving the expected -1
    when the step is negative like in:

    >>> slice(None, -10, -1).indices(8)
    (7, -1, -1)

    This issue affects python 2.5 and 2.6 at least. I did not test with
    other versions.

    @anakha anakha mannequin added interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error labels May 29, 2008
    @mdickinson
    Copy link
    Member

    I agree that those -1s should really be 0s.

    Do you have any examples of real-life code
    that's affected by this bug? It doesn't seem
    like something that would be a problem in
    practice.

    @anakha
    Copy link
    Mannequin Author

    anakha mannequin commented Jun 5, 2008

    It's for code that I am developping. I developped a class to allow
    full slicing over iterators (like what islice does, but with negative
    indexes). When I have a positive step I just foward the call to
    isclice using slice.indices() to compute my limits. But with this
    behavior, I am forced to wrap the indices() call with a function that
    patches this case.

    I agree that for the common usage of computing the limits of a for
    loop it doesn't matter. But it is really surprising when you realise
    this behavior is what is causing these exceptions after having passed
    half a day trying to debug your code.

    In fact, I think this bug should really be more of a documentation bug
    and I should propose a patch to add clearer documentation to this
    method. But the fix proposed should also go in because:

    • it's trivial
    • it's better

    Documentation for the method will be submitted later tomorrow. Should
    I post another report or just attach it to this one?

    @anakha
    Copy link
    Mannequin Author

    anakha mannequin commented Jun 10, 2008

    Don't blame me for the delay, I have long days (yes, really up to 96
    hours long :)

    As for the documentation patch, I'm not certain anymore about it.
    Unless I bloat the description to about one full screen worth of text,
    there will always be surprises for the user. And describing only one
    little part in detail feels inconsistent.

    So unless I'm just a really bad writer, I think the current doc could be
    left as-is. I'm still all for the attached patch. Comments anyone? Or
    does this needs more nagging?

    @mdickinson
    Copy link
    Member

    Could you provide some tests for the fixed behaviour?

    I'll try to check this in (with appropriate tests) after the beta.

    @mdickinson mdickinson self-assigned this Jun 17, 2008
    @anakha
    Copy link
    Mannequin Author

    anakha mannequin commented Jun 18, 2008

    Would these do?

    self.assertEqual(slice(None, -10 ).indices(10), (0, 0, 1))
    self.assertEqual(slice(None, -11, ).indices(10), (0, 0, 1))
    self.assertEqual(slice(None, -12, -1).indices(10), (9, -1, -1))

    If yes, test_slice.patch adds them.

    @mdickinson
    Copy link
    Member

    On Wed, Jun 18, 2008 at 4:56 PM, Arnaud Bergeron <report@bugs.python.org>
    wrote:

    Arnaud Bergeron <abergeron@gmail.com> added the comment:

    Would these do?

    self.assertEqual(slice(None, -10 ).indices(10), (0, 0, 1))
    self.assertEqual(slice(None, -11, ).indices(10), (0, 0, 1))
    self.assertEqual(slice(None, -12, -1).indices(10), (9, -1, -1))

    Perfect. Thank you.

    If this is changed, then I think the following should also be
    changed:

    (9, 10, -1)

    I believe the second index here should be 9, not 10.
    Do you agree?

    With these two changes the code, while marginally
    more complicated, is actually easier to understand than
    before, since exactly the same processing is applied
    to both the start and stop indices. I think this is as
    it should be.

    @mdickinson
    Copy link
    Member

    Sorry: looks like I messed up that last post. The example should be:

    >>> slice(10, 10, -1).indices(10)  # expect (9, 9, -1)
    (9, 10, -1)

    @mdickinson
    Copy link
    Member

    Here's a new patch that incorporates Arnaud's fix and tests, together with
    a few extra tests.

    While I expect that this change will affect very little code, I think it's
    the right thing to do, because:

    • start and stop are now processed identically, making the source code
      easier to understand, and the behaviour easier to explain.

    • expected invariants now hold even in corner cases; for example, after:

    start, stop, step = my_slice.indices(length)

    it's guaranteed that

    0 <= start <= stop <= length if step is positive, and
    length-1 >= start >= stop >= -1 if step is negative.

    However, I'd like a second opinion from another core developer before
    checking this in.

    @mdickinson
    Copy link
    Member

    0 <= start <= stop <= length if step is positive, and
    length-1 >= start >= stop >= -1 if step is negative.

    That should be:

    0 <= start <= length and 0 <= stop <= length (step > 0), and
    length-1 >= start >= -1, length-1 >= stop >= -1 (step < 0);

    it's not guaranteed that start <= stop always holds in the first case,
    or that start >= stop in the second.

    @rhettinger rhettinger assigned rhettinger and unassigned mdickinson Jun 20, 2008
    @rhettinger
    Copy link
    Contributor

    Looks like a straight-forward patch.

    @rhettinger rhettinger assigned mdickinson and unassigned rhettinger Jun 20, 2008
    @mdickinson
    Copy link
    Member

    Committed, r64426.

    Thanks for the report, Arnaud.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants