Henry Schreiner | d8c7ee0 | 2020-07-20 13:35:21 -0400 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 2 | import io |
Bruce Merry | fe0cf8b | 2017-05-17 10:52:33 +0200 | [diff] [blame] | 3 | import struct |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 4 | |
Dean Moldovan | a0c1ccf | 2016-08-12 13:50:00 +0200 | [diff] [blame] | 5 | import pytest |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 6 | |
Henry Schreiner | 4d9024e | 2020-08-16 16:02:12 -0400 | [diff] [blame] | 7 | import env # noqa: F401 |
| 8 | |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 9 | from pybind11_tests import buffers as m |
| 10 | from pybind11_tests import ConstructorStats |
Dean Moldovan | a0c1ccf | 2016-08-12 13:50:00 +0200 | [diff] [blame] | 11 | |
Henry Schreiner | 4d9024e | 2020-08-16 16:02:12 -0400 | [diff] [blame] | 12 | np = pytest.importorskip("numpy") |
Dean Moldovan | a0c1ccf | 2016-08-12 13:50:00 +0200 | [diff] [blame] | 13 | |
| 14 | |
Dean Moldovan | a0c1ccf | 2016-08-12 13:50:00 +0200 | [diff] [blame] | 15 | def test_from_python(): |
| 16 | with pytest.raises(RuntimeError) as excinfo: |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 17 | m.Matrix(np.array([1, 2, 3])) # trying to assign a 1D array |
Dean Moldovan | a0c1ccf | 2016-08-12 13:50:00 +0200 | [diff] [blame] | 18 | assert str(excinfo.value) == "Incompatible buffer format!" |
| 19 | |
| 20 | m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32) |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 21 | m4 = m.Matrix(m3) |
Dean Moldovan | a0c1ccf | 2016-08-12 13:50:00 +0200 | [diff] [blame] | 22 | |
| 23 | for i in range(m4.rows()): |
| 24 | for j in range(m4.cols()): |
| 25 | assert m3[i, j] == m4[i, j] |
| 26 | |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 27 | cstats = ConstructorStats.get(m.Matrix) |
Dean Moldovan | a0c1ccf | 2016-08-12 13:50:00 +0200 | [diff] [blame] | 28 | assert cstats.alive() == 1 |
| 29 | del m3, m4 |
| 30 | assert cstats.alive() == 0 |
| 31 | assert cstats.values() == ["2x3 matrix"] |
| 32 | assert cstats.copy_constructions == 0 |
| 33 | # assert cstats.move_constructions >= 0 # Don't invoke any |
| 34 | assert cstats.copy_assignments == 0 |
| 35 | assert cstats.move_assignments == 0 |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 36 | |
| 37 | |
Henry Schreiner | 4d9024e | 2020-08-16 16:02:12 -0400 | [diff] [blame] | 38 | # https://foss.heptapod.net/pypy/pypy/-/issues/2444 |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 39 | def test_to_python(): |
Ansgar Burchardt | a22dd2d | 2017-09-21 23:07:48 +0200 | [diff] [blame] | 40 | mat = m.Matrix(5, 4) |
| 41 | assert memoryview(mat).shape == (5, 4) |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 42 | |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 43 | assert mat[2, 3] == 0 |
Ansgar Burchardt | a22dd2d | 2017-09-21 23:07:48 +0200 | [diff] [blame] | 44 | mat[2, 3] = 4.0 |
| 45 | mat[3, 2] = 7.0 |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 46 | assert mat[2, 3] == 4 |
Ansgar Burchardt | a22dd2d | 2017-09-21 23:07:48 +0200 | [diff] [blame] | 47 | assert mat[3, 2] == 7 |
| 48 | assert struct.unpack_from('f', mat, (3 * 4 + 2) * 4) == (7, ) |
| 49 | assert struct.unpack_from('f', mat, (2 * 4 + 3) * 4) == (4, ) |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 50 | |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 51 | mat2 = np.array(mat, copy=False) |
Ansgar Burchardt | a22dd2d | 2017-09-21 23:07:48 +0200 | [diff] [blame] | 52 | assert mat2.shape == (5, 4) |
| 53 | assert abs(mat2).sum() == 11 |
| 54 | assert mat2[2, 3] == 4 and mat2[3, 2] == 7 |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 55 | mat2[2, 3] = 5 |
| 56 | assert mat2[2, 3] == 5 |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 57 | |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 58 | cstats = ConstructorStats.get(m.Matrix) |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 59 | assert cstats.alive() == 1 |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 60 | del mat |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 61 | pytest.gc_collect() |
| 62 | assert cstats.alive() == 1 |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 63 | del mat2 # holds a mat reference |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 64 | pytest.gc_collect() |
| 65 | assert cstats.alive() == 0 |
Ansgar Burchardt | a22dd2d | 2017-09-21 23:07:48 +0200 | [diff] [blame] | 66 | assert cstats.values() == ["5x4 matrix"] |
Wenzel Jakob | 1d1f81b | 2016-12-16 15:00:46 +0100 | [diff] [blame] | 67 | assert cstats.copy_constructions == 0 |
| 68 | # assert cstats.move_constructions >= 0 # Don't invoke any |
| 69 | assert cstats.copy_assignments == 0 |
| 70 | assert cstats.move_assignments == 0 |
Bruce Merry | fe0cf8b | 2017-05-17 10:52:33 +0200 | [diff] [blame] | 71 | |
| 72 | |
Dean Moldovan | 427e4af | 2017-05-28 16:35:02 +0200 | [diff] [blame] | 73 | def test_inherited_protocol(): |
| 74 | """SquareMatrix is derived from Matrix and inherits the buffer protocol""" |
Dean Moldovan | 427e4af | 2017-05-28 16:35:02 +0200 | [diff] [blame] | 75 | |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 76 | matrix = m.SquareMatrix(5) |
Dean Moldovan | 427e4af | 2017-05-28 16:35:02 +0200 | [diff] [blame] | 77 | assert memoryview(matrix).shape == (5, 5) |
| 78 | assert np.asarray(matrix).shape == (5, 5) |
| 79 | |
| 80 | |
Jason Rhinelander | 391c754 | 2017-07-25 16:47:36 -0400 | [diff] [blame] | 81 | def test_pointer_to_member_fn(): |
| 82 | for cls in [m.Buffer, m.ConstBuffer, m.DerivedBuffer]: |
Bruce Merry | fe0cf8b | 2017-05-17 10:52:33 +0200 | [diff] [blame] | 83 | buf = cls() |
| 84 | buf.value = 0x12345678 |
| 85 | value = struct.unpack('i', bytearray(buf))[0] |
| 86 | assert value == 0x12345678 |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 87 | |
| 88 | |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 89 | def test_readonly_buffer(): |
| 90 | buf = m.BufferReadOnly(0x64) |
| 91 | view = memoryview(buf) |
Henry Schreiner | 4d9024e | 2020-08-16 16:02:12 -0400 | [diff] [blame] | 92 | assert view[0] == b'd' if env.PY2 else 0x64 |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 93 | assert view.readonly |
| 94 | |
| 95 | |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 96 | def test_selective_readonly_buffer(): |
| 97 | buf = m.BufferReadOnlySelect() |
| 98 | |
Henry Schreiner | 4d9024e | 2020-08-16 16:02:12 -0400 | [diff] [blame] | 99 | memoryview(buf)[0] = b'd' if env.PY2 else 0x64 |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 100 | assert buf.value == 0x64 |
| 101 | |
| 102 | io.BytesIO(b'A').readinto(buf) |
| 103 | assert buf.value == ord(b'A') |
| 104 | |
| 105 | buf.readonly = True |
| 106 | with pytest.raises(TypeError): |
Henry Schreiner | 4d9024e | 2020-08-16 16:02:12 -0400 | [diff] [blame] | 107 | memoryview(buf)[0] = b'\0' if env.PY2 else 0 |
Sebastian Koslowski | dc65d66 | 2019-11-24 08:33:05 +0100 | [diff] [blame] | 108 | with pytest.raises(TypeError): |
| 109 | io.BytesIO(b'1').readinto(buf) |