mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Update test_buffer.py
This commit is contained in:
1 parent
897bbe1b48
commit
d923f84687
1 file changed
+423
-21
Vendored
+423
-21
@@ -17,12 +17,14 @@ import contextlib
|
||||
import unittest
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
import inspect
|
||||
from itertools import permutations, product
|
||||
from random import randrange, sample, choice
|
||||
import warnings
|
||||
import sys, array, io, os
|
||||
from decimal import Decimal
|
||||
from fractions import Fraction
|
||||
from test.support import warnings_helper
|
||||
|
||||
try:
|
||||
from _testbuffer import *
|
||||
@@ -64,7 +66,7 @@ NATIVE = {
|
||||
'?':0, 'c':0, 'b':0, 'B':0,
|
||||
'h':0, 'H':0, 'i':0, 'I':0,
|
||||
'l':0, 'L':0, 'n':0, 'N':0,
|
||||
'f':0, 'd':0, 'P':0
|
||||
'e':0, 'f':0, 'd':0, 'P':0
|
||||
}
|
||||
|
||||
# NumPy does not have 'n' or 'N':
|
||||
@@ -89,7 +91,8 @@ STANDARD = {
|
||||
'i':(-(1<<31), 1<<31), 'I':(0, 1<<32),
|
||||
'l':(-(1<<31), 1<<31), 'L':(0, 1<<32),
|
||||
'q':(-(1<<63), 1<<63), 'Q':(0, 1<<64),
|
||||
'f':(-(1<<63), 1<<63), 'd':(-(1<<1023), 1<<1023)
|
||||
'e':(-65519, 65520), 'f':(-(1<<63), 1<<63),
|
||||
'd':(-(1<<1023), 1<<1023)
|
||||
}
|
||||
|
||||
def native_type_range(fmt):
|
||||
@@ -98,6 +101,8 @@ def native_type_range(fmt):
|
||||
lh = (0, 256)
|
||||
elif fmt == '?':
|
||||
lh = (0, 2)
|
||||
elif fmt == 'e':
|
||||
lh = (-65519, 65520)
|
||||
elif fmt == 'f':
|
||||
lh = (-(1<<63), 1<<63)
|
||||
elif fmt == 'd':
|
||||
@@ -125,7 +130,10 @@ if struct:
|
||||
for fmt in fmtdict['@']:
|
||||
fmtdict['@'][fmt] = native_type_range(fmt)
|
||||
|
||||
# Format codes supported by the memoryview object
|
||||
MEMORYVIEW = NATIVE.copy()
|
||||
|
||||
# Format codes supported by array.array
|
||||
ARRAY = NATIVE.copy()
|
||||
for k in NATIVE:
|
||||
if not k in "bBhHiIlLfd":
|
||||
@@ -160,11 +168,11 @@ def randrange_fmt(mode, char, obj):
|
||||
if char == 'c':
|
||||
x = bytes([x])
|
||||
if obj == 'numpy' and x == b'\x00':
|
||||
# http://projects.scipy.org/numpy/ticket/1925
|
||||
# https://github.com/numpy/numpy/issues/2518
|
||||
x = b'\x01'
|
||||
if char == '?':
|
||||
x = bool(x)
|
||||
if char == 'f' or char == 'd':
|
||||
if char in 'efd':
|
||||
x = struct.pack(char, x)
|
||||
x = struct.unpack(char, x)[0]
|
||||
return x
|
||||
@@ -959,8 +967,10 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
self.assertEqual(m.strides, tuple(strides))
|
||||
self.assertEqual(m.suboffsets, tuple(suboffsets))
|
||||
|
||||
n = 1 if ndim == 0 else len(lst)
|
||||
self.assertEqual(len(m), n)
|
||||
if ndim == 0:
|
||||
self.assertRaises(TypeError, len, m)
|
||||
else:
|
||||
self.assertEqual(len(m), len(lst))
|
||||
|
||||
rep = result.tolist() if fmt else result.tobytes()
|
||||
self.assertEqual(rep, lst)
|
||||
@@ -1019,6 +1029,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
ndim=ndim, shape=shape, strides=strides,
|
||||
lst=lst, sliced=sliced)
|
||||
|
||||
@support.requires_resource('cpu')
|
||||
def test_ndarray_getbuf(self):
|
||||
requests = (
|
||||
# distinct flags
|
||||
@@ -1907,7 +1918,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
if numpy_array:
|
||||
shape = t[3]
|
||||
if 0 in shape:
|
||||
continue # http://projects.scipy.org/numpy/ticket/1910
|
||||
continue # https://github.com/numpy/numpy/issues/2503
|
||||
z = numpy_array_from_structure(items, fmt, t)
|
||||
self.verify(x, obj=None,
|
||||
itemsize=z.itemsize, fmt=fmt, readonly=False,
|
||||
@@ -1939,7 +1950,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
except Exception as e:
|
||||
numpy_err = e.__class__
|
||||
|
||||
if 0: # http://projects.scipy.org/numpy/ticket/1910
|
||||
if 0: # https://github.com/numpy/numpy/issues/2503
|
||||
self.assertTrue(numpy_err)
|
||||
|
||||
def test_ndarray_random_slice_assign(self):
|
||||
@@ -1985,7 +1996,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
|
||||
if numpy_array:
|
||||
if 0 in lshape or 0 in rshape:
|
||||
continue # http://projects.scipy.org/numpy/ticket/1910
|
||||
continue # https://github.com/numpy/numpy/issues/2503
|
||||
|
||||
zl = numpy_array_from_structure(litems, fmt, tl)
|
||||
zr = numpy_array_from_structure(ritems, fmt, tr)
|
||||
@@ -2246,7 +2257,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
###
|
||||
### Fortran output:
|
||||
### ---------------
|
||||
### >>> fortran_buf = nd.tostring(order='F')
|
||||
### >>> fortran_buf = nd.tobytes(order='F')
|
||||
### >>> fortran_buf
|
||||
### b'\x00\x04\x08\x01\x05\t\x02\x06\n\x03\x07\x0b'
|
||||
###
|
||||
@@ -2289,7 +2300,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
self.assertEqual(memoryview(y), memoryview(nd))
|
||||
|
||||
if numpy_array:
|
||||
self.assertEqual(b, na.tostring(order='C'))
|
||||
self.assertEqual(b, na.tobytes(order='C'))
|
||||
|
||||
# 'F' request
|
||||
if f == 0: # 'C' to 'F'
|
||||
@@ -2312,7 +2323,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
self.assertEqual(memoryview(y), memoryview(nd))
|
||||
|
||||
if numpy_array:
|
||||
self.assertEqual(b, na.tostring(order='F'))
|
||||
self.assertEqual(b, na.tobytes(order='F'))
|
||||
|
||||
# 'A' request
|
||||
if f == ND_FORTRAN:
|
||||
@@ -2336,7 +2347,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
self.assertEqual(memoryview(y), memoryview(nd))
|
||||
|
||||
if numpy_array:
|
||||
self.assertEqual(b, na.tostring(order='A'))
|
||||
self.assertEqual(b, na.tobytes(order='A'))
|
||||
|
||||
# multi-dimensional, non-contiguous input
|
||||
nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE|ND_PIL)
|
||||
@@ -2750,6 +2761,7 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
m = memoryview(ex)
|
||||
iter_roundtrip(ex, m, items, fmt)
|
||||
|
||||
@support.requires_resource('cpu')
|
||||
def test_memoryview_cast_1D_ND(self):
|
||||
# Cast between C-contiguous buffers. At least one buffer must
|
||||
# be 1D, at least one format must be 'c', 'b' or 'B'.
|
||||
@@ -2867,11 +2879,11 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
def test_memoryview_repr(self):
|
||||
m = memoryview(bytearray(9))
|
||||
r = m.__repr__()
|
||||
self.assertTrue(r.startswith("<memory"))
|
||||
self.assertStartsWith(r, "<memory")
|
||||
|
||||
m.release()
|
||||
r = m.__repr__()
|
||||
self.assertTrue(r.startswith("<released"))
|
||||
self.assertStartsWith(r, "<released")
|
||||
|
||||
def test_memoryview_sequence(self):
|
||||
|
||||
@@ -3208,12 +3220,6 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
nd[0] = (-1, float('nan'))
|
||||
self.assertNotEqual(memoryview(nd), nd)
|
||||
|
||||
# Depends on issue #15625: the struct module does not understand 'u'.
|
||||
a = array.array('u', 'xyz')
|
||||
v = memoryview(a)
|
||||
self.assertNotEqual(a, v)
|
||||
self.assertNotEqual(v, a)
|
||||
|
||||
# Some ctypes format strings are unknown to the struct module.
|
||||
if ctypes:
|
||||
# format: "T{>l:x:>l:y:}"
|
||||
@@ -3227,6 +3233,15 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
self.assertNotEqual(point, a)
|
||||
self.assertRaises(NotImplementedError, a.tolist)
|
||||
|
||||
@warnings_helper.ignore_warnings(category=DeprecationWarning) # gh-80480 array('u')
|
||||
def test_memoryview_compare_special_cases_deprecated_u_type_code(self):
|
||||
|
||||
# Depends on issue #15625: the struct module does not understand 'u'.
|
||||
a = array.array('u', 'xyz')
|
||||
v = memoryview(a)
|
||||
self.assertNotEqual(a, v)
|
||||
self.assertNotEqual(v, a)
|
||||
|
||||
def test_memoryview_compare_ndim_zero(self):
|
||||
|
||||
nd1 = ndarray(1729, shape=[], format='@L')
|
||||
@@ -3895,6 +3910,8 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
self.assertRaises(ValueError, memoryview, m)
|
||||
# memoryview.cast()
|
||||
self.assertRaises(ValueError, m.cast, 'c')
|
||||
# memoryview.__iter__()
|
||||
self.assertRaises(ValueError, m.__iter__)
|
||||
# getbuffer()
|
||||
self.assertRaises(ValueError, ndarray, m)
|
||||
# memoryview.tolist()
|
||||
@@ -4422,6 +4439,14 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL)
|
||||
self.assertRaises(BufferError, memoryview, x)
|
||||
|
||||
def test_bytearray_release_buffer_read_flag(self):
|
||||
# See https://github.com/python/cpython/issues/126980
|
||||
obj = bytearray(b'abc')
|
||||
with self.assertRaises(SystemError):
|
||||
obj.__buffer__(inspect.BufferFlags.READ)
|
||||
with self.assertRaises(SystemError):
|
||||
obj.__buffer__(inspect.BufferFlags.WRITE)
|
||||
|
||||
@support.cpython_only
|
||||
def test_pybuffer_size_from_format(self):
|
||||
# basic tests
|
||||
@@ -4429,6 +4454,383 @@ class TestBufferProtocol(unittest.TestCase):
|
||||
self.assertEqual(_testcapi.PyBuffer_SizeFromFormat(format),
|
||||
struct.calcsize(format))
|
||||
|
||||
@support.cpython_only
|
||||
def test_flags_overflow(self):
|
||||
# gh-126594: Check for integer overlow on large flags
|
||||
try:
|
||||
from _testcapi import INT_MIN, INT_MAX
|
||||
except ImportError:
|
||||
INT_MIN = -(2 ** 31)
|
||||
INT_MAX = 2 ** 31 - 1
|
||||
|
||||
obj = b'abc'
|
||||
for flags in (INT_MIN - 1, INT_MAX + 1):
|
||||
with self.subTest(flags=flags):
|
||||
with self.assertRaises(OverflowError):
|
||||
obj.__buffer__(flags)
|
||||
|
||||
|
||||
class TestPythonBufferProtocol(unittest.TestCase):
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_basic(self):
|
||||
class MyBuffer:
|
||||
def __buffer__(self, flags):
|
||||
return memoryview(b"hello")
|
||||
|
||||
mv = memoryview(MyBuffer())
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
self.assertEqual(bytes(MyBuffer()), b"hello")
|
||||
|
||||
def test_bad_buffer_method(self):
|
||||
class MustReturnMV:
|
||||
def __buffer__(self, flags):
|
||||
return 42
|
||||
|
||||
self.assertRaises(TypeError, memoryview, MustReturnMV())
|
||||
|
||||
class NoBytesEither:
|
||||
def __buffer__(self, flags):
|
||||
return b"hello"
|
||||
|
||||
self.assertRaises(TypeError, memoryview, NoBytesEither())
|
||||
|
||||
class WrongArity:
|
||||
def __buffer__(self):
|
||||
return memoryview(b"hello")
|
||||
|
||||
self.assertRaises(TypeError, memoryview, WrongArity())
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_release_buffer(self):
|
||||
class WhatToRelease:
|
||||
def __init__(self):
|
||||
self.held = False
|
||||
self.ba = bytearray(b"hello")
|
||||
|
||||
def __buffer__(self, flags):
|
||||
if self.held:
|
||||
raise TypeError("already held")
|
||||
self.held = True
|
||||
return memoryview(self.ba)
|
||||
|
||||
def __release_buffer__(self, buffer):
|
||||
self.held = False
|
||||
|
||||
wr = WhatToRelease()
|
||||
self.assertFalse(wr.held)
|
||||
with memoryview(wr) as mv:
|
||||
self.assertTrue(wr.held)
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
self.assertFalse(wr.held)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_same_buffer_returned(self):
|
||||
class WhatToRelease:
|
||||
def __init__(self):
|
||||
self.held = False
|
||||
self.ba = bytearray(b"hello")
|
||||
self.created_mv = None
|
||||
|
||||
def __buffer__(self, flags):
|
||||
if self.held:
|
||||
raise TypeError("already held")
|
||||
self.held = True
|
||||
self.created_mv = memoryview(self.ba)
|
||||
return self.created_mv
|
||||
|
||||
def __release_buffer__(self, buffer):
|
||||
assert buffer is self.created_mv
|
||||
self.held = False
|
||||
|
||||
wr = WhatToRelease()
|
||||
self.assertFalse(wr.held)
|
||||
with memoryview(wr) as mv:
|
||||
self.assertTrue(wr.held)
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
self.assertFalse(wr.held)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_buffer_flags(self):
|
||||
class PossiblyMutable:
|
||||
def __init__(self, data, mutable) -> None:
|
||||
self._data = bytearray(data)
|
||||
self._mutable = mutable
|
||||
|
||||
def __buffer__(self, flags):
|
||||
if flags & inspect.BufferFlags.WRITABLE:
|
||||
if not self._mutable:
|
||||
raise RuntimeError("not mutable")
|
||||
return memoryview(self._data)
|
||||
else:
|
||||
return memoryview(bytes(self._data))
|
||||
|
||||
mutable = PossiblyMutable(b"hello", True)
|
||||
immutable = PossiblyMutable(b"hello", False)
|
||||
with memoryview._from_flags(mutable, inspect.BufferFlags.WRITABLE) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
mv[0] = ord(b'x')
|
||||
self.assertEqual(mv.tobytes(), b"xello")
|
||||
with memoryview._from_flags(mutable, inspect.BufferFlags.SIMPLE) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"xello")
|
||||
with self.assertRaises(TypeError):
|
||||
mv[0] = ord(b'h')
|
||||
self.assertEqual(mv.tobytes(), b"xello")
|
||||
with memoryview._from_flags(immutable, inspect.BufferFlags.SIMPLE) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
with self.assertRaises(TypeError):
|
||||
mv[0] = ord(b'x')
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
memoryview._from_flags(immutable, inspect.BufferFlags.WRITABLE)
|
||||
with memoryview(immutable) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
with self.assertRaises(TypeError):
|
||||
mv[0] = ord(b'x')
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_call_builtins(self):
|
||||
ba = bytearray(b"hello")
|
||||
mv = ba.__buffer__(0)
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
ba.__release_buffer__(mv)
|
||||
with self.assertRaises(OverflowError):
|
||||
ba.__buffer__(sys.maxsize + 1)
|
||||
|
||||
@unittest.skipIf(_testcapi is None, "requires _testcapi")
|
||||
def test_c_buffer(self):
|
||||
buf = _testcapi.testBuf()
|
||||
self.assertEqual(buf.references, 0)
|
||||
mv = buf.__buffer__(0)
|
||||
self.assertIsInstance(mv, memoryview)
|
||||
self.assertEqual(mv.tobytes(), b"test")
|
||||
self.assertEqual(buf.references, 1)
|
||||
buf.__release_buffer__(mv)
|
||||
self.assertEqual(buf.references, 0)
|
||||
with self.assertRaises(ValueError):
|
||||
mv.tobytes()
|
||||
# Calling it again doesn't cause issues
|
||||
with self.assertRaises(ValueError):
|
||||
buf.__release_buffer__(mv)
|
||||
self.assertEqual(buf.references, 0)
|
||||
|
||||
@unittest.skipIf(_testcapi is None, "requires _testcapi")
|
||||
def test_c_buffer_invalid_flags(self):
|
||||
buf = _testcapi.testBuf()
|
||||
self.assertRaises(SystemError, buf.__buffer__, PyBUF_READ)
|
||||
self.assertRaises(SystemError, buf.__buffer__, PyBUF_WRITE)
|
||||
|
||||
@unittest.skipIf(_testcapi is None, "requires _testcapi")
|
||||
def test_c_fill_buffer_invalid_flags(self):
|
||||
# PyBuffer_FillInfo
|
||||
source = b"abc"
|
||||
self.assertRaises(SystemError, _testcapi.buffer_fill_info,
|
||||
source, 0, PyBUF_READ)
|
||||
self.assertRaises(SystemError, _testcapi.buffer_fill_info,
|
||||
source, 0, PyBUF_WRITE)
|
||||
|
||||
@unittest.skipIf(_testcapi is None, "requires _testcapi")
|
||||
def test_c_fill_buffer_readonly_and_writable(self):
|
||||
source = b"abc"
|
||||
with _testcapi.buffer_fill_info(source, 1, PyBUF_SIMPLE) as m:
|
||||
self.assertEqual(bytes(m), b"abc")
|
||||
self.assertTrue(m.readonly)
|
||||
with _testcapi.buffer_fill_info(source, 0, PyBUF_WRITABLE) as m:
|
||||
self.assertEqual(bytes(m), b"abc")
|
||||
self.assertFalse(m.readonly)
|
||||
self.assertRaises(BufferError, _testcapi.buffer_fill_info,
|
||||
source, 1, PyBUF_WRITABLE)
|
||||
|
||||
def test_inheritance(self):
|
||||
class A(bytearray):
|
||||
def __buffer__(self, flags):
|
||||
return super().__buffer__(flags)
|
||||
|
||||
a = A(b"hello")
|
||||
mv = memoryview(a)
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_inheritance_releasebuffer(self):
|
||||
rb_call_count = 0
|
||||
class B(bytearray):
|
||||
def __buffer__(self, flags):
|
||||
return super().__buffer__(flags)
|
||||
def __release_buffer__(self, view):
|
||||
nonlocal rb_call_count
|
||||
rb_call_count += 1
|
||||
super().__release_buffer__(view)
|
||||
|
||||
b = B(b"hello")
|
||||
with memoryview(b) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
self.assertEqual(rb_call_count, 0)
|
||||
self.assertEqual(rb_call_count, 1)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_inherit_but_return_something_else(self):
|
||||
class A(bytearray):
|
||||
def __buffer__(self, flags):
|
||||
return memoryview(b"hello")
|
||||
|
||||
a = A(b"hello")
|
||||
with memoryview(a) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
|
||||
rb_call_count = 0
|
||||
rb_raised = False
|
||||
class B(bytearray):
|
||||
def __buffer__(self, flags):
|
||||
return memoryview(b"hello")
|
||||
def __release_buffer__(self, view):
|
||||
nonlocal rb_call_count
|
||||
rb_call_count += 1
|
||||
try:
|
||||
super().__release_buffer__(view)
|
||||
except ValueError:
|
||||
nonlocal rb_raised
|
||||
rb_raised = True
|
||||
|
||||
b = B(b"hello")
|
||||
with memoryview(b) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
self.assertEqual(rb_call_count, 0)
|
||||
self.assertEqual(rb_call_count, 1)
|
||||
self.assertIs(rb_raised, True)
|
||||
|
||||
def test_override_only_release(self):
|
||||
class C(bytearray):
|
||||
def __release_buffer__(self, buffer):
|
||||
super().__release_buffer__(buffer)
|
||||
|
||||
c = C(b"hello")
|
||||
with memoryview(c) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_release_saves_reference(self):
|
||||
smuggled_buffer = None
|
||||
|
||||
class C(bytearray):
|
||||
def __release_buffer__(s, buffer: memoryview):
|
||||
with self.assertRaises(ValueError):
|
||||
memoryview(buffer)
|
||||
with self.assertRaises(ValueError):
|
||||
buffer.cast("b")
|
||||
with self.assertRaises(ValueError):
|
||||
buffer.toreadonly()
|
||||
with self.assertRaises(ValueError):
|
||||
buffer[:1]
|
||||
with self.assertRaises(ValueError):
|
||||
buffer.__buffer__(0)
|
||||
nonlocal smuggled_buffer
|
||||
smuggled_buffer = buffer
|
||||
self.assertEqual(buffer.tobytes(), b"hello")
|
||||
super().__release_buffer__(buffer)
|
||||
|
||||
c = C(b"hello")
|
||||
with memoryview(c) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
c.clear()
|
||||
with self.assertRaises(ValueError):
|
||||
smuggled_buffer.tobytes()
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_release_saves_reference_no_subclassing(self):
|
||||
ba = bytearray(b"hello")
|
||||
|
||||
class C:
|
||||
def __buffer__(self, flags):
|
||||
return memoryview(ba)
|
||||
|
||||
def __release_buffer__(self, buffer):
|
||||
self.buffer = buffer
|
||||
|
||||
c = C()
|
||||
with memoryview(c) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
self.assertEqual(c.buffer.tobytes(), b"hello")
|
||||
|
||||
with self.assertRaises(BufferError):
|
||||
ba.clear()
|
||||
c.buffer.release()
|
||||
ba.clear()
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_multiple_inheritance_buffer_last(self):
|
||||
class A:
|
||||
def __buffer__(self, flags):
|
||||
return memoryview(b"hello A")
|
||||
|
||||
class B(A, bytearray):
|
||||
def __buffer__(self, flags):
|
||||
return super().__buffer__(flags)
|
||||
|
||||
b = B(b"hello")
|
||||
with memoryview(b) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello A")
|
||||
|
||||
class Releaser:
|
||||
def __release_buffer__(self, buffer):
|
||||
self.buffer = buffer
|
||||
|
||||
class C(Releaser, bytearray):
|
||||
def __buffer__(self, flags):
|
||||
return super().__buffer__(flags)
|
||||
|
||||
c = C(b"hello C")
|
||||
with memoryview(c) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello C")
|
||||
c.clear()
|
||||
with self.assertRaises(ValueError):
|
||||
c.buffer.tobytes()
|
||||
|
||||
def test_multiple_inheritance_buffer_last_raising(self):
|
||||
class A:
|
||||
def __buffer__(self, flags):
|
||||
raise RuntimeError("should not be called")
|
||||
|
||||
def __release_buffer__(self, buffer):
|
||||
raise RuntimeError("should not be called")
|
||||
|
||||
class B(bytearray, A):
|
||||
def __buffer__(self, flags):
|
||||
return super().__buffer__(flags)
|
||||
|
||||
b = B(b"hello")
|
||||
with memoryview(b) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
|
||||
class Releaser:
|
||||
buffer = None
|
||||
def __release_buffer__(self, buffer):
|
||||
self.buffer = buffer
|
||||
|
||||
class C(bytearray, Releaser):
|
||||
def __buffer__(self, flags):
|
||||
return super().__buffer__(flags)
|
||||
|
||||
c = C(b"hello")
|
||||
with memoryview(c) as mv:
|
||||
self.assertEqual(mv.tobytes(), b"hello")
|
||||
c.clear()
|
||||
self.assertIs(c.buffer, None)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_release_buffer_with_exception_set(self):
|
||||
class A:
|
||||
def __buffer__(self, flags):
|
||||
return memoryview(bytes(8))
|
||||
def __release_buffer__(self, view):
|
||||
pass
|
||||
|
||||
b = bytearray(8)
|
||||
with memoryview(b):
|
||||
# now b.extend will raise an exception due to exports
|
||||
with self.assertRaises(BufferError):
|
||||
b.extend(A())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user