@@ -241,115 +241,151 @@ def test_buffer_exception():
241
241
assert "for context" in str (excinfo .value .__cause__ )
242
242
243
243
244
- def test_to_pybuffer ():
245
- mat = m .Matrix (5 , 4 )
244
+ @pytest .mark .parametrize ("type" , ["pybind11" , "numpy" ])
245
+ def test_c_contiguous_to_pybuffer (type ):
246
+ if type == "pybind11" :
247
+ mat = m .Matrix (5 , 4 )
248
+ elif type == "numpy" :
249
+ mat = np .empty ((5 , 4 ), dtype = np .float32 )
250
+ else :
251
+ raise ValueError (f"Unknown parametrization { type } " )
246
252
247
253
info = m .get_py_buffer (mat , m .PyBUF_SIMPLE )
248
254
assert info .itemsize == ctypes .sizeof (ctypes .c_float )
249
- assert info .len == mat . rows () * mat . cols () * info .itemsize
255
+ assert info .len == 5 * 4 * info .itemsize
250
256
assert info .ndim == 0 # See discussion on PR #5407.
251
257
assert info .shape is None
252
258
assert info .strides is None
253
259
assert info .suboffsets is None
254
260
assert not info .readonly
255
261
info = m .get_py_buffer (mat , m .PyBUF_ND )
256
262
assert info .itemsize == ctypes .sizeof (ctypes .c_float )
257
- assert info .len == mat . rows () * mat . cols () * info .itemsize
263
+ assert info .len == 5 * 4 * info .itemsize
258
264
assert info .ndim == 2
259
265
assert info .shape == [5 , 4 ]
260
266
assert info .strides is None
261
267
assert info .suboffsets is None
262
268
assert not info .readonly
263
269
info = m .get_py_buffer (mat , m .PyBUF_STRIDES )
264
270
assert info .itemsize == ctypes .sizeof (ctypes .c_float )
265
- assert info .len == mat . rows () * mat . cols () * info .itemsize
271
+ assert info .len == 5 * 4 * info .itemsize
266
272
assert info .ndim == 2
267
273
assert info .shape == [5 , 4 ]
268
274
assert info .strides == [4 * info .itemsize , info .itemsize ]
269
275
assert info .suboffsets is None
270
276
assert not info .readonly
271
277
info = m .get_py_buffer (mat , m .PyBUF_INDIRECT )
272
278
assert info .itemsize == ctypes .sizeof (ctypes .c_float )
273
- assert info .len == mat . rows () * mat . cols () * info .itemsize
279
+ assert info .len == 5 * 4 * info .itemsize
274
280
assert info .ndim == 2
275
281
assert info .shape == [5 , 4 ]
276
282
assert info .strides == [4 * info .itemsize , info .itemsize ]
277
283
assert info .suboffsets is None # Should be filled in here, but we don't use it.
278
284
assert not info .readonly
279
285
286
+
287
+ @pytest .mark .parametrize ("type" , ["pybind11" , "numpy" ])
288
+ def test_fortran_contiguous_to_pybuffer (type ):
289
+ if type == "pybind11" :
290
+ mat = m .FortranMatrix (5 , 4 )
291
+ elif type == "numpy" :
292
+ mat = np .empty ((5 , 4 ), dtype = np .float32 , order = "F" )
293
+ else :
294
+ raise ValueError (f"Unknown parametrization { type } " )
295
+
280
296
# A Fortran-shaped buffer can only be accessed at PyBUF_STRIDES level or higher.
281
- mat = m .FortranMatrix (5 , 4 )
282
297
info = m .get_py_buffer (mat , m .PyBUF_STRIDES )
283
298
assert info .itemsize == ctypes .sizeof (ctypes .c_float )
284
- assert info .len == mat . rows () * mat . cols () * info .itemsize
299
+ assert info .len == 5 * 4 * info .itemsize
285
300
assert info .ndim == 2
286
301
assert info .shape == [5 , 4 ]
287
302
assert info .strides == [info .itemsize , 5 * info .itemsize ]
288
303
assert info .suboffsets is None
289
304
assert not info .readonly
290
305
info = m .get_py_buffer (mat , m .PyBUF_INDIRECT )
291
306
assert info .itemsize == ctypes .sizeof (ctypes .c_float )
292
- assert info .len == mat . rows () * mat . cols () * info .itemsize
307
+ assert info .len == 5 * 4 * info .itemsize
293
308
assert info .ndim == 2
294
309
assert info .shape == [5 , 4 ]
295
310
assert info .strides == [info .itemsize , 5 * info .itemsize ]
296
311
assert info .suboffsets is None # Should be filled in here, but we don't use it.
297
312
assert not info .readonly
298
313
299
- mat = m .DiscontiguousMatrix (5 , 4 , 2 , 3 )
314
+
315
+ @pytest .mark .parametrize ("type" , ["pybind11" , "numpy" ])
316
+ def test_discontiguous_to_pybuffer (type ):
317
+ if type == "pybind11" :
318
+ mat = m .DiscontiguousMatrix (5 , 4 , 2 , 3 )
319
+ elif type == "numpy" :
320
+ mat = np .empty ((5 * 2 , 4 * 3 ), dtype = np .float32 )[::2 , ::3 ]
321
+ else :
322
+ raise ValueError (f"Unknown parametrization { type } " )
323
+
300
324
info = m .get_py_buffer (mat , m .PyBUF_STRIDES )
301
325
assert info .itemsize == ctypes .sizeof (ctypes .c_float )
302
- assert info .len == mat . rows () * mat . cols () * info .itemsize
326
+ assert info .len == 5 * 4 * info .itemsize
303
327
assert info .ndim == 2
304
328
assert info .shape == [5 , 4 ]
305
329
assert info .strides == [2 * 4 * 3 * info .itemsize , 3 * info .itemsize ]
306
330
assert info .suboffsets is None
307
331
assert not info .readonly
308
332
309
333
310
- def test_to_pybuffer_contiguity ():
334
+ @pytest .mark .parametrize ("type" , ["pybind11" , "numpy" ])
335
+ def test_to_pybuffer_contiguity (type ):
311
336
def check_strides (mat ):
312
337
# The full block is memset to 0, so fill it with non-zero in real spots.
313
- expected = np .arange (1 , mat .rows () * mat .cols () + 1 ).reshape (
314
- (mat .rows (), mat .cols ())
315
- )
316
- for i in range (mat .rows ()):
317
- for j in range (mat .cols ()):
338
+ expected = np .arange (1 , 5 * 4 + 1 ).reshape ((5 , 4 ))
339
+ for i in range (5 ):
340
+ for j in range (4 ):
318
341
mat [i , j ] = expected [i , j ]
319
342
# If all strides are correct, the exposed buffer should match the input.
320
343
np .testing .assert_array_equal (np .array (mat ), expected )
321
344
322
- mat = m .Matrix (5 , 4 )
323
- check_strides (mat )
345
+ if type == "pybind11" :
346
+ cmat = m .Matrix (5 , 4 ) # C contiguous.
347
+ fmat = m .FortranMatrix (5 , 4 ) # Fortran contiguous.
348
+ dmat = m .DiscontiguousMatrix (5 , 4 , 2 , 3 ) # Not contiguous.
349
+ expected_exception = BufferError
350
+ elif type == "numpy" :
351
+ cmat = np .empty ((5 , 4 ), dtype = np .float32 ) # C contiguous.
352
+ fmat = np .empty ((5 , 4 ), dtype = np .float32 , order = "F" ) # Fortran contiguous.
353
+ dmat = np .empty ((5 * 2 , 4 * 3 ), dtype = np .float32 )[::2 , ::3 ] # Not contiguous.
354
+ # NumPy incorrectly raises ValueError; when the minimum NumPy requirement is
355
+ # above the version that fixes https://github.com/numpy/numpy/issues/3634 then
356
+ # BufferError can be used everywhere.
357
+ expected_exception = (BufferError , ValueError )
358
+ else :
359
+ raise ValueError (f"Unknown parametrization { type } " )
360
+
361
+ check_strides (cmat )
324
362
# Should work in C-contiguous mode, but not Fortran order.
325
- m .get_py_buffer (mat , m .PyBUF_C_CONTIGUOUS )
326
- m .get_py_buffer (mat , m .PyBUF_ANY_CONTIGUOUS )
327
- with pytest .raises (BufferError ):
328
- m .get_py_buffer (mat , m .PyBUF_F_CONTIGUOUS )
363
+ m .get_py_buffer (cmat , m .PyBUF_C_CONTIGUOUS )
364
+ m .get_py_buffer (cmat , m .PyBUF_ANY_CONTIGUOUS )
365
+ with pytest .raises (expected_exception ):
366
+ m .get_py_buffer (cmat , m .PyBUF_F_CONTIGUOUS )
329
367
330
- mat = m .FortranMatrix (5 , 4 )
331
- check_strides (mat )
368
+ check_strides (fmat )
332
369
# These flags imply C-contiguity, so won't work.
333
- with pytest .raises (BufferError ):
334
- m .get_py_buffer (mat , m .PyBUF_SIMPLE )
335
- with pytest .raises (BufferError ):
336
- m .get_py_buffer (mat , m .PyBUF_ND )
370
+ with pytest .raises (expected_exception ):
371
+ m .get_py_buffer (fmat , m .PyBUF_SIMPLE )
372
+ with pytest .raises (expected_exception ):
373
+ m .get_py_buffer (fmat , m .PyBUF_ND )
337
374
# Should work in Fortran-contiguous mode, but not C order.
338
- with pytest .raises (BufferError ):
339
- m .get_py_buffer (mat , m .PyBUF_C_CONTIGUOUS )
340
- m .get_py_buffer (mat , m .PyBUF_ANY_CONTIGUOUS )
341
- m .get_py_buffer (mat , m .PyBUF_F_CONTIGUOUS )
375
+ with pytest .raises (expected_exception ):
376
+ m .get_py_buffer (fmat , m .PyBUF_C_CONTIGUOUS )
377
+ m .get_py_buffer (fmat , m .PyBUF_ANY_CONTIGUOUS )
378
+ m .get_py_buffer (fmat , m .PyBUF_F_CONTIGUOUS )
342
379
343
- mat = m .DiscontiguousMatrix (5 , 4 , 2 , 3 )
344
- check_strides (mat )
380
+ check_strides (dmat )
345
381
# Should never work.
346
- with pytest .raises (BufferError ):
347
- m .get_py_buffer (mat , m .PyBUF_SIMPLE )
348
- with pytest .raises (BufferError ):
349
- m .get_py_buffer (mat , m .PyBUF_ND )
350
- with pytest .raises (BufferError ):
351
- m .get_py_buffer (mat , m .PyBUF_C_CONTIGUOUS )
352
- with pytest .raises (BufferError ):
353
- m .get_py_buffer (mat , m .PyBUF_ANY_CONTIGUOUS )
354
- with pytest .raises (BufferError ):
355
- m .get_py_buffer (mat , m .PyBUF_F_CONTIGUOUS )
382
+ with pytest .raises (expected_exception ):
383
+ m .get_py_buffer (dmat , m .PyBUF_SIMPLE )
384
+ with pytest .raises (expected_exception ):
385
+ m .get_py_buffer (dmat , m .PyBUF_ND )
386
+ with pytest .raises (expected_exception ):
387
+ m .get_py_buffer (dmat , m .PyBUF_C_CONTIGUOUS )
388
+ with pytest .raises (expected_exception ):
389
+ m .get_py_buffer (dmat , m .PyBUF_ANY_CONTIGUOUS )
390
+ with pytest .raises (expected_exception ):
391
+ m .get_py_buffer (dmat , m .PyBUF_F_CONTIGUOUS )
0 commit comments