@@ -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