Fix array payload encoding from sequences - #31
Conversation
An array register now formats a sequence element-wise rather than against the sub-array dtype, which broadcast each element into the full shape. A list or tuple of the declared length produces the same bytes as the equivalent ndarray, where before [1, 2] for a two-element U16 register would produce four elements. A sequence of the wrong length raises instead of producing a longer payload. parse also raises HarpParseError naming the register, its payload type and the byte count when the buffer is too short to read one item, replacing a numpy message that named neither side.
bruno-f-cruz
left a comment
There was a problem hiding this comment.
Nice catch! If I understand correctly this should not affect the bulk parsing/format path, but but worth a check.
format_bulk converts a sequence against the element type of an array register and lets the declared shape decide the frame count, so a nested list and an element-typed array produce the same frames, and a flat sequence of the declared length produces one frame. A shape not ending in the declared payload shape raises. parse_bulk raises HarpParseError naming the register and the byte counts when the buffer holds less than one frame. A partial trailing frame is still dropped, so a truncated recording still loads.
|
Checked, and you were right that the bulk path is unaffected. It did leave an asymmetry though, with The partial trailing frame stays as it is. The same path serves a file read through |
An array register mis-encoded a Python list or tuple. Its payload dtype is a sub-array,
('<u2', (2,))for a two-elementU16register, and converting a sequence against that dtype makes numpy broadcast each element into the full shape, so[1, 2]would produce four elements and eight bytes, round-tripping to[1, 1], while the equivalent ndarray produced the correct two. A caller writing a list put wrong bytes on the wire with nothing raised.Encoding a sequence
formatandformat_bulkboth convert against the element type and let the declared shape decide how many elements are expected, so a list, a tuple and an ndarray agree, and on the bulk path a nested sequence and an element-typed array produce the same frames. A flat sequence of the declared length is a single frame.Shapes that do not end in the declared payload shape raise instead of being interpreted, which covers a sequence of the wrong length and the ambiguous flat form, where four elements for a two-element register could be one frame or two. Nothing shielded the original defect, since
formathandlesPayloadBaseandndarraybefore reaching the constructor and only the sequence path was affected.Naming the register on a short buffer
parsehanded the buffer straight to numpy, which reportedbuffer is smaller than requested size, naming neither the register, its declared payload type, nor the byte count. It now raisesHarpParseErrorwith all three, andparse_bulkdoes the same when the buffer holds less than one frame, in place of an out-of-bounds index against its strided view. The smallest frame on the wire becomes a single constant, whichHarpMessage.parsereads as well.The
parsecheck is a lower bound rather than equality, deliberately.parsereads one item from the front, which is whatcount=1means, andparse_bulkis its sibling for reading many items from one buffer.HarpMessage.decodealready requires the payload to be exactly the declared size, so the strict form sits at the level that interprets a whole message. That also bounds who this affects. A message going throughdecodeis rejected earlier with a better message, so the improvement is for callers reachingparsedirectly, which the widerbytes | bytearray | memoryviewsignature invites.The trailing frame stays as it is
A partial trailing frame is still dropped without complaint. One path serves both an in-memory buffer and a file read from a path, and
DatasetReader.readconcatenates chunks as raw bytes, so raising would make a recording cut off mid-acquisition unreadable. Reporting a dropped tail belongs with a strict option, as its own change.