Permit creation of NumPy arrays with a "base" object that owns the data

This patch adds an extra base handle parameter to most ``py::array`` and
``py::array_t<>`` constructors. If specified along with a pointer to
data, the base object will be registered within NumPy, which increases
the base's reference count. This feature is useful to create shallow
copies of C++ or Python arrays while ensuring that the owners of the
underlying can't be garbage collected while referenced by NumPy.

The commit also adds a simple test function involving a ``wrap()``
function that creates shallow copies of various N-D arrays.
This commit is contained in:
Wenzel Jakob
2016-10-13 01:03:40 +02:00
parent 43f6aa6846
commit 369e9b3937
3 changed files with 124 additions and 24 deletions
+51
View File
@@ -149,6 +149,7 @@ def test_bounds_check(arr):
index_at(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 (
@@ -158,3 +159,53 @@ def test_make_c_f_array():
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)