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