def test_replicate_pointers(self): """Tests sending a heap with replicate_pointers set to true""" id = 0x2345 data = np.arange(32, dtype=np.uint8) item1 = spead2.Item(id=id, name='item1', description='addressed item', shape=data.shape, dtype=data.dtype, value=data) item2 = spead2.Item(id=id + 1, name='item2', description='inline item', shape=(), format=[('u', self.flavour.heap_address_bits)], value=0xdeadbeef) expected = [ b''.join([ self.flavour.make_header(6), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, 32), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, 16), self.flavour.make_address(id, 0), self.flavour.make_immediate(id + 1, 0xdeadbeef), data.tobytes()[0:16] ]), b''.join([ self.flavour.make_header(6), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, 32), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 16), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, 16), self.flavour.make_address(id, 0), self.flavour.make_immediate(id + 1, 0xdeadbeef), data.tobytes()[16:32] ]) ] packets = self.flavour.items_to_bytes([item1, item2], [], max_packet_size=72, repeat_pointers=True) assert hexlify(packets) == hexlify(expected)
def test_nonascii_value(self): """Using a non-ASCII unicode character raises a :py:exc:`UnicodeEncodeError`.""" item1 = spead2.Item(0x1000, 'name1', 'description', (None,), format=[('c', 8)], value='\u0200') item2 = spead2.Item(0x1001, 'name2', 'description2', (), dtype='S5', value='\u0201') with pytest.raises(UnicodeEncodeError): item1.to_buffer() with pytest.raises(UnicodeEncodeError): item2.to_buffer()
def test_small_variable(self): """Sending a small item with dynamic shape must not use an immediate.""" id = 0x2345 shape = (1, None) data = np.array([[4, 5]], dtype=np.uint8) payload = struct.pack('>2B', 4, 5) expected = [ b''.join([ self.flavour.make_header(5), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, len(payload)), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, len(payload)), self.flavour.make_address(id, 0), payload ]) ] item = spead2.Item(id=id, name='name', description='description', shape=shape, format=[('u', 8)]) item.value = data packet = self.flavour.items_to_bytes([item], []) assert_equal(hexlify(expected), hexlify(packet))
def test_numpy_simple(self): """A single numpy-format item with descriptor""" id = 0x2345 shape = (2, 3) data = np.array([[6, 7, 8], [10, 11, 12000]], dtype=np.uint16) payload_fields = [ self.make_descriptor_numpy(id, 'name', 'description', shape, '<u2', False), struct.pack('<6H', 6, 7, 8, 10, 11, 12000) ] payload = b''.join(payload_fields) offsets = offset_generator(payload_fields) expected = [ b''.join([ self.flavour.make_header(6), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, len(payload)), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, len(payload)), self.flavour.make_address(spead2.DESCRIPTOR_ID, next(offsets)), self.flavour.make_address(id, next(offsets)), payload ]) ] item = spead2.Item(id=id, name='name', description='description', shape=shape, dtype=np.uint16) item.value = data packet = self.flavour.items_to_bytes([item]) assert_equal(hexlify(expected), hexlify(packet))
def test_numpy_noncontiguous(self): """A numpy item with a discontiguous item value is sent correctly""" id = 0x2345 shape = (2, 3) store = np.array( [[6, 7, 8, 0, 1], [10, 11, 12000, 2, 3], [9, 9, 9, 9, 9]], dtype=np.uint16) data = store[:2, :3] payload = struct.pack('<6H', 6, 7, 8, 10, 11, 12000) expected = [ b''.join([ self.flavour.make_header(5), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, len(payload)), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, len(payload)), self.flavour.make_address(id, 0), payload ]) ] item = spead2.Item(id=id, name='name', description='description', shape=shape, dtype=np.uint16) item.value = data packet = self.flavour.items_to_bytes([item], []) assert_equal(hexlify(expected), hexlify(packet))
def test_numpy_fortran_order(self): """A numpy item with Fortran-order descriptor must be sent in Fortran order""" id = 0x2345 shape = (2, 3) data = np.array([[6, 7, 8], [10, 11, 12000]], order='F') assert_false(data.flags.c_contiguous) payload_fields = [ self.make_descriptor_numpy(id, 'name', 'description', shape, '<u2', True), struct.pack('<6H', 6, 10, 7, 11, 8, 12000) ] payload = b''.join(payload_fields) offsets = offset_generator(payload_fields) expected = [ b''.join([ self.flavour.make_header(6), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, len(payload)), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, len(payload)), self.flavour.make_address(spead2.DESCRIPTOR_ID, next(offsets)), self.flavour.make_address(id, next(offsets)), payload ]) ] item = spead2.Item(id=id, name='name', description='description', shape=shape, dtype=np.uint16, order='F') item.value = data packet = self.flavour.items_to_bytes([item]) assert_equal(hexlify(expected), hexlify(packet))
def test_small_fixed(self): """Sending a small item with fixed shape must use an immediate.""" id = 0x2345 data = 0x7654 payload = struct.pack('>I', data) expected = [ b''.join([ self.flavour.make_header(6), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, 1), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, 1), self.flavour.make_immediate(id, data), self.flavour.make_address(spead2.NULL_ID, 0), struct.pack('B', 0) ]) ] item = spead2.Item(id=id, name='name', description='description', shape=(), format=[('u', 16)]) item.value = data packet = self.flavour.items_to_bytes([item], []) assert_equal(hexlify(expected), hexlify(packet))
def test_fallback_types(self): """Send an array with mixed types and strange packing""" id = 0x2345 format = [('b', 1), ('i', 7), ('c', 8), ('f', 32)] shape = (2, ) data = [(True, 17, 'y', 1.0), (False, -23.0, 'n', -1.0)] payload_fields = [ self.make_descriptor_fallback(id, 'name', 'description', shape, format), b'\x91y\x3F\x80\x00\x00' + b'\x69n\xBF\x80\x00\x00' ] payload = b''.join(payload_fields) offsets = offset_generator(payload_fields) expected = [ b''.join([ self.flavour.make_header(6), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, len(payload)), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, len(payload)), self.flavour.make_address(spead2.DESCRIPTOR_ID, next(offsets)), self.flavour.make_address(id, next(offsets)), payload ]) ] item = spead2.Item(id=id, name='name', description='description', shape=shape, format=format) item.value = data packet = self.flavour.items_to_bytes([item]) assert_equal(hexlify(expected), hexlify(packet))
def test_numpy_zero_length(self): """A zero-length numpy type raises :exc:`ValueError`""" with pytest.raises(ValueError): spead2.Item(id=0x2345, name='name', description='description', shape=(), dtype=np.str_)
def test_fallback_zero_length(self): """A zero-length type raises :exc:`ValueError`""" with pytest.raises(ValueError): spead2.Item(id=0x2345, name='name', description='description', shape=(), format=[('u', 0)])
def test_zero_copy(self): """Test that heaps can reference original data. This allows heaps to be updated by just changing the data. """ id = 0x2345 data = np.arange(8, dtype=np.uint8) imm = np.zeros((), dtype='>u8') item1 = spead2.Item(id=id, name='item1', description='addressed item', shape=data.shape, dtype=data.dtype, value=data) item2 = spead2.Item(id=id + 1, name='item2', description='inline item', shape=(), format=[('u', self.flavour.heap_address_bits)], value=imm) heap = spead2.send.Heap(self.flavour) heap.add_item(item1) heap.add_item(item2) # Now change the values after they've been added to the heap. data *= 2 imm[()] = 0xdeadbeef expected = [ b''.join([ self.flavour.make_header(6), self.flavour.make_immediate(spead2.HEAP_CNT_ID, 0x123456), self.flavour.make_immediate(spead2.HEAP_LENGTH_ID, 8), self.flavour.make_immediate(spead2.PAYLOAD_OFFSET_ID, 0), self.flavour.make_immediate(spead2.PAYLOAD_LENGTH_ID, 8), self.flavour.make_address(id, 0), self.flavour.make_immediate(id + 1, 0xdeadbeef), data.tobytes() ]) ] gen = send.PacketGenerator(heap, 0x123456, 1500) packets = list(gen) assert hexlify(packets) == hexlify(expected)
def test_lifetime(self): """Heap must hold references to item values""" item = spead2.Item(id=0x2345, name='name', description='description', shape=(2, 3), dtype=np.uint16) item.value = np.array([[6, 7, 8], [10, 11, 12000]], dtype=np.uint16) weak = weakref.ref(item.value) heap = send.Heap(self.flavour) heap.add_item(item) del item packets = list(send.PacketGenerator(heap, 0x123456, 1472)) # noqa: F841 assert weak() is not None del heap # pypy needs multiple gc passes to wind it all up for i in range(10): gc.collect() assert weak() is None
def test_lifetime(self): """Heap must hold references to item values""" item = spead2.Item(id=0x2345, name='name', description='description', shape=(2, 3), dtype=np.uint16) item.value = np.array([[6, 7, 8], [10, 11, 12000]], dtype=np.uint16) weak = weakref.ref(item.value) heap = send.Heap(self.flavour) heap.add_item(item) del item packets = list(send.PacketGenerator(heap, 0x123456, 1472)) assert_is_not_none(weak()) del heap assert_is_none(weak())
def test_fortran_fallback(self): """The `order` parameter must be 'C' for legacy formats.""" with pytest.raises(ValueError): spead2.Item(0x1000, 'name', 'description', (1, 2), format=[('u', 32)], order='F')
def test_assign_none(self): """Changing a value back to `None` raises :py:exc:`ValueError`.""" item = spead2.Item(0x1000, 'name', 'description', (), np.int32) with pytest.raises(ValueError): item.value = None
def test_empty_format(self): """Format must not be empty""" with pytest.raises(ValueError): spead2.Item(0x1000, 'name', 'description', (1, 2), format=[])
def test_multiple_unknown(self): """Multiple unknown dimensions are not allowed.""" with pytest.raises(ValueError): spead2.Item(0x1000, 'name', 'description', (5, None, 3, None), format=[('u', 32)])
def test_numpy_unknown(self): """Unknown dimensions are not permitted when using a numpy descriptor""" with pytest.raises(ValueError): spead2.Item(0x1000, 'name', 'description', (5, None), np.int32)
def test_nonascii_description(self): """Description with non-ASCII characters must fail""" with pytest.raises(UnicodeEncodeError): item = spead2.Item(0x1000, 'name', '\u0200', (), np.int32) item.to_raw(spead2.Flavour())
def test_invalid_order(self): """The `order` parameter must be either 'C' or 'F'.""" with pytest.raises(ValueError): spead2.Item(0x1000, 'name', 'description', (1, 2), np.int32, order='K')
def test_nonascii_name(self): """Name with non-ASCII characters must fail""" with assert_raises(UnicodeEncodeError): item = spead2.Item(0x1000, '\u0200', 'description', (), np.int32) item.to_raw(spead2.Flavour())
def test_format_and_dtype(self): """Specifying both a format and dtype raises :py:exc:`ValueError`.""" with pytest.raises(ValueError): spead2.Item(0x1000, 'name', 'description', (1, 2), format=[('c', 8)], dtype='S1')
def test_no_format_or_dtype(self): """At least one of format and dtype must be specified.""" with pytest.raises(ValueError): spead2.Item(0x1000, 'name', 'description', (1, 2), format=None)