pybind11/tests/test_numpy_array.py
Wenzel Jakob 1d1f81b278 WIP: PyPy support (#527)
This commit includes modifications that are needed to get pybind11 to work with PyPy. The full test suite compiles and runs except for a last few functions that are commented out (due to problems in PyPy that were reported on the PyPy bugtracker).

Two somewhat intrusive changes were needed to make it possible: two new tags ``py::buffer_protocol()`` and ``py::metaclass()`` must now be specified to the ``class_`` constructor if the class uses the buffer protocol and/or requires a metaclass (e.g. for static properties).

Note that this is only for the PyPy version based on Python 2.7 for now. When the PyPy 3.x has caught up in terms of cpyext compliance, a PyPy 3.x patch will follow.
2016-12-16 15:00:46 +01:00

275 lines
9.0 KiB
Python

import pytest
with pytest.suppress(ImportError):
import numpy as np
@pytest.fixture(scope='function')
def arr():
return np.array([[1, 2, 3], [4, 5, 6]], '<u2')
@pytest.requires_numpy
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.requires_numpy
@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
@pytest.requires_numpy
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.requires_numpy
@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
assert all(data_t(arr, *args) == ret)
assert all(data(arr, *args)[::2] == ret)
assert all(data(arr, *args)[1::2] == 0)
@pytest.requires_numpy
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(RuntimeError) as excinfo:
func(arr, *args)
assert str(excinfo.value) == 'array is not writeable'
@pytest.requires_numpy
@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)
@pytest.requires_numpy
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])
@pytest.requires_numpy
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])
@pytest.requires_numpy
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'
@pytest.requires_numpy
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
@pytest.requires_numpy
def test_wrap():
from pybind11_tests.array import wrap
def assert_references(a, b):
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 a
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)
a1 = a1.transpose()
a2 = wrap(a1)
assert_references(a1, a2)
a1 = a1.diagonal()
a2 = wrap(a1)
assert_references(a1, a2)
@pytest.requires_numpy
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
@pytest.requires_numpy
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))
@pytest.requires_numpy
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]))
@pytest.requires_numpy
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<int32>"].dtype == np.int32
assert defaults["array_t<double>"].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<int32>"].dtype == np.int32
assert results["array_t<double>"].dtype == np.float64