(root)/
Python-3.11.7/
Lib/
test/
test_memoryview.py
       1  """Unit tests for the memoryview
       2  
       3     Some tests are in test_bytes. Many tests that require _testbuffer.ndarray
       4     are in test_buffer.
       5  """
       6  
       7  import unittest
       8  import test.support
       9  import sys
      10  import gc
      11  import weakref
      12  import array
      13  import io
      14  import copy
      15  import pickle
      16  
      17  from test.support import import_helper
      18  
      19  
      20  class ESC[4;38;5;81mAbstractMemoryTests:
      21      source_bytes = b"abcdef"
      22  
      23      @property
      24      def _source(self):
      25          return self.source_bytes
      26  
      27      @property
      28      def _types(self):
      29          return filter(None, [self.ro_type, self.rw_type])
      30  
      31      def check_getitem_with_type(self, tp):
      32          b = tp(self._source)
      33          oldrefcount = sys.getrefcount(b)
      34          m = self._view(b)
      35          self.assertEqual(m[0], ord(b"a"))
      36          self.assertIsInstance(m[0], int)
      37          self.assertEqual(m[5], ord(b"f"))
      38          self.assertEqual(m[-1], ord(b"f"))
      39          self.assertEqual(m[-6], ord(b"a"))
      40          # Bounds checking
      41          self.assertRaises(IndexError, lambda: m[6])
      42          self.assertRaises(IndexError, lambda: m[-7])
      43          self.assertRaises(IndexError, lambda: m[sys.maxsize])
      44          self.assertRaises(IndexError, lambda: m[-sys.maxsize])
      45          # Type checking
      46          self.assertRaises(TypeError, lambda: m[None])
      47          self.assertRaises(TypeError, lambda: m[0.0])
      48          self.assertRaises(TypeError, lambda: m["a"])
      49          m = None
      50          self.assertEqual(sys.getrefcount(b), oldrefcount)
      51  
      52      def test_getitem(self):
      53          for tp in self._types:
      54              self.check_getitem_with_type(tp)
      55  
      56      def test_iter(self):
      57          for tp in self._types:
      58              b = tp(self._source)
      59              m = self._view(b)
      60              self.assertEqual(list(m), [m[i] for i in range(len(m))])
      61  
      62      def test_setitem_readonly(self):
      63          if not self.ro_type:
      64              self.skipTest("no read-only type to test")
      65          b = self.ro_type(self._source)
      66          oldrefcount = sys.getrefcount(b)
      67          m = self._view(b)
      68          def setitem(value):
      69              m[0] = value
      70          self.assertRaises(TypeError, setitem, b"a")
      71          self.assertRaises(TypeError, setitem, 65)
      72          self.assertRaises(TypeError, setitem, memoryview(b"a"))
      73          m = None
      74          self.assertEqual(sys.getrefcount(b), oldrefcount)
      75  
      76      def test_setitem_writable(self):
      77          if not self.rw_type:
      78              self.skipTest("no writable type to test")
      79          tp = self.rw_type
      80          b = self.rw_type(self._source)
      81          oldrefcount = sys.getrefcount(b)
      82          m = self._view(b)
      83          m[0] = ord(b'1')
      84          self._check_contents(tp, b, b"1bcdef")
      85          m[0:1] = tp(b"0")
      86          self._check_contents(tp, b, b"0bcdef")
      87          m[1:3] = tp(b"12")
      88          self._check_contents(tp, b, b"012def")
      89          m[1:1] = tp(b"")
      90          self._check_contents(tp, b, b"012def")
      91          m[:] = tp(b"abcdef")
      92          self._check_contents(tp, b, b"abcdef")
      93  
      94          # Overlapping copies of a view into itself
      95          m[0:3] = m[2:5]
      96          self._check_contents(tp, b, b"cdedef")
      97          m[:] = tp(b"abcdef")
      98          m[2:5] = m[0:3]
      99          self._check_contents(tp, b, b"ababcf")
     100  
     101          def setitem(key, value):
     102              m[key] = tp(value)
     103          # Bounds checking
     104          self.assertRaises(IndexError, setitem, 6, b"a")
     105          self.assertRaises(IndexError, setitem, -7, b"a")
     106          self.assertRaises(IndexError, setitem, sys.maxsize, b"a")
     107          self.assertRaises(IndexError, setitem, -sys.maxsize, b"a")
     108          # Wrong index/slice types
     109          self.assertRaises(TypeError, setitem, 0.0, b"a")
     110          self.assertRaises(TypeError, setitem, (0,), b"a")
     111          self.assertRaises(TypeError, setitem, (slice(0,1,1), 0), b"a")
     112          self.assertRaises(TypeError, setitem, (0, slice(0,1,1)), b"a")
     113          self.assertRaises(TypeError, setitem, (0,), b"a")
     114          self.assertRaises(TypeError, setitem, "a", b"a")
     115          # Not implemented: multidimensional slices
     116          slices = (slice(0,1,1), slice(0,1,2))
     117          self.assertRaises(NotImplementedError, setitem, slices, b"a")
     118          # Trying to resize the memory object
     119          exc = ValueError if m.format == 'c' else TypeError
     120          self.assertRaises(exc, setitem, 0, b"")
     121          self.assertRaises(exc, setitem, 0, b"ab")
     122          self.assertRaises(ValueError, setitem, slice(1,1), b"a")
     123          self.assertRaises(ValueError, setitem, slice(0,2), b"a")
     124  
     125          m = None
     126          self.assertEqual(sys.getrefcount(b), oldrefcount)
     127  
     128      def test_delitem(self):
     129          for tp in self._types:
     130              b = tp(self._source)
     131              m = self._view(b)
     132              with self.assertRaises(TypeError):
     133                  del m[1]
     134              with self.assertRaises(TypeError):
     135                  del m[1:4]
     136  
     137      def test_tobytes(self):
     138          for tp in self._types:
     139              m = self._view(tp(self._source))
     140              b = m.tobytes()
     141              # This calls self.getitem_type() on each separate byte of b"abcdef"
     142              expected = b"".join(
     143                  self.getitem_type(bytes([c])) for c in b"abcdef")
     144              self.assertEqual(b, expected)
     145              self.assertIsInstance(b, bytes)
     146  
     147      def test_tolist(self):
     148          for tp in self._types:
     149              m = self._view(tp(self._source))
     150              l = m.tolist()
     151              self.assertEqual(l, list(b"abcdef"))
     152  
     153      def test_compare(self):
     154          # memoryviews can compare for equality with other objects
     155          # having the buffer interface.
     156          for tp in self._types:
     157              m = self._view(tp(self._source))
     158              for tp_comp in self._types:
     159                  self.assertTrue(m == tp_comp(b"abcdef"))
     160                  self.assertFalse(m != tp_comp(b"abcdef"))
     161                  self.assertFalse(m == tp_comp(b"abcde"))
     162                  self.assertTrue(m != tp_comp(b"abcde"))
     163                  self.assertFalse(m == tp_comp(b"abcde1"))
     164                  self.assertTrue(m != tp_comp(b"abcde1"))
     165              self.assertTrue(m == m)
     166              self.assertTrue(m == m[:])
     167              self.assertTrue(m[0:6] == m[:])
     168              self.assertFalse(m[0:5] == m)
     169  
     170              # Comparison with objects which don't support the buffer API
     171              self.assertFalse(m == "abcdef")
     172              self.assertTrue(m != "abcdef")
     173              self.assertFalse("abcdef" == m)
     174              self.assertTrue("abcdef" != m)
     175  
     176              # Unordered comparisons
     177              for c in (m, b"abcdef"):
     178                  self.assertRaises(TypeError, lambda: m < c)
     179                  self.assertRaises(TypeError, lambda: c <= m)
     180                  self.assertRaises(TypeError, lambda: m >= c)
     181                  self.assertRaises(TypeError, lambda: c > m)
     182  
     183      def check_attributes_with_type(self, tp):
     184          m = self._view(tp(self._source))
     185          self.assertEqual(m.format, self.format)
     186          self.assertEqual(m.itemsize, self.itemsize)
     187          self.assertEqual(m.ndim, 1)
     188          self.assertEqual(m.shape, (6,))
     189          self.assertEqual(len(m), 6)
     190          self.assertEqual(m.strides, (self.itemsize,))
     191          self.assertEqual(m.suboffsets, ())
     192          return m
     193  
     194      def test_attributes_readonly(self):
     195          if not self.ro_type:
     196              self.skipTest("no read-only type to test")
     197          m = self.check_attributes_with_type(self.ro_type)
     198          self.assertEqual(m.readonly, True)
     199  
     200      def test_attributes_writable(self):
     201          if not self.rw_type:
     202              self.skipTest("no writable type to test")
     203          m = self.check_attributes_with_type(self.rw_type)
     204          self.assertEqual(m.readonly, False)
     205  
     206      def test_getbuffer(self):
     207          # Test PyObject_GetBuffer() on a memoryview object.
     208          for tp in self._types:
     209              b = tp(self._source)
     210              oldrefcount = sys.getrefcount(b)
     211              m = self._view(b)
     212              oldviewrefcount = sys.getrefcount(m)
     213              s = str(m, "utf-8")
     214              self._check_contents(tp, b, s.encode("utf-8"))
     215              self.assertEqual(sys.getrefcount(m), oldviewrefcount)
     216              m = None
     217              self.assertEqual(sys.getrefcount(b), oldrefcount)
     218  
     219      def test_gc(self):
     220          for tp in self._types:
     221              if not isinstance(tp, type):
     222                  # If tp is a factory rather than a plain type, skip
     223                  continue
     224  
     225              class ESC[4;38;5;81mMyView():
     226                  def __init__(self, base):
     227                      self.m = memoryview(base)
     228              class ESC[4;38;5;81mMySource(ESC[4;38;5;149mtp):
     229                  pass
     230              class ESC[4;38;5;81mMyObject:
     231                  pass
     232  
     233              # Create a reference cycle through a memoryview object.
     234              # This exercises mbuf_clear().
     235              b = MySource(tp(b'abc'))
     236              m = self._view(b)
     237              o = MyObject()
     238              b.m = m
     239              b.o = o
     240              wr = weakref.ref(o)
     241              b = m = o = None
     242              # The cycle must be broken
     243              gc.collect()
     244              self.assertTrue(wr() is None, wr())
     245  
     246              # This exercises memory_clear().
     247              m = MyView(tp(b'abc'))
     248              o = MyObject()
     249              m.x = m
     250              m.o = o
     251              wr = weakref.ref(o)
     252              m = o = None
     253              # The cycle must be broken
     254              gc.collect()
     255              self.assertTrue(wr() is None, wr())
     256  
     257      def _check_released(self, m, tp):
     258          check = self.assertRaisesRegex(ValueError, "released")
     259          with check: bytes(m)
     260          with check: m.tobytes()
     261          with check: m.tolist()
     262          with check: m[0]
     263          with check: m[0] = b'x'
     264          with check: len(m)
     265          with check: m.format
     266          with check: m.itemsize
     267          with check: m.ndim
     268          with check: m.readonly
     269          with check: m.shape
     270          with check: m.strides
     271          with check:
     272              with m:
     273                  pass
     274          # str() and repr() still function
     275          self.assertIn("released memory", str(m))
     276          self.assertIn("released memory", repr(m))
     277          self.assertEqual(m, m)
     278          self.assertNotEqual(m, memoryview(tp(self._source)))
     279          self.assertNotEqual(m, tp(self._source))
     280  
     281      def test_contextmanager(self):
     282          for tp in self._types:
     283              b = tp(self._source)
     284              m = self._view(b)
     285              with m as cm:
     286                  self.assertIs(cm, m)
     287              self._check_released(m, tp)
     288              m = self._view(b)
     289              # Can release explicitly inside the context manager
     290              with m:
     291                  m.release()
     292  
     293      def test_release(self):
     294          for tp in self._types:
     295              b = tp(self._source)
     296              m = self._view(b)
     297              m.release()
     298              self._check_released(m, tp)
     299              # Can be called a second time (it's a no-op)
     300              m.release()
     301              self._check_released(m, tp)
     302  
     303      def test_writable_readonly(self):
     304          # Issue #10451: memoryview incorrectly exposes a readonly
     305          # buffer as writable causing a segfault if using mmap
     306          tp = self.ro_type
     307          if tp is None:
     308              self.skipTest("no read-only type to test")
     309          b = tp(self._source)
     310          m = self._view(b)
     311          i = io.BytesIO(b'ZZZZ')
     312          self.assertRaises(TypeError, i.readinto, m)
     313  
     314      def test_getbuf_fail(self):
     315          self.assertRaises(TypeError, self._view, {})
     316  
     317      def test_hash(self):
     318          # Memoryviews of readonly (hashable) types are hashable, and they
     319          # hash as hash(obj.tobytes()).
     320          tp = self.ro_type
     321          if tp is None:
     322              self.skipTest("no read-only type to test")
     323          b = tp(self._source)
     324          m = self._view(b)
     325          self.assertEqual(hash(m), hash(b"abcdef"))
     326          # Releasing the memoryview keeps the stored hash value (as with weakrefs)
     327          m.release()
     328          self.assertEqual(hash(m), hash(b"abcdef"))
     329          # Hashing a memoryview for the first time after it is released
     330          # results in an error (as with weakrefs).
     331          m = self._view(b)
     332          m.release()
     333          self.assertRaises(ValueError, hash, m)
     334  
     335      def test_hash_writable(self):
     336          # Memoryviews of writable types are unhashable
     337          tp = self.rw_type
     338          if tp is None:
     339              self.skipTest("no writable type to test")
     340          b = tp(self._source)
     341          m = self._view(b)
     342          self.assertRaises(ValueError, hash, m)
     343  
     344      def test_weakref(self):
     345          # Check memoryviews are weakrefable
     346          for tp in self._types:
     347              b = tp(self._source)
     348              m = self._view(b)
     349              L = []
     350              def callback(wr, b=b):
     351                  L.append(b)
     352              wr = weakref.ref(m, callback)
     353              self.assertIs(wr(), m)
     354              del m
     355              test.support.gc_collect()
     356              self.assertIs(wr(), None)
     357              self.assertIs(L[0], b)
     358  
     359      def test_reversed(self):
     360          for tp in self._types:
     361              b = tp(self._source)
     362              m = self._view(b)
     363              aslist = list(reversed(m.tolist()))
     364              self.assertEqual(list(reversed(m)), aslist)
     365              self.assertEqual(list(reversed(m)), list(m[::-1]))
     366  
     367      def test_toreadonly(self):
     368          for tp in self._types:
     369              b = tp(self._source)
     370              m = self._view(b)
     371              mm = m.toreadonly()
     372              self.assertTrue(mm.readonly)
     373              self.assertTrue(memoryview(mm).readonly)
     374              self.assertEqual(mm.tolist(), m.tolist())
     375              mm.release()
     376              m.tolist()
     377  
     378      def test_issue22668(self):
     379          a = array.array('H', [256, 256, 256, 256])
     380          x = memoryview(a)
     381          m = x.cast('B')
     382          b = m.cast('H')
     383          c = b[0:2]
     384          d = memoryview(b)
     385  
     386          del b
     387  
     388          self.assertEqual(c[0], 256)
     389          self.assertEqual(d[0], 256)
     390          self.assertEqual(c.format, "H")
     391          self.assertEqual(d.format, "H")
     392  
     393          _ = m.cast('I')
     394          self.assertEqual(c[0], 256)
     395          self.assertEqual(d[0], 256)
     396          self.assertEqual(c.format, "H")
     397          self.assertEqual(d.format, "H")
     398  
     399  
     400  # Variations on source objects for the buffer: bytes-like objects, then arrays
     401  # with itemsize > 1.
     402  # NOTE: support for multi-dimensional objects is unimplemented.
     403  
     404  class ESC[4;38;5;81mBaseBytesMemoryTests(ESC[4;38;5;149mAbstractMemoryTests):
     405      ro_type = bytes
     406      rw_type = bytearray
     407      getitem_type = bytes
     408      itemsize = 1
     409      format = 'B'
     410  
     411  class ESC[4;38;5;81mBaseArrayMemoryTests(ESC[4;38;5;149mAbstractMemoryTests):
     412      ro_type = None
     413      rw_type = lambda self, b: array.array('i', list(b))
     414      getitem_type = lambda self, b: array.array('i', list(b)).tobytes()
     415      itemsize = array.array('i').itemsize
     416      format = 'i'
     417  
     418      @unittest.skip('XXX test should be adapted for non-byte buffers')
     419      def test_getbuffer(self):
     420          pass
     421  
     422      @unittest.skip('XXX NotImplementedError: tolist() only supports byte views')
     423      def test_tolist(self):
     424          pass
     425  
     426  
     427  # Variations on indirection levels: memoryview, slice of memoryview,
     428  # slice of slice of memoryview.
     429  # This is important to test allocation subtleties.
     430  
     431  class ESC[4;38;5;81mBaseMemoryviewTests:
     432      def _view(self, obj):
     433          return memoryview(obj)
     434  
     435      def _check_contents(self, tp, obj, contents):
     436          self.assertEqual(obj, tp(contents))
     437  
     438  class ESC[4;38;5;81mBaseMemorySliceTests:
     439      source_bytes = b"XabcdefY"
     440  
     441      def _view(self, obj):
     442          m = memoryview(obj)
     443          return m[1:7]
     444  
     445      def _check_contents(self, tp, obj, contents):
     446          self.assertEqual(obj[1:7], tp(contents))
     447  
     448      def test_refs(self):
     449          for tp in self._types:
     450              m = memoryview(tp(self._source))
     451              oldrefcount = sys.getrefcount(m)
     452              m[1:2]
     453              self.assertEqual(sys.getrefcount(m), oldrefcount)
     454  
     455  class ESC[4;38;5;81mBaseMemorySliceSliceTests:
     456      source_bytes = b"XabcdefY"
     457  
     458      def _view(self, obj):
     459          m = memoryview(obj)
     460          return m[:7][1:]
     461  
     462      def _check_contents(self, tp, obj, contents):
     463          self.assertEqual(obj[1:7], tp(contents))
     464  
     465  
     466  # Concrete test classes
     467  
     468  class ESC[4;38;5;81mBytesMemoryviewTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase,
     469      ESC[4;38;5;149mBaseMemoryviewTests, ESC[4;38;5;149mBaseBytesMemoryTests):
     470  
     471      def test_constructor(self):
     472          for tp in self._types:
     473              ob = tp(self._source)
     474              self.assertTrue(memoryview(ob))
     475              self.assertTrue(memoryview(object=ob))
     476              self.assertRaises(TypeError, memoryview)
     477              self.assertRaises(TypeError, memoryview, ob, ob)
     478              self.assertRaises(TypeError, memoryview, argument=ob)
     479              self.assertRaises(TypeError, memoryview, ob, argument=True)
     480  
     481  class ESC[4;38;5;81mArrayMemoryviewTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase,
     482      ESC[4;38;5;149mBaseMemoryviewTests, ESC[4;38;5;149mBaseArrayMemoryTests):
     483  
     484      def test_array_assign(self):
     485          # Issue #4569: segfault when mutating a memoryview with itemsize != 1
     486          a = array.array('i', range(10))
     487          m = memoryview(a)
     488          new_a = array.array('i', range(9, -1, -1))
     489          m[:] = new_a
     490          self.assertEqual(a, new_a)
     491  
     492  
     493  class ESC[4;38;5;81mBytesMemorySliceTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase,
     494      ESC[4;38;5;149mBaseMemorySliceTests, ESC[4;38;5;149mBaseBytesMemoryTests):
     495      pass
     496  
     497  class ESC[4;38;5;81mArrayMemorySliceTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase,
     498      ESC[4;38;5;149mBaseMemorySliceTests, ESC[4;38;5;149mBaseArrayMemoryTests):
     499      pass
     500  
     501  class ESC[4;38;5;81mBytesMemorySliceSliceTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase,
     502      ESC[4;38;5;149mBaseMemorySliceSliceTests, ESC[4;38;5;149mBaseBytesMemoryTests):
     503      pass
     504  
     505  class ESC[4;38;5;81mArrayMemorySliceSliceTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase,
     506      ESC[4;38;5;149mBaseMemorySliceSliceTests, ESC[4;38;5;149mBaseArrayMemoryTests):
     507      pass
     508  
     509  
     510  class ESC[4;38;5;81mOtherTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     511      def test_ctypes_cast(self):
     512          # Issue 15944: Allow all source formats when casting to bytes.
     513          ctypes = import_helper.import_module("ctypes")
     514          p6 = bytes(ctypes.c_double(0.6))
     515  
     516          d = ctypes.c_double()
     517          m = memoryview(d).cast("B")
     518          m[:2] = p6[:2]
     519          m[2:] = p6[2:]
     520          self.assertEqual(d.value, 0.6)
     521  
     522          for format in "Bbc":
     523              with self.subTest(format):
     524                  d = ctypes.c_double()
     525                  m = memoryview(d).cast(format)
     526                  m[:2] = memoryview(p6).cast(format)[:2]
     527                  m[2:] = memoryview(p6).cast(format)[2:]
     528                  self.assertEqual(d.value, 0.6)
     529  
     530      def test_memoryview_hex(self):
     531          # Issue #9951: memoryview.hex() segfaults with non-contiguous buffers.
     532          x = b'0' * 200000
     533          m1 = memoryview(x)
     534          m2 = m1[::-1]
     535          self.assertEqual(m2.hex(), '30' * 200000)
     536  
     537      def test_copy(self):
     538          m = memoryview(b'abc')
     539          with self.assertRaises(TypeError):
     540              copy.copy(m)
     541  
     542      def test_pickle(self):
     543          m = memoryview(b'abc')
     544          for proto in range(pickle.HIGHEST_PROTOCOL + 1):
     545              with self.assertRaises(TypeError):
     546                  pickle.dumps(m, proto)
     547  
     548      def test_use_released_memory(self):
     549          # gh-92888: Previously it was possible to use a memoryview even after
     550          # backing buffer is freed in certain cases. This tests that those
     551          # cases raise an exception.
     552          size = 128
     553          def release():
     554              m.release()
     555              nonlocal ba
     556              ba = bytearray(size)
     557          class ESC[4;38;5;81mMyIndex:
     558              def __index__(self):
     559                  release()
     560                  return 4
     561          class ESC[4;38;5;81mMyFloat:
     562              def __float__(self):
     563                  release()
     564                  return 4.25
     565          class ESC[4;38;5;81mMyBool:
     566              def __bool__(self):
     567                  release()
     568                  return True
     569  
     570          ba = None
     571          m = memoryview(bytearray(b'\xff'*size))
     572          with self.assertRaises(ValueError):
     573              m[MyIndex()]
     574  
     575          ba = None
     576          m = memoryview(bytearray(b'\xff'*size))
     577          self.assertEqual(list(m[:MyIndex()]), [255] * 4)
     578  
     579          ba = None
     580          m = memoryview(bytearray(b'\xff'*size))
     581          self.assertEqual(list(m[MyIndex():8]), [255] * 4)
     582  
     583          ba = None
     584          m = memoryview(bytearray(b'\xff'*size)).cast('B', (64, 2))
     585          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     586              m[MyIndex(), 0]
     587  
     588          ba = None
     589          m = memoryview(bytearray(b'\xff'*size)).cast('B', (2, 64))
     590          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     591              m[0, MyIndex()]
     592  
     593          ba = None
     594          m = memoryview(bytearray(b'\xff'*size))
     595          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     596              m[MyIndex()] = 42
     597          self.assertEqual(ba[:8], b'\0'*8)
     598  
     599          ba = None
     600          m = memoryview(bytearray(b'\xff'*size))
     601          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     602              m[:MyIndex()] = b'spam'
     603          self.assertEqual(ba[:8], b'\0'*8)
     604  
     605          ba = None
     606          m = memoryview(bytearray(b'\xff'*size))
     607          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     608              m[MyIndex():8] = b'spam'
     609          self.assertEqual(ba[:8], b'\0'*8)
     610  
     611          ba = None
     612          m = memoryview(bytearray(b'\xff'*size)).cast('B', (64, 2))
     613          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     614              m[MyIndex(), 0] = 42
     615          self.assertEqual(ba[8:16], b'\0'*8)
     616          ba = None
     617          m = memoryview(bytearray(b'\xff'*size)).cast('B', (2, 64))
     618          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     619              m[0, MyIndex()] = 42
     620          self.assertEqual(ba[:8], b'\0'*8)
     621  
     622          ba = None
     623          m = memoryview(bytearray(b'\xff'*size))
     624          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     625              m[0] = MyIndex()
     626          self.assertEqual(ba[:8], b'\0'*8)
     627  
     628          for fmt in 'bhilqnBHILQN':
     629              with self.subTest(fmt=fmt):
     630                  ba = None
     631                  m = memoryview(bytearray(b'\xff'*size)).cast(fmt)
     632                  with self.assertRaisesRegex(ValueError, "operation forbidden"):
     633                      m[0] = MyIndex()
     634                  self.assertEqual(ba[:8], b'\0'*8)
     635  
     636          for fmt in 'fd':
     637              with self.subTest(fmt=fmt):
     638                  ba = None
     639                  m = memoryview(bytearray(b'\xff'*size)).cast(fmt)
     640                  with self.assertRaisesRegex(ValueError, "operation forbidden"):
     641                      m[0] = MyFloat()
     642                  self.assertEqual(ba[:8], b'\0'*8)
     643  
     644          ba = None
     645          m = memoryview(bytearray(b'\xff'*size)).cast('?')
     646          with self.assertRaisesRegex(ValueError, "operation forbidden"):
     647              m[0] = MyBool()
     648          self.assertEqual(ba[:8], b'\0'*8)
     649  
     650  if __name__ == "__main__":
     651      unittest.main()