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