test_numpy_array.py 19.8 KB
Newer Older
1
2
import pytest

3
4
import env  # noqa: F401
from pybind11_tests import numpy_array as m
5

6
np = pytest.importorskip("numpy")
7
8


9
10
11
12
13
14
15
16
17
18
19
def test_dtypes():
    # See issue #1328.
    # - Platform-dependent sizes.
    for size_check in m.get_platform_dtype_size_checks():
        print(size_check)
        assert size_check.size_cpp == size_check.size_numpy, size_check
    # - Concrete sizes.
    for check in m.get_concrete_dtype_checks():
        print(check)
        assert check.numpy == check.pybind11, check
        if check.numpy.num != check.pybind11.num:
20
21
22
23
24
            print(
                "NOTE: typenum mismatch for {}: {} != {}".format(
                    check, check.numpy.num, check.pybind11.num
                )
            )
25
26


27
@pytest.fixture(scope="function")
28
def arr():
29
    return np.array([[1, 2, 3], [4, 5, 6]], "=u2")
30
31


32
def test_array_attributes():
33
    a = np.array(0, "f8")
34
35
36
    assert m.ndim(a) == 0
    assert all(m.shape(a) == [])
    assert all(m.strides(a) == [])
37
    with pytest.raises(IndexError) as excinfo:
38
        m.shape(a, 0)
39
    assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"
40
    with pytest.raises(IndexError) as excinfo:
41
        m.strides(a, 0)
42
    assert str(excinfo.value) == "invalid axis: 0 (ndim = 0)"
43
44
45
46
47
    assert m.writeable(a)
    assert m.size(a) == 1
    assert m.itemsize(a) == 8
    assert m.nbytes(a) == 8
    assert m.owndata(a)
48

49
    a = np.array([[1, 2, 3], [4, 5, 6]], "u2").view()
50
    a.flags.writeable = False
51
52
53
54
55
56
57
    assert m.ndim(a) == 2
    assert all(m.shape(a) == [2, 3])
    assert m.shape(a, 0) == 2
    assert m.shape(a, 1) == 3
    assert all(m.strides(a) == [6, 2])
    assert m.strides(a, 0) == 6
    assert m.strides(a, 1) == 2
58
    with pytest.raises(IndexError) as excinfo:
59
        m.shape(a, 2)
60
    assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"
61
    with pytest.raises(IndexError) as excinfo:
62
        m.strides(a, 2)
63
    assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)"
64
65
66
67
68
    assert not m.writeable(a)
    assert m.size(a) == 6
    assert m.itemsize(a) == 2
    assert m.nbytes(a) == 12
    assert not m.owndata(a)
69
70


71
72
73
@pytest.mark.parametrize(
    "args, ret", [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]
)
74
def test_index_offset(arr, args, ret):
75
76
77
78
    assert m.index_at(arr, *args) == ret
    assert m.index_at_t(arr, *args) == ret
    assert m.offset_at(arr, *args) == ret * arr.dtype.itemsize
    assert m.offset_at_t(arr, *args) == ret * arr.dtype.itemsize
79
80
81


def test_dim_check_fail(arr):
82
83
84
85
86
87
88
89
90
91
    for func in (
        m.index_at,
        m.index_at_t,
        m.offset_at,
        m.offset_at_t,
        m.data,
        m.data_t,
        m.mutate_data,
        m.mutate_data_t,
    ):
92
93
        with pytest.raises(IndexError) as excinfo:
            func(arr, 1, 2, 3)
94
        assert str(excinfo.value) == "too many indices for an array: 3 (ndim = 2)"
95
96


97
98
99
100
101
102
103
104
105
@pytest.mark.parametrize(
    "args, ret",
    [
        ([], [1, 2, 3, 4, 5, 6]),
        ([1], [4, 5, 6]),
        ([0, 1], [2, 3, 4, 5, 6]),
        ([1, 2], [6]),
    ],
)
106
def test_data(arr, args, ret):
107
    from sys import byteorder
108

109
    assert all(m.data_t(arr, *args) == ret)
110
111
    assert all(m.data(arr, *args)[(0 if byteorder == "little" else 1) :: 2] == ret)
    assert all(m.data(arr, *args)[(1 if byteorder == "little" else 0) :: 2] == 0)
112
113


114
@pytest.mark.parametrize("dim", [0, 1, 3])
115
def test_at_fail(arr, dim):
116
    for func in m.at_t, m.mutate_at_t:
117
118
        with pytest.raises(IndexError) as excinfo:
            func(arr, *([0] * dim))
119
120
121
        assert str(excinfo.value) == "index dimension mismatch: {} (ndim = 2)".format(
            dim
        )
122
123
124


def test_at(arr):
125
126
127
128
129
    assert m.at_t(arr, 0, 2) == 3
    assert m.at_t(arr, 1, 0) == 4

    assert all(m.mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6])
    assert all(m.mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6])
130
131


132
133
def test_mutate_readonly(arr):
    arr.flags.writeable = False
134
135
136
137
138
    for func, args in (
        (m.mutate_data, ()),
        (m.mutate_data_t, ()),
        (m.mutate_at_t, (0, 0)),
    ):
139
140
        with pytest.raises(ValueError) as excinfo:
            func(arr, *args)
141
        assert str(excinfo.value) == "array is not writeable"
142
143
144


def test_mutate_data(arr):
145
146
147
148
149
    assert all(m.mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12])
    assert all(m.mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24])
    assert all(m.mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48])
    assert all(m.mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96])
    assert all(m.mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192])
150

151
152
153
154
155
    assert all(m.mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193])
    assert all(m.mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194])
    assert all(m.mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195])
    assert all(m.mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196])
    assert all(m.mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197])
156
157
158


def test_bounds_check(arr):
159
160
161
162
163
164
165
166
167
168
    for func in (
        m.index_at,
        m.index_at_t,
        m.data,
        m.data_t,
        m.mutate_data,
        m.mutate_data_t,
        m.at_t,
        m.mutate_at_t,
    ):
169
        with pytest.raises(IndexError) as excinfo:
170
            func(arr, 2, 0)
171
        assert str(excinfo.value) == "index 2 is out of bounds for axis 0 with size 2"
172
        with pytest.raises(IndexError) as excinfo:
173
            func(arr, 0, 4)
174
        assert str(excinfo.value) == "index 4 is out of bounds for axis 1 with size 3"
175

176

177
def test_make_c_f_array():
178
179
180
181
    assert m.make_c_array().flags.c_contiguous
    assert not m.make_c_array().flags.f_contiguous
    assert m.make_f_array().flags.f_contiguous
    assert not m.make_f_array().flags.c_contiguous
182
183


184
185
186
def test_make_empty_shaped_array():
    m.make_empty_shaped_array()

187
188
189
190
191
    # empty shape means numpy scalar, PEP 3118
    assert m.scalar_int().ndim == 0
    assert m.scalar_int().shape == ()
    assert m.scalar_int() == 42

192

193
def test_wrap():
Jason Rhinelander's avatar
Jason Rhinelander committed
194
    def assert_references(a, b, base=None):
195
        from distutils.version import LooseVersion
196

Jason Rhinelander's avatar
Jason Rhinelander committed
197
198
        if base is None:
            base = a
199
        assert a is not b
200
        assert a.__array_interface__["data"][0] == b.__array_interface__["data"][0]
201
202
203
204
205
206
        assert a.shape == b.shape
        assert a.strides == b.strides
        assert a.flags.c_contiguous == b.flags.c_contiguous
        assert a.flags.f_contiguous == b.flags.f_contiguous
        assert a.flags.writeable == b.flags.writeable
        assert a.flags.aligned == b.flags.aligned
207
208
209
210
        if LooseVersion(np.__version__) >= LooseVersion("1.14.0"):
            assert a.flags.writebackifcopy == b.flags.writebackifcopy
        else:
            assert a.flags.updateifcopy == b.flags.updateifcopy
211
212
        assert np.all(a == b)
        assert not b.flags.owndata
Jason Rhinelander's avatar
Jason Rhinelander committed
213
        assert b.base is base
214
215
216
217
218
219
        if a.flags.writeable and a.ndim == 2:
            a[0, 0] = 1234
            assert b[0, 0] == 1234

    a1 = np.array([1, 2], dtype=np.int16)
    assert a1.flags.owndata and a1.base is None
220
    a2 = m.wrap(a1)
221
222
    assert_references(a1, a2)

223
    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="F")
224
    assert a1.flags.owndata and a1.base is None
225
    a2 = m.wrap(a1)
226
227
    assert_references(a1, a2)

228
    a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order="C")
229
    a1.flags.writeable = False
230
    a2 = m.wrap(a1)
231
232
233
    assert_references(a1, a2)

    a1 = np.random.random((4, 4, 4))
234
    a2 = m.wrap(a1)
235
236
    assert_references(a1, a2)

Jason Rhinelander's avatar
Jason Rhinelander committed
237
    a1t = a1.transpose()
238
    a2 = m.wrap(a1t)
Jason Rhinelander's avatar
Jason Rhinelander committed
239
    assert_references(a1t, a2, a1)
240

Jason Rhinelander's avatar
Jason Rhinelander committed
241
    a1d = a1.diagonal()
242
    a2 = m.wrap(a1d)
Jason Rhinelander's avatar
Jason Rhinelander committed
243
    assert_references(a1d, a2, a1)
244

245
    a1m = a1[::-1, ::-1, ::-1]
246
    a2 = m.wrap(a1m)
247
248
    assert_references(a1m, a2, a1)

249
250
251

def test_numpy_view(capture):
    with capture:
252
        ac = m.ArrayClass()
253
254
255
256
        ac_view_1 = ac.numpy_view()
        ac_view_2 = ac.numpy_view()
        assert np.all(ac_view_1 == np.array([1, 2], dtype=np.int32))
        del ac
Wenzel Jakob's avatar
Wenzel Jakob committed
257
        pytest.gc_collect()
258
259
260
    assert (
        capture
        == """
261
262
263
264
        ArrayClass()
        ArrayClass::numpy_view()
        ArrayClass::numpy_view()
    """
265
    )
266
267
268
269
270
271
272
    ac_view_1[0] = 4
    ac_view_1[1] = 3
    assert ac_view_2[0] == 4
    assert ac_view_2[1] == 3
    with capture:
        del ac_view_1
        del ac_view_2
Wenzel Jakob's avatar
Wenzel Jakob committed
273
274
        pytest.gc_collect()
        pytest.gc_collect()
275
276
277
    assert (
        capture
        == """
278
279
        ~ArrayClass()
    """
280
    )
281
282
283


def test_cast_numpy_int64_to_uint64():
284
285
    m.function_taking_uint64(123)
    m.function_taking_uint64(np.uint64(123))
286
287
288


def test_isinstance():
289
290
    assert m.isinstance_untyped(np.array([1, 2, 3]), "not an array")
    assert m.isinstance_typed(np.array([1.0, 2.0, 3.0]))
291
292
293


def test_constructors():
294
    defaults = m.default_constructors()
295
296
297
298
299
300
    for a in defaults.values():
        assert a.size == 0
    assert defaults["array"].dtype == np.array([]).dtype
    assert defaults["array_t<int32>"].dtype == np.int32
    assert defaults["array_t<double>"].dtype == np.float64

301
    results = m.converting_constructors([1, 2, 3])
302
303
304
305
306
    for a in results.values():
        np.testing.assert_array_equal(a, [1, 2, 3])
    assert results["array"].dtype == np.int_
    assert results["array_t<int32>"].dtype == np.int32
    assert results["array_t<double>"].dtype == np.float64
307
308


309
310
def test_overload_resolution(msg):
    # Exact overload matches:
311
312
313
314
315
316
317
    assert m.overloaded(np.array([1], dtype="float64")) == "double"
    assert m.overloaded(np.array([1], dtype="float32")) == "float"
    assert m.overloaded(np.array([1], dtype="ushort")) == "unsigned short"
    assert m.overloaded(np.array([1], dtype="intc")) == "int"
    assert m.overloaded(np.array([1], dtype="longlong")) == "long long"
    assert m.overloaded(np.array([1], dtype="complex")) == "double complex"
    assert m.overloaded(np.array([1], dtype="csingle")) == "float complex"
318
319

    # No exact match, should call first convertible version:
320
    assert m.overloaded(np.array([1], dtype="uint8")) == "double"
321

322
    with pytest.raises(TypeError) as excinfo:
323
        m.overloaded("not an array")
324
325
326
    assert (
        msg(excinfo.value)
        == """
327
        overloaded(): incompatible function arguments. The following argument types are supported:
328
329
330
331
332
333
334
            1. (arg0: numpy.ndarray[numpy.float64]) -> str
            2. (arg0: numpy.ndarray[numpy.float32]) -> str
            3. (arg0: numpy.ndarray[numpy.int32]) -> str
            4. (arg0: numpy.ndarray[numpy.uint16]) -> str
            5. (arg0: numpy.ndarray[numpy.int64]) -> str
            6. (arg0: numpy.ndarray[numpy.complex128]) -> str
            7. (arg0: numpy.ndarray[numpy.complex64]) -> str
335
336
337

        Invoked with: 'not an array'
    """
338
    )
339

340
341
342
343
344
    assert m.overloaded2(np.array([1], dtype="float64")) == "double"
    assert m.overloaded2(np.array([1], dtype="float32")) == "float"
    assert m.overloaded2(np.array([1], dtype="complex64")) == "float complex"
    assert m.overloaded2(np.array([1], dtype="complex128")) == "double complex"
    assert m.overloaded2(np.array([1], dtype="float32")) == "float"
345

346
347
    assert m.overloaded3(np.array([1], dtype="float64")) == "double"
    assert m.overloaded3(np.array([1], dtype="intc")) == "int"
348
349
    expected_exc = """
        overloaded3(): incompatible function arguments. The following argument types are supported:
350
351
            1. (arg0: numpy.ndarray[numpy.int32]) -> str
            2. (arg0: numpy.ndarray[numpy.float64]) -> str
352

353
        Invoked with: """
354
355

    with pytest.raises(TypeError) as excinfo:
356
357
        m.overloaded3(np.array([1], dtype="uintc"))
    assert msg(excinfo.value) == expected_exc + repr(np.array([1], dtype="uint32"))
358
    with pytest.raises(TypeError) as excinfo:
359
360
        m.overloaded3(np.array([1], dtype="float32"))
    assert msg(excinfo.value) == expected_exc + repr(np.array([1.0], dtype="float32"))
361
    with pytest.raises(TypeError) as excinfo:
362
363
        m.overloaded3(np.array([1], dtype="complex"))
    assert msg(excinfo.value) == expected_exc + repr(np.array([1.0 + 0.0j]))
364
365

    # Exact matches:
366
367
    assert m.overloaded4(np.array([1], dtype="double")) == "double"
    assert m.overloaded4(np.array([1], dtype="longlong")) == "long long"
368
369
370
    # Non-exact matches requiring conversion.  Since float to integer isn't a
    # save conversion, it should go to the double overload, but short can go to
    # either (and so should end up on the first-registered, the long long).
371
372
    assert m.overloaded4(np.array([1], dtype="float32")) == "double"
    assert m.overloaded4(np.array([1], dtype="short")) == "long long"
373

374
375
376
    assert m.overloaded5(np.array([1], dtype="double")) == "double"
    assert m.overloaded5(np.array([1], dtype="uintc")) == "unsigned int"
    assert m.overloaded5(np.array([1], dtype="float32")) == "unsigned int"
377
378


379
380
def test_greedy_string_overload():
    """Tests fix for #685 - ndarray shouldn't go to std::string overload"""
381

382
    assert m.issue685("abc") == "string"
383
    assert m.issue685(np.array([97, 98, 99], dtype="b")) == "array"
384
    assert m.issue685(123) == "other"
385
386


387
def test_array_unchecked_fixed_dims(msg):
388
    z1 = np.array([[1, 2], [3, 4]], dtype="float64")
389
    m.proxy_add2(z1, 10)
390
391
392
    assert np.all(z1 == [[11, 12], [13, 14]])

    with pytest.raises(ValueError) as excinfo:
393
394
395
396
        m.proxy_add2(np.array([1.0, 2, 3]), 5.0)
    assert (
        msg(excinfo.value) == "array has incorrect number of dimensions: 1; expected 2"
    )
397

398
    expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")
399
    assert np.all(m.proxy_init3(3.0) == expect_c)
400
    expect_f = np.transpose(expect_c)
401
    assert np.all(m.proxy_init3F(3.0) == expect_f)
402

403
404
    assert m.proxy_squared_L2_norm(np.array(range(6))) == 55
    assert m.proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
405

406
407
    assert m.proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
    assert m.proxy_auxiliaries2(z1) == m.array_auxiliaries2(z1)
408

409
410
411
    assert m.proxy_auxiliaries1_const_ref(z1[0, :])
    assert m.proxy_auxiliaries2_const_ref(z1)

412

Nick Cullen's avatar
Nick Cullen committed
413
def test_array_unchecked_dyn_dims():
414
    z1 = np.array([[1, 2], [3, 4]], dtype="float64")
415
    m.proxy_add2_dyn(z1, 10)
416
417
    assert np.all(z1 == [[11, 12], [13, 14]])

418
    expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype="int")
419
    assert np.all(m.proxy_init3_dyn(3.0) == expect_c)
420

421
422
    assert m.proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
    assert m.proxy_auxiliaries2_dyn(z1) == m.array_auxiliaries2(z1)
423
424
425
426


def test_array_failure():
    with pytest.raises(ValueError) as excinfo:
427
        m.array_fail_test()
428
    assert str(excinfo.value) == "cannot create a pybind11::array from a nullptr"
429
430

    with pytest.raises(ValueError) as excinfo:
431
        m.array_t_fail_test()
432
    assert str(excinfo.value) == "cannot create a pybind11::array_t from a nullptr"
uentity's avatar
uentity committed
433

434
    with pytest.raises(ValueError) as excinfo:
435
        m.array_fail_test_negative_size()
436
    assert str(excinfo.value) == "negative dimensions are not allowed"
437

uentity's avatar
uentity committed
438

439
440
441
442
443
444
def test_initializer_list():
    assert m.array_initializer_list1().shape == (1,)
    assert m.array_initializer_list2().shape == (1, 2)
    assert m.array_initializer_list3().shape == (1, 2, 3)
    assert m.array_initializer_list4().shape == (1, 2, 3, 4)

uentity's avatar
uentity committed
445

Nick Cullen's avatar
Nick Cullen committed
446
def test_array_resize():
447
    a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9], dtype="float64")
448
    m.array_reshape2(a)
449
450
    assert a.size == 9
    assert np.all(a == [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
uentity's avatar
uentity committed
451
452

    # total size change should succced with refcheck off
453
    m.array_resize3(a, 4, False)
454
    assert a.size == 64
uentity's avatar
uentity committed
455
456
    # ... and fail with refcheck on
    try:
457
        m.array_resize3(a, 3, True)
uentity's avatar
uentity committed
458
    except ValueError as e:
459
        assert str(e).startswith("cannot resize an array")
uentity's avatar
uentity committed
460
461
462
    # transposed array doesn't own data
    b = a.transpose()
    try:
463
        m.array_resize3(b, 3, False)
uentity's avatar
uentity committed
464
    except ValueError as e:
465
        assert str(e).startswith("cannot resize this array: it does not own its data")
uentity's avatar
uentity committed
466
    # ... but reshape should be fine
467
    m.array_reshape2(b)
468
    assert b.shape == (8, 8)
uentity's avatar
uentity committed
469
470


471
@pytest.mark.xfail("env.PYPY")
Nick Cullen's avatar
Nick Cullen committed
472
def test_array_create_and_resize():
473
    a = m.create_and_resize(2)
474
475
    assert a.size == 4
    assert np.all(a == 42.0)
476
477


Nick Cullen's avatar
Nick Cullen committed
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
def test_array_view():
    a = np.ones(100 * 4).astype("uint8")
    a_float_view = m.array_view(a, "float32")
    assert a_float_view.shape == (100 * 1,)  # 1 / 4 bytes = 8 / 32

    a_int16_view = m.array_view(a, "int16")  # 1 / 2 bytes = 16 / 32
    assert a_int16_view.shape == (100 * 2,)


def test_array_view_invalid():
    a = np.ones(100 * 4).astype("uint8")
    with pytest.raises(TypeError):
        m.array_view(a, "deadly_dtype")


Nick Cullen's avatar
Nick Cullen committed
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
def test_reshape_initializer_list():
    a = np.arange(2 * 7 * 3) + 1
    x = m.reshape_initializer_list(a, 2, 7, 3)
    assert x.shape == (2, 7, 3)
    assert list(x[1][4]) == [34, 35, 36]
    with pytest.raises(ValueError) as excinfo:
        m.reshape_initializer_list(a, 1, 7, 3)
    assert str(excinfo.value) == "cannot reshape array of size 42 into shape (1,7,3)"


def test_reshape_tuple():
    a = np.arange(3 * 7 * 2) + 1
    x = m.reshape_tuple(a, (3, 7, 2))
    assert x.shape == (3, 7, 2)
    assert list(x[1][4]) == [23, 24]
    y = m.reshape_tuple(x, (x.size,))
    assert y.shape == (42,)
    with pytest.raises(ValueError) as excinfo:
        m.reshape_tuple(a, (3, 7, 1))
    assert str(excinfo.value) == "cannot reshape array of size 42 into shape (3,7,1)"
    with pytest.raises(ValueError) as excinfo:
        m.reshape_tuple(a, ())
    assert str(excinfo.value) == "cannot reshape array of size 42 into shape ()"


518
519
520
def test_index_using_ellipsis():
    a = m.index_using_ellipsis(np.zeros((5, 6, 7)))
    assert a.shape == (6,)
521
522


523
524
525
526
527
528
529
530
531
532
533
534
535
@pytest.mark.parametrize(
    "test_func",
    [
        m.test_fmt_desc_float,
        m.test_fmt_desc_double,
        m.test_fmt_desc_const_float,
        m.test_fmt_desc_const_double,
    ],
)
def test_format_descriptors_for_floating_point_types(test_func):
    assert "numpy.ndarray[numpy.float" in test_func.__doc__


536
@pytest.mark.parametrize("forcecast", [False, True])
537
@pytest.mark.parametrize("contiguity", [None, "C", "F"])
538
539
540
541
542
543
@pytest.mark.parametrize("noconvert", [False, True])
@pytest.mark.filterwarnings(
    "ignore:Casting complex values to real discards the imaginary part:numpy.ComplexWarning"
)
def test_argument_conversions(forcecast, contiguity, noconvert):
    function_name = "accept_double"
544
    if contiguity == "C":
545
        function_name += "_c_style"
546
    elif contiguity == "F":
547
548
549
550
551
552
553
        function_name += "_f_style"
    if forcecast:
        function_name += "_forcecast"
    if noconvert:
        function_name += "_noconvert"
    function = getattr(m, function_name)

554
555
    for dtype in [np.dtype("float32"), np.dtype("float64"), np.dtype("complex128")]:
        for order in ["C", "F"]:
556
557
558
559
560
            for shape in [(2, 2), (1, 3, 1, 1), (1, 1, 1), (0,)]:
                if not noconvert:
                    # If noconvert is not passed, only complex128 needs to be truncated and
                    # "cannot be safely obtained". So without `forcecast`, the argument shouldn't
                    # be accepted.
561
                    should_raise = dtype.name == "complex128" and not forcecast
562
563
564
565
566
                else:
                    # If noconvert is passed, only float64 and the matching order is accepted.
                    # If at most one dimension has a size greater than 1, the array is also
                    # trivially contiguous.
                    trivially_contiguous = sum(1 for d in shape if d > 1) <= 1
567
568
569
570
                    should_raise = dtype.name != "float64" or (
                        contiguity is not None
                        and contiguity != order
                        and not trivially_contiguous
571
572
573
574
575
576
                    )

                array = np.zeros(shape, dtype=dtype, order=order)
                if not should_raise:
                    function(array)
                else:
577
578
579
                    with pytest.raises(
                        TypeError, match="incompatible function arguments"
                    ):
580
581
582
                        function(array)


583
@pytest.mark.xfail("env.PYPY")
584
585
def test_dtype_refcount_leak():
    from sys import getrefcount
586

587
588
589
590
591
592
    dtype = np.dtype(np.float_)
    a = np.array([1], dtype=dtype)
    before = getrefcount(dtype)
    m.ndim(a)
    after = getrefcount(dtype)
    assert after == before