def test_convert_memoryview(self): a = b'World is hell!' a_refcount = sys.getrefcount(a) b = containers.StridedArrayView1D(a) b_refcount = sys.getrefcount(b) self.assertEqual(sys.getrefcount(a), a_refcount + 1) c = memoryview(b) self.assertEqual(c.ndim, 1) self.assertEqual(len(c), len(a)) self.assertEqual(bytes(c), a) # Unlike slicing, StridedArrayView's buffer protocol returns a # reference to itself and not the underlying buffer -- it needs to be # kept around because the Py_buffer refers to its internals for size. # Also returning a reference to the underlying buffer would mean the # underlying buffer's releasebuffer function gets called instead of # ours which is *not* wanted. self.assertIs(c.obj, b) self.assertEqual(sys.getrefcount(b), b_refcount + 1) self.assertEqual(sys.getrefcount(a), a_refcount + 1) with self.assertRaisesRegex(TypeError, "cannot modify read-only memory"): c[-1] = ord('?')
def test_init_buffer_memoryview_obj(self): a = b'hello' v = memoryview(a) b = containers.StridedArrayView1D(v) # memoryview's buffer protocol returns itself, not the underlying # bytes, as it manages the Py_buffer instance. So this is expected. self.assertIs(b.owner, v)
def test_init_buffer(self): a = b'hello' a_refcount = sys.getrefcount(a) b = containers.StridedArrayView1D(a) self.assertIs(b.owner, a) self.assertEqual(len(b), 5) self.assertEqual(bytes(b), b'hello') self.assertEqual(b.size, (5, )) self.assertEqual(b.stride, (1, )) self.assertEqual(b[2], 'l') self.assertEqual(sys.getrefcount(a), a_refcount + 1) # Not mutable with self.assertRaisesRegex(TypeError, "object does not support item assignment"): b[4] = '!' # b should keep a reference to a, so deleting the local reference # shouldn't affect it del a self.assertTrue(sys.getrefcount(b.owner), a_refcount) self.assertEqual(b[2], 'l') # Now, if we delete b, a should not be referenced by anything anymore a = b.owner del b self.assertTrue(sys.getrefcount(a), a_refcount)
def test_init_buffer_empty(self): a = b'' a_refcount = sys.getrefcount(a) b = containers.StridedArrayView1D(a) self.assertIs(b.owner, None) self.assertEqual(len(b), 0) self.assertEqual(sys.getrefcount(a), a_refcount)
def test_init_buffer_stride(self): a = memoryview(b'hello')[::2] self.assertEqual(bytes(a), b'hlo') b = containers.StridedArrayView1D(a) self.assertEqual(len(b), 3) self.assertEqual(bytes(b), b'hlo') self.assertEqual(b.size, (3, )) self.assertEqual(b.stride, (2, )) self.assertEqual(b[2], 'o')
def test_slice_empty(self): data = b'hello' data_refcount = sys.getrefcount(data) # slice.start = slice.stop a = containers.StridedArrayView1D(data)[7:8] self.assertEqual(a.size, (0, )) # Empty view, original data not referenced at all self.assertIs(a.owner, None) self.assertEqual(sys.getrefcount(data), data_refcount)
def test_slice_stride_negative(self): a = b'World_ _i_s_ _hell!' b = containers.StridedArrayView1D(a) # Check consistency with slices on bytes c1 = a[-5:3:-2] # like [4:-4:2] above, but reverted c2 = b[-5:3:-2] self.assertEqual(len(c1), 6) self.assertEqual(len(c2), 6) self.assertEqual(bytes(c1), b'h si d') # like b'd is h' but reverted self.assertEqual(bytes(c2), b'h si d') self.assertEqual(c2.size, (6, )) self.assertEqual(c2.stride, (-2, ))
def test_slice_stride(self): a = b'World_ _i_s_ _hell!' b = containers.StridedArrayView1D(a) # Check consistency with slices on bytes c1 = a[4:-4:2] c2 = b[4:-4:2] self.assertIsInstance(c2, containers.StridedArrayView1D) self.assertEqual(len(c1), 6) self.assertEqual(len(c2), 6) self.assertEqual(bytes(c1), b'd is h') self.assertEqual(bytes(c2), b'd is h') self.assertEqual(c2.size, (6, )) self.assertEqual(c2.stride, (2, ))
def test_init(self): a = containers.StridedArrayView1D() b = containers.MutableStridedArrayView1D() self.assertIs(a.owner, None) self.assertIs(b.owner, None) self.assertEqual(len(a), 0) self.assertEqual(len(b), 0) self.assertEqual(bytes(a), b'') self.assertEqual(bytes(b), b'') self.assertEqual(a.size, (0, )) self.assertEqual(b.size, (0, )) self.assertEqual(a.stride, (0, )) self.assertEqual(b.stride, (0, )) self.assertEqual(a.dimensions, 1) self.assertEqual(b.dimensions, 1)
def test_slice(self): a = b'World is hell!' a_refcount = sys.getrefcount(a) b = containers.StridedArrayView1D(a) b_refcount = sys.getrefcount(b) self.assertIs(b.owner, a) self.assertEqual(sys.getrefcount(a), a_refcount + 1) # When slicing, b's refcount should not change but a's refcount should # increase c = b[4:-4] self.assertEqual(c.size, (6, )) self.assertEqual(c.stride, (1, )) self.assertIs(c.owner, a) self.assertIsInstance(c, containers.StridedArrayView1D) self.assertEqual(bytes(c), b'd is h') self.assertEqual(sys.getrefcount(b), b_refcount) self.assertEqual(sys.getrefcount(a), a_refcount + 2) # Deleting a slice should reduce a's refcount again, keep b's unchanged del c self.assertEqual(sys.getrefcount(b), b_refcount) self.assertEqual(sys.getrefcount(a), a_refcount + 1)
def test_slice_invalid(self): with self.assertRaisesRegex(ValueError, "slice step cannot be zero"): containers.StridedArrayView1D()[-5:3:0]
def test_slice_invalid(self): with self.assertRaisesRegex(TypeError, "indices must be integers"): containers.StridedArrayView1D()[-5:3:"boo"]
def test_init_buffer_unexpected_dimensions(self): a = memoryview(b'123456').cast('b', shape=[2, 3]) self.assertEqual(bytes(a), b'123456') with self.assertRaisesRegex(BufferError, "expected 1 dimensions but got 2"): b = containers.StridedArrayView1D(a)