Skip to content

Commit 9f5c932

Browse files
committed
Also fix pandas 2 :)
1 parent 4f4c489 commit 9f5c932

4 files changed

Lines changed: 36 additions & 13 deletions

File tree

fastparquet/api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from fastparquet.util import (default_open, default_remove, ParquetException, val_to_num,
1616
ops, ensure_bytes, ensure_str, check_column_names, metadata_from_many,
1717
ex_from_sep, _strip_path_tail, get_fs, PANDAS_VERSION, join_path)
18-
from fastparquet.encoding import _HAVE_ARROW
18+
from fastparquet.encoding import _HAVE_ARROW, _USE_ARROW_STRINGS
1919

2020
if _HAVE_ARROW:
2121
import pyarrow as _pa
@@ -786,7 +786,7 @@ def to_pandas(self, columns=None, categories=None, filters=[],
786786
# Skip columns whose dtype was explicitly requested as object (via dtypes=)
787787
# to honour the caller's preference and to handle schema-evolution cases.
788788
arrow_string_columns = {}
789-
if _HAVE_ARROW:
789+
if _HAVE_ARROW and _USE_ARROW_STRINGS:
790790
_cats = categories or {}
791791
# Resolve user-supplied dtype overrides only (not auto-inferred ones).
792792
# Auto-inferred dtypes always show dtype('O') for UTF-8 columns, so
@@ -841,7 +841,7 @@ def to_pandas(self, columns=None, categories=None, filters=[],
841841
start += thislen
842842

843843
# Finalize arrow string columns: concatenate per-page arrays and assign.
844-
if _HAVE_ARROW:
844+
if _HAVE_ARROW and _USE_ARROW_STRINGS:
845845
for col, parts in arrow_string_columns.items():
846846
if not parts:
847847
continue

fastparquet/core.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pandas as pd
33

44
from fastparquet import encoding
5-
from fastparquet.encoding import read_plain, _HAVE_ARROW
5+
from fastparquet.encoding import read_plain, _HAVE_ARROW, _USE_ARROW_STRINGS
66
import fastparquet.cencoding as encoding
77
from fastparquet.compression import decompress_data, rev_map, decom_into
88
from fastparquet.converted_types import convert, simple, converts_inplace
@@ -308,7 +308,7 @@ def read_data_page_v2(infile, schema_helper, se, data_header2, cmd,
308308
raw_bytes = decompress_data(np.frombuffer(infile.read(size), "uint8"),
309309
uncompressed_page_size, codec)
310310
# Arrow path: build ArrowStringArray directly without Python str objects.
311-
if (arrow_parts is not None and _HAVE_ARROW
311+
if (arrow_parts is not None and _HAVE_ARROW and _USE_ARROW_STRINGS
312312
and se.converted_type == parquet_thrift.ConvertedType.UTF8
313313
and not use_cat):
314314
raw_np = np.asarray(raw_bytes, dtype=np.uint8)
@@ -487,9 +487,11 @@ def read_col(column, schema_helper, infile, use_cat=False,
487487
rows = row_filter.sum() if isinstance(row_filter, np.ndarray) else cmd.num_values
488488

489489
# Determine whether to use the arrow accumulation path for this column.
490-
# Conditions: pyarrow available, utf=True schema element, caller provided a list.
490+
# Conditions: pyarrow available, arrow strings are the default, utf=True
491+
# schema element, and caller provided a list to accumulate into.
491492
use_arrow = (
492493
_HAVE_ARROW
494+
and _USE_ARROW_STRINGS
493495
and arrow_parts is not None
494496
and not use_cat
495497
and se.converted_type == parquet_thrift.ConvertedType.UTF8

fastparquet/encoding.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@
1111
except ImportError:
1212
_HAVE_ARROW = False
1313

14+
# Use the arrow string path only when pandas itself defaults to arrow strings.
15+
# In pandas 3+, pd.options.future.infer_string is True by default.
16+
# In pandas 2, it is False (object dtype is the default for strings).
17+
# This can also be explicitly enabled in pandas 2 with
18+
# pd.options.future.infer_string = True
19+
# so we respect that too.
20+
try:
21+
import pandas as _pd
22+
_USE_ARROW_STRINGS = bool(getattr(getattr(_pd.options, 'future', None),
23+
'infer_string', False))
24+
except Exception:
25+
_USE_ARROW_STRINGS = False
26+
1427

1528
def read_plain_boolean(raw_bytes, count, out=None):
1629
data = np.frombuffer(raw_bytes, dtype='uint8')
@@ -45,9 +58,11 @@ def read_plain(raw_bytes, type_, count, width=0, utf=False, stat=False):
4558
return np.array([bytes(raw_bytes).decode()], dtype='O')
4659
else:
4760
return np.array([bytes(raw_bytes)], dtype='O')
48-
if utf and _HAVE_ARROW:
61+
if utf and _HAVE_ARROW and _USE_ARROW_STRINGS:
4962
# Build an ArrowStringArray directly from the packed bytes, without
5063
# creating intermediate Python str objects in the inner loop.
64+
# Only used when pandas defaults to arrow strings (pandas 3+, or
65+
# pandas 2 with future.infer_string=True).
5166
raw_np = np.frombuffer(memoryview(raw_bytes), dtype=np.uint8)
5267
return _unpack_arrow(raw_np, count)
5368
return unpack_byte_array(raw_bytes, count, utf=utf)

fastparquet/test/test_api.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,18 @@ def test_text_schema(tempdir):
8282
write(fn, df)
8383
p = ParquetFile(fn)
8484
t = p.schema.text
85-
expected = ('- schema: \n'
86-
'| - A: DOUBLE, OPTIONAL\n'
87-
'| - B: DOUBLE, OPTIONAL\n'
88-
'| - C: BYTE_ARRAY, UTF8, OPTIONAL\n'
89-
' - D: INT64, TIMESTAMP[MICROS], TIMESTAMP_MICROS, OPTIONAL')
90-
assert t == expected
85+
# pandas 2 uses nanosecond timestamps (NANOS), pandas 3 uses microseconds (MICROS)
86+
expected_micros = ('- schema: \n'
87+
'| - A: DOUBLE, OPTIONAL\n'
88+
'| - B: DOUBLE, OPTIONAL\n'
89+
'| - C: BYTE_ARRAY, UTF8, OPTIONAL\n'
90+
' - D: INT64, TIMESTAMP[MICROS], TIMESTAMP_MICROS, OPTIONAL')
91+
expected_nanos = ('- schema: \n'
92+
'| - A: DOUBLE, OPTIONAL\n'
93+
'| - B: DOUBLE, OPTIONAL\n'
94+
'| - C: BYTE_ARRAY, UTF8, OPTIONAL\n'
95+
' - D: INT64, TIMESTAMP[NANOS], OPTIONAL')
96+
assert t in (expected_micros, expected_nanos)
9197
assert repr(p.schema) == "<Parquet Schema with 5 entries>"
9298

9399

0 commit comments

Comments
 (0)