test_sequences_and_iterators.py revision 12037
1import pytest 2 3 4def isclose(a, b, rel_tol=1e-05, abs_tol=0.0): 5 """Like math.isclose() from Python 3.5""" 6 return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) 7 8 9def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0): 10 return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list)) 11 12 13def test_generalized_iterators(): 14 from pybind11_tests.sequences_and_iterators import IntPairs 15 16 assert list(IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero()) == [(1, 2), (3, 4)] 17 assert list(IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero()) == [(1, 2)] 18 assert list(IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero()) == [] 19 20 assert list(IntPairs([(1, 2), (3, 4), (0, 5)]).nonzero_keys()) == [1, 3] 21 assert list(IntPairs([(1, 2), (2, 0), (0, 3), (4, 5)]).nonzero_keys()) == [1] 22 assert list(IntPairs([(0, 3), (1, 2), (3, 4)]).nonzero_keys()) == [] 23 24 25def test_sequence(): 26 from pybind11_tests import ConstructorStats 27 from pybind11_tests.sequences_and_iterators import Sequence 28 29 cstats = ConstructorStats.get(Sequence) 30 31 s = Sequence(5) 32 assert cstats.values() == ['of size', '5'] 33 34 assert "Sequence" in repr(s) 35 assert len(s) == 5 36 assert s[0] == 0 and s[3] == 0 37 assert 12.34 not in s 38 s[0], s[3] = 12.34, 56.78 39 assert 12.34 in s 40 assert isclose(s[0], 12.34) and isclose(s[3], 56.78) 41 42 rev = reversed(s) 43 assert cstats.values() == ['of size', '5'] 44 45 rev2 = s[::-1] 46 assert cstats.values() == ['of size', '5'] 47 48 expected = [0, 56.78, 0, 0, 12.34] 49 assert allclose(rev, expected) 50 assert allclose(rev2, expected) 51 assert rev == rev2 52 53 rev[0::2] = Sequence([2.0, 2.0, 2.0]) 54 assert cstats.values() == ['of size', '3', 'from std::vector'] 55 56 assert allclose(rev, [2, 56.78, 2, 0, 2]) 57 58 assert cstats.alive() == 3 59 del s 60 assert cstats.alive() == 2 61 del rev 62 assert cstats.alive() == 1 63 del rev2 64 assert cstats.alive() == 0 65 66 assert cstats.values() == [] 67 assert cstats.default_constructions == 0 68 assert cstats.copy_constructions == 0 69 assert cstats.move_constructions >= 1 70 assert cstats.copy_assignments == 0 71 assert cstats.move_assignments == 0 72 73 74def test_map_iterator(): 75 from pybind11_tests.sequences_and_iterators import StringMap 76 77 m = StringMap({'hi': 'bye', 'black': 'white'}) 78 assert m['hi'] == 'bye' 79 assert len(m) == 2 80 assert m['black'] == 'white' 81 82 with pytest.raises(KeyError): 83 assert m['orange'] 84 m['orange'] = 'banana' 85 assert m['orange'] == 'banana' 86 87 expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'} 88 for k in m: 89 assert m[k] == expected[k] 90 for k, v in m.items(): 91 assert v == expected[k] 92 93 94def test_python_iterator_in_cpp(): 95 import pybind11_tests.sequences_and_iterators as m 96 97 t = (1, 2, 3) 98 assert m.object_to_list(t) == [1, 2, 3] 99 assert m.object_to_list(iter(t)) == [1, 2, 3] 100 assert m.iterator_to_list(iter(t)) == [1, 2, 3] 101 102 with pytest.raises(TypeError) as excinfo: 103 m.object_to_list(1) 104 assert "object is not iterable" in str(excinfo.value) 105 106 with pytest.raises(TypeError) as excinfo: 107 m.iterator_to_list(1) 108 assert "incompatible function arguments" in str(excinfo.value) 109 110 def bad_next_call(): 111 raise RuntimeError("py::iterator::advance() should propagate errors") 112 113 with pytest.raises(RuntimeError) as excinfo: 114 m.iterator_to_list(iter(bad_next_call, None)) 115 assert str(excinfo.value) == "py::iterator::advance() should propagate errors" 116 117 l = [1, None, 0, None] 118 assert m.count_none(l) == 2 119 assert m.find_none(l) is True 120 assert m.count_nonzeros({"a": 0, "b": 1, "c": 2}) == 2 121 122 r = range(5) 123 assert all(m.tuple_iterator(tuple(r))) 124 assert all(m.list_iterator(list(r))) 125 assert all(m.sequence_iterator(r)) 126