Skip to content

[BUG]: iterator increment operator does not skip first item #5399

Closed
@dalboris

Description

@dalboris

Required prerequisites

What version (or hash if on master) of pybind11 are you using?

master (c4a05f)

Problem description

The bug is that as currently implemented, the first call to iterator::operator++ is semantically a no-op, since it calls iterator::advance(), but operator* also automatically calls advance() if it has never been advanced yet (that is, when iterator::value is null). So the two following snippets are equivalent:

// Snippet 1
py::iterator it = my_iterable.begin();
return *it; // Returns the first item, as expected

// Snippet 2
py::iterator it = my_iterable.begin();
++it;
return *it; // BUG: also returns the first item

I have locally added unit tests that reproduce the problem (see below), and I'm working on a fix.

Reproducible example code

Adding the following to test_pytypes.cpp:

    m.def("get_second_item_from_iterable", [](const py::iterable &iter) {
        py::iterator it = iter.begin();
        ++it;
        return *it;
    });

and to test_pytypes.py:

def test_get_second_item_from_iterable():
    lins = [1, 2]
    i = m.get_second_item_from_iterable(lins)
    assert i == 2

Fails with:

___ test_get_second_item_from_iterable ___

    def test_get_second_item_from_iterable():
        lins = [1, 2]
        i = m.get_second_item_from_iterable(lins)
>       assert i == 2
E       assert 1 == 2

i          = 1
lins       = [1, 2]

Is this a regression? Put the last known working version here if it is.

Not a regression

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageNew bug, unverified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions