test_scalarbuffer.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. Test scalar buffer interface adheres to PEP 3118
  3. """
  4. import numpy as np
  5. from numpy.core._rational_tests import rational
  6. from numpy.core._multiarray_tests import get_buffer_info
  7. import pytest
  8. from numpy.testing import assert_, assert_equal, assert_raises
  9. # PEP3118 format strings for native (standard alignment and byteorder) types
  10. scalars_and_codes = [
  11. (np.bool_, '?'),
  12. (np.byte, 'b'),
  13. (np.short, 'h'),
  14. (np.intc, 'i'),
  15. (np.int_, 'l'),
  16. (np.longlong, 'q'),
  17. (np.ubyte, 'B'),
  18. (np.ushort, 'H'),
  19. (np.uintc, 'I'),
  20. (np.uint, 'L'),
  21. (np.ulonglong, 'Q'),
  22. (np.half, 'e'),
  23. (np.single, 'f'),
  24. (np.double, 'd'),
  25. (np.longdouble, 'g'),
  26. (np.csingle, 'Zf'),
  27. (np.cdouble, 'Zd'),
  28. (np.clongdouble, 'Zg'),
  29. ]
  30. scalars_only, codes_only = zip(*scalars_and_codes)
  31. class TestScalarPEP3118:
  32. @pytest.mark.parametrize('scalar', scalars_only, ids=codes_only)
  33. def test_scalar_match_array(self, scalar):
  34. x = scalar()
  35. a = np.array([], dtype=np.dtype(scalar))
  36. mv_x = memoryview(x)
  37. mv_a = memoryview(a)
  38. assert_equal(mv_x.format, mv_a.format)
  39. @pytest.mark.parametrize('scalar', scalars_only, ids=codes_only)
  40. def test_scalar_dim(self, scalar):
  41. x = scalar()
  42. mv_x = memoryview(x)
  43. assert_equal(mv_x.itemsize, np.dtype(scalar).itemsize)
  44. assert_equal(mv_x.ndim, 0)
  45. assert_equal(mv_x.shape, ())
  46. assert_equal(mv_x.strides, ())
  47. assert_equal(mv_x.suboffsets, ())
  48. @pytest.mark.parametrize('scalar, code', scalars_and_codes, ids=codes_only)
  49. def test_scalar_code_and_properties(self, scalar, code):
  50. x = scalar()
  51. expected = dict(strides=(), itemsize=x.dtype.itemsize, ndim=0,
  52. shape=(), format=code, readonly=True)
  53. mv_x = memoryview(x)
  54. print(mv_x.readonly, self._as_dict(mv_x))
  55. assert self._as_dict(mv_x) == expected
  56. @pytest.mark.parametrize('scalar', scalars_only, ids=codes_only)
  57. def test_scalar_buffers_readonly(self, scalar):
  58. x = scalar()
  59. with pytest.raises(BufferError, match="scalar buffer is readonly"):
  60. get_buffer_info(x, ["WRITABLE"])
  61. def test_void_scalar_structured_data(self):
  62. dt = np.dtype([('name', np.unicode_, 16), ('grades', np.float64, (2,))])
  63. x = np.array(('ndarray_scalar', (1.2, 3.0)), dtype=dt)[()]
  64. assert_(isinstance(x, np.void))
  65. mv_x = memoryview(x)
  66. expected_size = 16 * np.dtype((np.unicode_, 1)).itemsize
  67. expected_size += 2 * np.dtype(np.float64).itemsize
  68. assert_equal(mv_x.itemsize, expected_size)
  69. assert_equal(mv_x.ndim, 0)
  70. assert_equal(mv_x.shape, ())
  71. assert_equal(mv_x.strides, ())
  72. assert_equal(mv_x.suboffsets, ())
  73. # check scalar format string against ndarray format string
  74. a = np.array([('Sarah', (8.0, 7.0)), ('John', (6.0, 7.0))], dtype=dt)
  75. assert_(isinstance(a, np.ndarray))
  76. mv_a = memoryview(a)
  77. assert_equal(mv_x.itemsize, mv_a.itemsize)
  78. assert_equal(mv_x.format, mv_a.format)
  79. # Check that we do not allow writeable buffer export (technically
  80. # we could allow it sometimes here...)
  81. with pytest.raises(BufferError, match="scalar buffer is readonly"):
  82. get_buffer_info(x, ["WRITABLE"])
  83. def _as_dict(self, m):
  84. return dict(strides=m.strides, shape=m.shape, itemsize=m.itemsize,
  85. ndim=m.ndim, format=m.format, readonly=m.readonly)
  86. def test_datetime_memoryview(self):
  87. # gh-11656
  88. # Values verified with v1.13.3, shape is not () as in test_scalar_dim
  89. dt1 = np.datetime64('2016-01-01')
  90. dt2 = np.datetime64('2017-01-01')
  91. expected = dict(strides=(1,), itemsize=1, ndim=1, shape=(8,),
  92. format='B', readonly=True)
  93. v = memoryview(dt1)
  94. assert self._as_dict(v) == expected
  95. v = memoryview(dt2 - dt1)
  96. assert self._as_dict(v) == expected
  97. dt = np.dtype([('a', 'uint16'), ('b', 'M8[s]')])
  98. a = np.empty(1, dt)
  99. # Fails to create a PEP 3118 valid buffer
  100. assert_raises((ValueError, BufferError), memoryview, a[0])
  101. # Check that we do not allow writeable buffer export
  102. with pytest.raises(BufferError, match="scalar buffer is readonly"):
  103. get_buffer_info(dt1, ["WRITABLE"])
  104. @pytest.mark.parametrize('s', [
  105. pytest.param("\x32\x32", id="ascii"),
  106. pytest.param("\uFE0F\uFE0F", id="basic multilingual"),
  107. pytest.param("\U0001f4bb\U0001f4bb", id="non-BMP"),
  108. ])
  109. def test_str_ucs4(self, s):
  110. s = np.str_(s) # only our subclass implements the buffer protocol
  111. # all the same, characters always encode as ucs4
  112. expected = dict(strides=(), itemsize=8, ndim=0, shape=(), format='2w',
  113. readonly=True)
  114. v = memoryview(s)
  115. assert self._as_dict(v) == expected
  116. # integers of the paltform-appropriate endianness
  117. code_points = np.frombuffer(v, dtype='i4')
  118. assert_equal(code_points, [ord(c) for c in s])
  119. # Check that we do not allow writeable buffer export
  120. with pytest.raises(BufferError, match="scalar buffer is readonly"):
  121. get_buffer_info(s, ["WRITABLE"])
  122. def test_user_scalar_fails_buffer(self):
  123. r = rational(1)
  124. with assert_raises(TypeError):
  125. memoryview(r)
  126. # Check that we do not allow writeable buffer export
  127. with pytest.raises(BufferError, match="scalar buffer is readonly"):
  128. get_buffer_info(r, ["WRITABLE"])