test_numpy_array.py revision 11986:c12e4625ab56
1import pytest
2import gc
3
4with pytest.suppress(ImportError):
5    import numpy as np
6
7
8@pytest.fixture(scope='function')
9def arr():
10    return np.array([[1, 2, 3], [4, 5, 6]], '<u2')
11
12
13@pytest.requires_numpy
14def test_array_attributes():
15    from pybind11_tests.array import (
16        ndim, shape, strides, writeable, size, itemsize, nbytes, owndata
17    )
18
19    a = np.array(0, 'f8')
20    assert ndim(a) == 0
21    assert all(shape(a) == [])
22    assert all(strides(a) == [])
23    with pytest.raises(IndexError) as excinfo:
24        shape(a, 0)
25    assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
26    with pytest.raises(IndexError) as excinfo:
27        strides(a, 0)
28    assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)'
29    assert writeable(a)
30    assert size(a) == 1
31    assert itemsize(a) == 8
32    assert nbytes(a) == 8
33    assert owndata(a)
34
35    a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view()
36    a.flags.writeable = False
37    assert ndim(a) == 2
38    assert all(shape(a) == [2, 3])
39    assert shape(a, 0) == 2
40    assert shape(a, 1) == 3
41    assert all(strides(a) == [6, 2])
42    assert strides(a, 0) == 6
43    assert strides(a, 1) == 2
44    with pytest.raises(IndexError) as excinfo:
45        shape(a, 2)
46    assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
47    with pytest.raises(IndexError) as excinfo:
48        strides(a, 2)
49    assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)'
50    assert not writeable(a)
51    assert size(a) == 6
52    assert itemsize(a) == 2
53    assert nbytes(a) == 12
54    assert not owndata(a)
55
56
57@pytest.requires_numpy
58@pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)])
59def test_index_offset(arr, args, ret):
60    from pybind11_tests.array import index_at, index_at_t, offset_at, offset_at_t
61    assert index_at(arr, *args) == ret
62    assert index_at_t(arr, *args) == ret
63    assert offset_at(arr, *args) == ret * arr.dtype.itemsize
64    assert offset_at_t(arr, *args) == ret * arr.dtype.itemsize
65
66
67@pytest.requires_numpy
68def test_dim_check_fail(arr):
69    from pybind11_tests.array import (index_at, index_at_t, offset_at, offset_at_t, data, data_t,
70                                      mutate_data, mutate_data_t)
71    for func in (index_at, index_at_t, offset_at, offset_at_t, data, data_t,
72                 mutate_data, mutate_data_t):
73        with pytest.raises(IndexError) as excinfo:
74            func(arr, 1, 2, 3)
75        assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)'
76
77
78@pytest.requires_numpy
79@pytest.mark.parametrize('args, ret',
80                         [([], [1, 2, 3, 4, 5, 6]),
81                          ([1], [4, 5, 6]),
82                          ([0, 1], [2, 3, 4, 5, 6]),
83                          ([1, 2], [6])])
84def test_data(arr, args, ret):
85    from pybind11_tests.array import data, data_t
86    assert all(data_t(arr, *args) == ret)
87    assert all(data(arr, *args)[::2] == ret)
88    assert all(data(arr, *args)[1::2] == 0)
89
90
91@pytest.requires_numpy
92def test_mutate_readonly(arr):
93    from pybind11_tests.array import mutate_data, mutate_data_t, mutate_at_t
94    arr.flags.writeable = False
95    for func, args in (mutate_data, ()), (mutate_data_t, ()), (mutate_at_t, (0, 0)):
96        with pytest.raises(RuntimeError) as excinfo:
97            func(arr, *args)
98        assert str(excinfo.value) == 'array is not writeable'
99
100
101@pytest.requires_numpy
102@pytest.mark.parametrize('dim', [0, 1, 3])
103def test_at_fail(arr, dim):
104    from pybind11_tests.array import at_t, mutate_at_t
105    for func in at_t, mutate_at_t:
106        with pytest.raises(IndexError) as excinfo:
107            func(arr, *([0] * dim))
108        assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim)
109
110
111@pytest.requires_numpy
112def test_at(arr):
113    from pybind11_tests.array import at_t, mutate_at_t
114
115    assert at_t(arr, 0, 2) == 3
116    assert at_t(arr, 1, 0) == 4
117
118    assert all(mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6])
119    assert all(mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
120
121
122@pytest.requires_numpy
123def test_mutate_data(arr):
124    from pybind11_tests.array import mutate_data, mutate_data_t
125
126    assert all(mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12])
127    assert all(mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24])
128    assert all(mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48])
129    assert all(mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
130    assert all(mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
131
132    assert all(mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193])
133    assert all(mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194])
134    assert all(mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195])
135    assert all(mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196])
136    assert all(mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
137
138
139@pytest.requires_numpy
140def test_bounds_check(arr):
141    from pybind11_tests.array import (index_at, index_at_t, data, data_t,
142                                      mutate_data, mutate_data_t, at_t, mutate_at_t)
143    funcs = (index_at, index_at_t, data, data_t,
144             mutate_data, mutate_data_t, at_t, mutate_at_t)
145    for func in funcs:
146        with pytest.raises(IndexError) as excinfo:
147            func(arr, 2, 0)
148        assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2'
149        with pytest.raises(IndexError) as excinfo:
150            func(arr, 0, 4)
151        assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3'
152
153
154@pytest.requires_numpy
155def test_make_c_f_array():
156    from pybind11_tests.array import (
157        make_c_array, make_f_array
158    )
159    assert make_c_array().flags.c_contiguous
160    assert not make_c_array().flags.f_contiguous
161    assert make_f_array().flags.f_contiguous
162    assert not make_f_array().flags.c_contiguous
163
164
165@pytest.requires_numpy
166def test_wrap():
167    from pybind11_tests.array import wrap
168
169    def assert_references(a, b):
170        assert a is not b
171        assert a.__array_interface__['data'][0] == b.__array_interface__['data'][0]
172        assert a.shape == b.shape
173        assert a.strides == b.strides
174        assert a.flags.c_contiguous == b.flags.c_contiguous
175        assert a.flags.f_contiguous == b.flags.f_contiguous
176        assert a.flags.writeable == b.flags.writeable
177        assert a.flags.aligned == b.flags.aligned
178        assert a.flags.updateifcopy == b.flags.updateifcopy
179        assert np.all(a == b)
180        assert not b.flags.owndata
181        assert b.base is a
182        if a.flags.writeable and a.ndim == 2:
183            a[0, 0] = 1234
184            assert b[0, 0] == 1234
185
186    a1 = np.array([1, 2], dtype=np.int16)
187    assert a1.flags.owndata and a1.base is None
188    a2 = wrap(a1)
189    assert_references(a1, a2)
190
191    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F')
192    assert a1.flags.owndata and a1.base is None
193    a2 = wrap(a1)
194    assert_references(a1, a2)
195
196    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C')
197    a1.flags.writeable = False
198    a2 = wrap(a1)
199    assert_references(a1, a2)
200
201    a1 = np.random.random((4, 4, 4))
202    a2 = wrap(a1)
203    assert_references(a1, a2)
204
205    a1 = a1.transpose()
206    a2 = wrap(a1)
207    assert_references(a1, a2)
208
209    a1 = a1.diagonal()
210    a2 = wrap(a1)
211    assert_references(a1, a2)
212
213
214@pytest.requires_numpy
215def test_numpy_view(capture):
216    from pybind11_tests.array import ArrayClass
217    with capture:
218        ac = ArrayClass()
219        ac_view_1 = ac.numpy_view()
220        ac_view_2 = ac.numpy_view()
221        assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
222        del ac
223        gc.collect()
224    assert capture == """
225        ArrayClass()
226        ArrayClass::numpy_view()
227        ArrayClass::numpy_view()
228    """
229    ac_view_1[0] = 4
230    ac_view_1[1] = 3
231    assert ac_view_2[0] == 4
232    assert ac_view_2[1] == 3
233    with capture:
234        del ac_view_1
235        del ac_view_2
236        gc.collect()
237    assert capture == """
238        ~ArrayClass()
239    """
240
241
242@pytest.requires_numpy
243def test_cast_numpy_int64_to_uint64():
244    from pybind11_tests.array import function_taking_uint64
245    function_taking_uint64(123)
246    function_taking_uint64(np.uint64(123))
247
248
249@pytest.requires_numpy
250def test_isinstance():
251    from pybind11_tests.array import isinstance_untyped, isinstance_typed
252
253    assert isinstance_untyped(np.array([1, 2, 3]), "not an array")
254    assert isinstance_typed(np.array([1.0, 2.0, 3.0]))
255
256
257@pytest.requires_numpy
258def test_constructors():
259    from pybind11_tests.array import default_constructors, converting_constructors
260
261    defaults = default_constructors()
262    for a in defaults.values():
263        assert a.size == 0
264    assert defaults["array"].dtype == np.array([]).dtype
265    assert defaults["array_t<int32>"].dtype == np.int32
266    assert defaults["array_t<double>"].dtype == np.float64
267
268    results = converting_constructors([1, 2, 3])
269    for a in results.values():
270        np.testing.assert_array_equal(a, [1, 2, 3])
271    assert results["array"].dtype == np.int_
272    assert results["array_t<int32>"].dtype == np.int32
273    assert results["array_t<double>"].dtype == np.float64
274