1# -*- coding: utf-8 -*- 2import io 3import struct 4import ctypes 5 6import pytest 7 8import env # noqa: F401 9 10from pybind11_tests import buffers as m 11from pybind11_tests import ConstructorStats 12 13np = pytest.importorskip("numpy") 14 15 16def test_from_python(): 17 with pytest.raises(RuntimeError) as excinfo: 18 m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array 19 assert str(excinfo.value) == "Incompatible buffer format!" 20 21 m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) 22 m4 = m.Matrix(m3) 23 24 for i in range(m4.rows()): 25 for j in range(m4.cols()): 26 assert m3[i, j] == m4[i, j] 27 28 cstats = ConstructorStats.get(m.Matrix) 29 assert cstats.alive() == 1 30 del m3, m4 31 assert cstats.alive() == 0 32 assert cstats.values() == ["2x3 matrix"] 33 assert cstats.copy_constructions == 0 34 # assert cstats.move_constructions >= 0 # Don't invoke any 35 assert cstats.copy_assignments == 0 36 assert cstats.move_assignments == 0 37 38 39# https://foss.heptapod.net/pypy/pypy/-/issues/2444 40def test_to_python(): 41 mat = m.Matrix(5, 4) 42 assert memoryview(mat).shape == (5, 4) 43 44 assert mat[2, 3] == 0 45 mat[2, 3] = 4.0 46 mat[3, 2] = 7.0 47 assert mat[2, 3] == 4 48 assert mat[3, 2] == 7 49 assert struct.unpack_from("f", mat, (3 * 4 + 2) * 4) == (7,) 50 assert struct.unpack_from("f", mat, (2 * 4 + 3) * 4) == (4,) 51 52 mat2 = np.array(mat, copy=False) 53 assert mat2.shape == (5, 4) 54 assert abs(mat2).sum() == 11 55 assert mat2[2, 3] == 4 and mat2[3, 2] == 7 56 mat2[2, 3] = 5 57 assert mat2[2, 3] == 5 58 59 cstats = ConstructorStats.get(m.Matrix) 60 assert cstats.alive() == 1 61 del mat 62 pytest.gc_collect() 63 assert cstats.alive() == 1 64 del mat2 # holds a mat reference 65 pytest.gc_collect() 66 assert cstats.alive() == 0 67 assert cstats.values() == ["5x4 matrix"] 68 assert cstats.copy_constructions == 0 69 # assert cstats.move_constructions >= 0 # Don't invoke any 70 assert cstats.copy_assignments == 0 71 assert cstats.move_assignments == 0 72 73 74def test_inherited_protocol(): 75 """SquareMatrix is derived from Matrix and inherits the buffer protocol""" 76 77 matrix = m.SquareMatrix(5) 78 assert memoryview(matrix).shape == (5, 5) 79 assert np.asarray(matrix).shape == (5, 5) 80 81 82def test_pointer_to_member_fn(): 83 for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]: 84 buf = cls() 85 buf.value = 0x12345678 86 value = struct.unpack("i", bytearray(buf))[0] 87 assert value == 0x12345678 88 89 90def test_readonly_buffer(): 91 buf = m.BufferReadOnly(0x64) 92 view = memoryview(buf) 93 assert view[0] == b"d" if env.PY2 else 0x64 94 assert view.readonly 95 with pytest.raises(TypeError): 96 view[0] = b"\0" if env.PY2 else 0 97 98 99def test_selective_readonly_buffer(): 100 buf = m.BufferReadOnlySelect() 101 102 memoryview(buf)[0] = b"d" if env.PY2 else 0x64 103 assert buf.value == 0x64 104 105 io.BytesIO(b"A").readinto(buf) 106 assert buf.value == ord(b"A") 107 108 buf.readonly = True 109 with pytest.raises(TypeError): 110 memoryview(buf)[0] = b"\0" if env.PY2 else 0 111 with pytest.raises(TypeError): 112 io.BytesIO(b"1").readinto(buf) 113 114 115def test_ctypes_array_1d(): 116 char1d = (ctypes.c_char * 10)() 117 int1d = (ctypes.c_int * 15)() 118 long1d = (ctypes.c_long * 7)() 119 120 for carray in (char1d, int1d, long1d): 121 info = m.get_buffer_info(carray) 122 assert info.itemsize == ctypes.sizeof(carray._type_) 123 assert info.size == len(carray) 124 assert info.ndim == 1 125 assert info.shape == [info.size] 126 assert info.strides == [info.itemsize] 127 assert not info.readonly 128 129 130def test_ctypes_array_2d(): 131 char2d = ((ctypes.c_char * 10) * 4)() 132 int2d = ((ctypes.c_int * 15) * 3)() 133 long2d = ((ctypes.c_long * 7) * 2)() 134 135 for carray in (char2d, int2d, long2d): 136 info = m.get_buffer_info(carray) 137 assert info.itemsize == ctypes.sizeof(carray[0]._type_) 138 assert info.size == len(carray) * len(carray[0]) 139 assert info.ndim == 2 140 assert info.shape == [len(carray), len(carray[0])] 141 assert info.strides == [info.itemsize * len(carray[0]), info.itemsize] 142 assert not info.readonly 143 144 145@pytest.mark.skipif( 146 "env.PYPY and env.PY2", reason="PyPy2 bytes buffer not reported as readonly" 147) 148def test_ctypes_from_buffer(): 149 test_pystr = b"0123456789" 150 for pyarray in (test_pystr, bytearray(test_pystr)): 151 pyinfo = m.get_buffer_info(pyarray) 152 153 if pyinfo.readonly: 154 cbytes = (ctypes.c_char * len(pyarray)).from_buffer_copy(pyarray) 155 cinfo = m.get_buffer_info(cbytes) 156 else: 157 cbytes = (ctypes.c_char * len(pyarray)).from_buffer(pyarray) 158 cinfo = m.get_buffer_info(cbytes) 159 160 assert cinfo.size == pyinfo.size 161 assert cinfo.ndim == pyinfo.ndim 162 assert cinfo.shape == pyinfo.shape 163 assert cinfo.strides == pyinfo.strides 164 assert not cinfo.readonly 165