Skip to content

Commit e9f33d8

Browse files
committed
fix for v2 pages
1 parent 8827f00 commit e9f33d8

2 files changed

Lines changed: 29 additions & 18 deletions

File tree

fastparquet/core.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,10 @@ def read_data_page_v2(infile, schema_helper, se, data_header2, cmd,
354354
pagefile.seek(4, 1)
355355
if bit_width in [8, 16, 32] and selfmade:
356356
# special fastpath for cats
357-
outbytes = raw_bytes[pagefile.tell():]
358-
if len(outbytes) == assign[num:num+data_header2.num_values].nbytes:
357+
# Trim to exact byte length (ignore padding)
358+
n_bytes = assign[num:num+data_header2.num_values].nbytes
359+
outbytes = raw_bytes[pagefile.tell():pagefile.tell() + n_bytes]
360+
if len(outbytes) == n_bytes:
359361
assign[num:num+data_header2.num_values].view('uint8')[row_filter] = outbytes[row_filter]
360362
else:
361363
if data_header2.num_nulls == 0:

fastparquet/test/test_output.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -599,15 +599,23 @@ def test_auto_null_object(tempdir):
599599

600600

601601
@pytest.mark.parametrize('remainder', (1, 2, 3))
602-
def test_dict_encoding_padding(tempdir, remainder):
602+
@pytest.mark.parametrize('datapage_version', (1, 2))
603+
def test_dict_encoding_padding(tempdir, remainder, datapage_version, monkeypatch):
603604
"""Regression test for GH#979.
604605
605606
When Ncat > 128 the backing dtype is int16 (bit_width=16). The RLE
606607
bit-packed run header declares ceil(N/8) groups of 8 values; each group
607608
must occupy exactly 8 * itemsize bytes. When N % 8 is in {1,2,3} the last
608609
group is partial and the missing slots must be zero-padded. Without the
609610
fix, strict readers (e.g. Apache Spark) overrun the page buffer.
611+
Both V1 and V2 data pages are exercised here.
610612
"""
613+
if datapage_version == 2:
614+
monkeypatch.setenv("FASTPARQUET_DATAPAGE_V2", "1")
615+
else:
616+
monkeypatch.delenv("FASTPARQUET_DATAPAGE_V2", raising=False)
617+
monkeypatch.setattr(writer, "DATAPAGE_VERSION", datapage_version)
618+
611619
categories = [f"CAT_{i:04d}" for i in range(490)] # 490 cats → int16 codes
612620
# Choose num_values so that num_values % 8 == remainder
613621
num_values = 496 + remainder # 497, 498 or 499
@@ -623,21 +631,22 @@ def test_dict_encoding_padding(tempdir, remainder):
623631
out = ParquetFile(fn).to_pandas()
624632
tm.assert_frame_equal(df, out, check_categorical=False, check_dtype=False)
625633

626-
# Verify the encoded page size is a multiple of 8 * itemsize (16 bytes per group)
627-
encoded = writer.encode_dict(df['col'].cat.codes, None)
628-
# First byte is bit_width; next byte(s) are the varint run header; rest is data+padding
629-
bit_width = encoded[0]
630-
assert bit_width == 16
631-
# Strip the header (bit_width byte + varint) to get the raw data+padding bytes
632-
idx = 1
633-
while encoded[idx] & 0x80:
634-
idx += 1
635-
idx += 1 # past the last varint byte
636-
data_bytes = len(encoded) - idx
637-
group_size = 8 * (bit_width // 8) # 16 bytes per group
638-
assert data_bytes % group_size == 0, (
639-
f"data bytes ({data_bytes}) not a multiple of group_size ({group_size})"
640-
)
634+
if datapage_version == 1:
635+
# Verify the encoded page size is a multiple of 8 * itemsize (16 bytes per group)
636+
encoded = writer.encode_dict(df['col'].cat.codes, None)
637+
# First byte is bit_width; next byte(s) are the varint run header; rest is data+padding
638+
bit_width = encoded[0]
639+
assert bit_width == 16
640+
# Strip the header (bit_width byte + varint) to get the raw data+padding bytes
641+
idx = 1
642+
while encoded[idx] & 0x80:
643+
idx += 1
644+
idx += 1 # past the last varint byte
645+
data_bytes = len(encoded) - idx
646+
group_size = 8 * (bit_width // 8) # 16 bytes per group
647+
assert data_bytes % group_size == 0, (
648+
f"data bytes ({data_bytes}) not a multiple of group_size ({group_size})"
649+
)
641650

642651

643652
@pytest.mark.parametrize('n', (10, 127, 2**8 + 1, 2**16 + 1))

0 commit comments

Comments
 (0)