1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
import pytest
from pybind11_tests import sequences_and_iterators as m
from pybind11_tests import ConstructorStats
def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):
"""Like math.isclose() from Python 3.5"""
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0):
return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list))
def test_generalized_iterators():
assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)]
assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)]
assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == []
assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3]
assert list(m.IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1]
assert list(m.IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == []
# __next__ must continue to raise StopIteration
it = m.IntPairs([(0, 0)]).nonzero()
for _ in range(3):
with pytest.raises(StopIteration):
next(it)
it = m.IntPairs([(0, 0)]).nonzero_keys()
for _ in range(3):
with pytest.raises(StopIteration):
next(it)
def test_sliceable():
sliceable = m.Sliceable(100)
assert sliceable[::] == (0, 100, 1)
assert sliceable[10::] == (10, 100, 1)
assert sliceable[:10:] == (0, 10, 1)
assert sliceable[::10] == (0, 100, 10)
assert sliceable[-10::] == (90, 100, 1)
assert sliceable[:-10:] == (0, 90, 1)
assert sliceable[::-10] == (99, -1, -10)
assert sliceable[50:60:1] == (50, 60, 1)
assert sliceable[50:60:-1] == (50, 60, -1)
def test_sequence():
cstats = ConstructorStats.get(m.Sequence)
s = m.Sequence(5)
assert cstats.values() == ['of size', '5']
assert "Sequence" in repr(s)
assert len(s) == 5
assert s[0] == 0 and s[3] == 0
assert 12.34 not in s
s[0], s[3] = 12.34, 56.78
assert 12.34 in s
assert isclose(s[0], 12.34) and isclose(s[3], 56.78)
rev = reversed(s)
assert cstats.values() == ['of size', '5']
rev2 = s[::-1]
assert cstats.values() == ['of size', '5']
it = iter(m.Sequence(0))
for _ in range(3): # __next__ must continue to raise StopIteration
with pytest.raises(StopIteration):
next(it)
assert cstats.values() == ['of size', '0']
expected = [0, 56.78, 0, 0, 12.34]
assert allclose(rev, expected)
assert allclose(rev2, expected)
assert rev == rev2
rev[0::2] = m.Sequence([2.0, 2.0, 2.0])
assert cstats.values() == ['of size', '3', 'from std::vector']
assert allclose(rev, [2, 56.78, 2, 0, 2])
assert cstats.alive() == 4
del it
assert cstats.alive() == 3
del s
assert cstats.alive() == 2
del rev
assert cstats.alive() == 1
del rev2
assert cstats.alive() == 0
assert cstats.values() == []
assert cstats.default_constructions == 0
assert cstats.copy_constructions == 0
assert cstats.move_constructions >= 1
assert cstats.copy_assignments == 0
assert cstats.move_assignments == 0
def test_map_iterator():
sm = m.StringMap({'hi': 'bye', 'black': 'white'})
assert sm['hi'] == 'bye'
assert len(sm) == 2
assert sm['black'] == 'white'
with pytest.raises(KeyError):
assert sm['orange']
sm['orange'] = 'banana'
assert sm['orange'] == 'banana'
expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'}
for k in sm:
assert sm[k] == expected[k]
for k, v in sm.items():
assert v == expected[k]
it = iter(m.StringMap({}))
for _ in range(3): # __next__ must continue to raise StopIteration
with pytest.raises(StopIteration):
next(it)
def test_python_iterator_in_cpp():
t = (1, 2, 3)
assert m.object_to_list(t) == [1, 2, 3]
assert m.object_to_list(iter(t)) == [1, 2, 3]
assert m.iterator_to_list(iter(t)) == [1, 2, 3]
with pytest.raises(TypeError) as excinfo:
m.object_to_list(1)
assert "object is not iterable" in str(excinfo.value)
with pytest.raises(TypeError) as excinfo:
m.iterator_to_list(1)
assert "incompatible function arguments" in str(excinfo.value)
def bad_next_call():
raise RuntimeError("py::iterator::advance() should propagate errors")
with pytest.raises(RuntimeError) as excinfo:
m.iterator_to_list(iter(bad_next_call, None))
assert str(excinfo.value) == "py::iterator::advance() should propagate errors"
lst = [1, None, 0, None]
assert m.count_none(lst) == 2
assert m.find_none(lst) is True
assert m.count_nonzeros({"a": 0, "b": 1, "c": 2}) == 2
r = range(5)
assert all(m.tuple_iterator(tuple(r)))
assert all(m.list_iterator(list(r)))
assert all(m.sequence_iterator(r))
def test_iterator_passthrough():
"""#181: iterator passthrough did not compile"""
from pybind11_tests.sequences_and_iterators import iterator_passthrough
assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
def test_iterator_rvp():
"""#388: Can't make iterators via make_iterator() with different r/v policies """
import pybind11_tests.sequences_and_iterators as m
assert list(m.make_iterator_1()) == [1, 2, 3]
assert list(m.make_iterator_2()) == [1, 2, 3]
assert not isinstance(m.make_iterator_1(), type(m.make_iterator_2()))
|