import pytest pytestmark = pytest.requires_numpy with pytest.suppress(ImportError): import numpy as np @pytest.fixture(scope='function') def arr(): return np.array([[1, 2, 3], [4, 5, 6]], '=u2') def test_array_attributes(): from pybind11_tests.array import ( ndim, shape, strides, writeable, size, itemsize, nbytes, owndata ) a = np.array(0, 'f8') assert ndim(a) == 0 assert all(shape(a) == []) assert all(strides(a) == []) with pytest.raises(IndexError) as excinfo: shape(a, 0) assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' with pytest.raises(IndexError) as excinfo: strides(a, 0) assert str(excinfo.value) == 'invalid axis: 0 (ndim = 0)' assert writeable(a) assert size(a) == 1 assert itemsize(a) == 8 assert nbytes(a) == 8 assert owndata(a) a = np.array([[1, 2, 3], [4, 5, 6]], 'u2').view() a.flags.writeable = False assert ndim(a) == 2 assert all(shape(a) == [2, 3]) assert shape(a, 0) == 2 assert shape(a, 1) == 3 assert all(strides(a) == [6, 2]) assert strides(a, 0) == 6 assert strides(a, 1) == 2 with pytest.raises(IndexError) as excinfo: shape(a, 2) assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' with pytest.raises(IndexError) as excinfo: strides(a, 2) assert str(excinfo.value) == 'invalid axis: 2 (ndim = 2)' assert not writeable(a) assert size(a) == 6 assert itemsize(a) == 2 assert nbytes(a) == 12 assert not owndata(a) @pytest.mark.parametrize('args, ret', [([], 0), ([0], 0), ([1], 3), ([0, 1], 1), ([1, 2], 5)]) def test_index_offset(arr, args, ret): from pybind11_tests.array import index_at, index_at_t, offset_at, offset_at_t assert index_at(arr, *args) == ret assert index_at_t(arr, *args) == ret assert offset_at(arr, *args) == ret * arr.dtype.itemsize assert offset_at_t(arr, *args) == ret * arr.dtype.itemsize def test_dim_check_fail(arr): from pybind11_tests.array import (index_at, index_at_t, offset_at, offset_at_t, data, data_t, mutate_data, mutate_data_t) for func in (index_at, index_at_t, offset_at, offset_at_t, data, data_t, mutate_data, mutate_data_t): with pytest.raises(IndexError) as excinfo: func(arr, 1, 2, 3) assert str(excinfo.value) == 'too many indices for an array: 3 (ndim = 2)' @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])]) def test_data(arr, args, ret): from pybind11_tests.array import data, data_t from sys import byteorder assert all(data_t(arr, *args) == ret) assert all(data(arr, *args)[(0 if byteorder == 'little' else 1)::2] == ret) assert all(data(arr, *args)[(1 if byteorder == 'little' else 0)::2] == 0) def test_mutate_readonly(arr): from pybind11_tests.array import mutate_data, mutate_data_t, mutate_at_t arr.flags.writeable = False for func, args in (mutate_data, ()), (mutate_data_t, ()), (mutate_at_t, (0, 0)): with pytest.raises(ValueError) as excinfo: func(arr, *args) assert str(excinfo.value) == 'array is not writeable' @pytest.mark.parametrize('dim', [0, 1, 3]) def test_at_fail(arr, dim): from pybind11_tests.array import at_t, mutate_at_t for func in at_t, mutate_at_t: with pytest.raises(IndexError) as excinfo: func(arr, *([0] * dim)) assert str(excinfo.value) == 'index dimension mismatch: {} (ndim = 2)'.format(dim) def test_at(arr): from pybind11_tests.array import at_t, mutate_at_t assert at_t(arr, 0, 2) == 3 assert at_t(arr, 1, 0) == 4 assert all(mutate_at_t(arr, 0, 2).ravel() == [1, 2, 4, 4, 5, 6]) assert all(mutate_at_t(arr, 1, 0).ravel() == [1, 2, 4, 5, 5, 6]) def test_mutate_data(arr): from pybind11_tests.array import mutate_data, mutate_data_t assert all(mutate_data(arr).ravel() == [2, 4, 6, 8, 10, 12]) assert all(mutate_data(arr).ravel() == [4, 8, 12, 16, 20, 24]) assert all(mutate_data(arr, 1).ravel() == [4, 8, 12, 32, 40, 48]) assert all(mutate_data(arr, 0, 1).ravel() == [4, 16, 24, 64, 80, 96]) assert all(mutate_data(arr, 1, 2).ravel() == [4, 16, 24, 64, 80, 192]) assert all(mutate_data_t(arr).ravel() == [5, 17, 25, 65, 81, 193]) assert all(mutate_data_t(arr).ravel() == [6, 18, 26, 66, 82, 194]) assert all(mutate_data_t(arr, 1).ravel() == [6, 18, 26, 67, 83, 195]) assert all(mutate_data_t(arr, 0, 1).ravel() == [6, 19, 27, 68, 84, 196]) assert all(mutate_data_t(arr, 1, 2).ravel() == [6, 19, 27, 68, 84, 197]) def test_bounds_check(arr): from pybind11_tests.array import (index_at, index_at_t, data, data_t, mutate_data, mutate_data_t, at_t, mutate_at_t) funcs = (index_at, index_at_t, data, data_t, mutate_data, mutate_data_t, at_t, mutate_at_t) for func in funcs: with pytest.raises(IndexError) as excinfo: func(arr, 2, 0) assert str(excinfo.value) == 'index 2 is out of bounds for axis 0 with size 2' with pytest.raises(IndexError) as excinfo: func(arr, 0, 4) assert str(excinfo.value) == 'index 4 is out of bounds for axis 1 with size 3' def test_make_c_f_array(): from pybind11_tests.array import ( make_c_array, make_f_array ) assert make_c_array().flags.c_contiguous assert not make_c_array().flags.f_contiguous assert make_f_array().flags.f_contiguous assert not make_f_array().flags.c_contiguous def test_wrap(): from pybind11_tests.array import wrap def assert_references(a, b, base=None): if base is None: base = a assert a is not b assert a.__array_interface__['data'][0] == b.__array_interface__['data'][0] 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 assert a.flags.updateifcopy == b.flags.updateifcopy assert np.all(a == b) assert not b.flags.owndata assert b.base is base 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 a2 = wrap(a1) assert_references(a1, a2) a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='F') assert a1.flags.owndata and a1.base is None a2 = wrap(a1) assert_references(a1, a2) a1 = np.array([[1, 2], [3, 4]], dtype=np.float32, order='C') a1.flags.writeable = False a2 = wrap(a1) assert_references(a1, a2) a1 = np.random.random((4, 4, 4)) a2 = wrap(a1) assert_references(a1, a2) a1t = a1.transpose() a2 = wrap(a1t) assert_references(a1t, a2, a1) a1d = a1.diagonal() a2 = wrap(a1d) assert_references(a1d, a2, a1) def test_numpy_view(capture): from pybind11_tests.array import ArrayClass with capture: ac = ArrayClass() 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 pytest.gc_collect() assert capture == """ ArrayClass() ArrayClass::numpy_view() ArrayClass::numpy_view() """ 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 pytest.gc_collect() pytest.gc_collect() assert capture == """ ~ArrayClass() """ @pytest.unsupported_on_pypy def test_cast_numpy_int64_to_uint64(): from pybind11_tests.array import function_taking_uint64 function_taking_uint64(123) function_taking_uint64(np.uint64(123)) def test_isinstance(): from pybind11_tests.array import isinstance_untyped, isinstance_typed assert isinstance_untyped(np.array([1, 2, 3]), "not an array") assert isinstance_typed(np.array([1.0, 2.0, 3.0])) def test_constructors(): from pybind11_tests.array import default_constructors, converting_constructors defaults = default_constructors() for a in defaults.values(): assert a.size == 0 assert defaults["array"].dtype == np.array([]).dtype assert defaults["array_t"].dtype == np.int32 assert defaults["array_t"].dtype == np.float64 results = converting_constructors([1, 2, 3]) for a in results.values(): np.testing.assert_array_equal(a, [1, 2, 3]) assert results["array"].dtype == np.int_ assert results["array_t"].dtype == np.int32 assert results["array_t"].dtype == np.float64 def test_overload_resolution(msg): from pybind11_tests.array import overloaded, overloaded2, overloaded3, overloaded4, overloaded5 # Exact overload matches: assert overloaded(np.array([1], dtype='float64')) == 'double' assert overloaded(np.array([1], dtype='float32')) == 'float' assert overloaded(np.array([1], dtype='ushort')) == 'unsigned short' assert overloaded(np.array([1], dtype='intc')) == 'int' assert overloaded(np.array([1], dtype='longlong')) == 'long long' assert overloaded(np.array([1], dtype='complex')) == 'double complex' assert overloaded(np.array([1], dtype='csingle')) == 'float complex' # No exact match, should call first convertible version: assert overloaded(np.array([1], dtype='uint8')) == 'double' with pytest.raises(TypeError) as excinfo: overloaded("not an array") assert msg(excinfo.value) == """ overloaded(): incompatible function arguments. The following argument types are supported: 1. (arg0: numpy.ndarray[float64]) -> str 2. (arg0: numpy.ndarray[float32]) -> str 3. (arg0: numpy.ndarray[int32]) -> str 4. (arg0: numpy.ndarray[uint16]) -> str 5. (arg0: numpy.ndarray[int64]) -> str 6. (arg0: numpy.ndarray[complex128]) -> str 7. (arg0: numpy.ndarray[complex64]) -> str Invoked with: 'not an array' """ assert overloaded2(np.array([1], dtype='float64')) == 'double' assert overloaded2(np.array([1], dtype='float32')) == 'float' assert overloaded2(np.array([1], dtype='complex64')) == 'float complex' assert overloaded2(np.array([1], dtype='complex128')) == 'double complex' assert overloaded2(np.array([1], dtype='float32')) == 'float' assert overloaded3(np.array([1], dtype='float64')) == 'double' assert overloaded3(np.array([1], dtype='intc')) == 'int' expected_exc = """ overloaded3(): incompatible function arguments. The following argument types are supported: 1. (arg0: numpy.ndarray[int32]) -> str 2. (arg0: numpy.ndarray[float64]) -> str Invoked with:""" with pytest.raises(TypeError) as excinfo: overloaded3(np.array([1], dtype='uintc')) assert msg(excinfo.value) == expected_exc + " array([1], dtype=uint32)" with pytest.raises(TypeError) as excinfo: overloaded3(np.array([1], dtype='float32')) assert msg(excinfo.value) == expected_exc + " array([ 1.], dtype=float32)" with pytest.raises(TypeError) as excinfo: overloaded3(np.array([1], dtype='complex')) assert msg(excinfo.value) == expected_exc + " array([ 1.+0.j])" # Exact matches: assert overloaded4(np.array([1], dtype='double')) == 'double' assert overloaded4(np.array([1], dtype='longlong')) == 'long long' # 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). assert overloaded4(np.array([1], dtype='float32')) == 'double' assert overloaded4(np.array([1], dtype='short')) == 'long long' assert overloaded5(np.array([1], dtype='double')) == 'double' assert overloaded5(np.array([1], dtype='uintc')) == 'unsigned int' assert overloaded5(np.array([1], dtype='float32')) == 'unsigned int' def test_greedy_string_overload(): # issue 685 from pybind11_tests.array import issue685 assert issue685("abc") == "string" assert issue685(np.array([97, 98, 99], dtype='b')) == "array" assert issue685(123) == "other"