From aafa183f7a57503e3fd347a5ce3b331c6d2fb8a2 Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Tue, 18 Aug 2026 01:35:31 +0000 Subject: [PATCH 1/3] Replace prefetch_file_metadata's bool/Unspecified with explicit remote_only/always/never values --- .../cudf_polars/cudf_polars/dsl/utils/io.py | 4 +- python/cudf_polars/cudf_polars/engine/core.py | 6 +- .../cudf_polars/streaming/benchmarks/utils.py | 4 +- .../cudf_polars/streaming/select.py | 2 +- .../cudf_polars/cudf_polars/utils/config.py | 82 ++++++++++--------- .../cudf_polars/tests/streaming/test_scan.py | 18 ++-- python/cudf_polars/tests/test_config.py | 53 ++++++++---- python/cudf_polars/tests/test_scan.py | 4 +- python/cudf_polars/tests/test_select.py | 4 +- 9 files changed, 98 insertions(+), 79 deletions(-) diff --git a/python/cudf_polars/cudf_polars/dsl/utils/io.py b/python/cudf_polars/cudf_polars/dsl/utils/io.py index 0c4b5bd989fc..9a5cc6e58575 100644 --- a/python/cudf_polars/cudf_polars/dsl/utils/io.py +++ b/python/cudf_polars/cudf_polars/dsl/utils/io.py @@ -28,8 +28,8 @@ class CachedParquetInfo: Metadata for a parquet file. File metadata is only cached when the setting - ``ParquetOptions.prefetch_file_metadata`` is ``True``. Metadata is cached - for the duration of the query. + ``ParquetOptions.prefetch_file_metadata`` is not ``"never"``. Metadata is + cached for the duration of the query. Parameters ---------- diff --git a/python/cudf_polars/cudf_polars/engine/core.py b/python/cudf_polars/cudf_polars/engine/core.py index 3a58ef3ac1c3..fd6631ca79f0 100644 --- a/python/cudf_polars/cudf_polars/engine/core.py +++ b/python/cudf_polars/cudf_polars/engine/core.py @@ -42,7 +42,7 @@ from cudf_polars.streaming.parallel import lower_ir_graph_with_node_map from cudf_polars.streaming.statistics import collect_statistics from cudf_polars.streaming.utils import _concat -from cudf_polars.utils.config import Unspecified, get_total_device_memory +from cudf_polars.utils.config import get_total_device_memory if TYPE_CHECKING: from collections.abc import Callable, MutableMapping @@ -786,12 +786,12 @@ def evaluate_on_rank( ) prefetch_file_metadata = config_options.parquet_options.prefetch_file_metadata - if prefetch_file_metadata is not False: + if prefetch_file_metadata != "never": cached_parquet_info_map = prefetch_parquet_file_metadata_for_ir( ir, ir_context.py_executor, stats=stats, - remote_only=isinstance(prefetch_file_metadata, Unspecified), + remote_only=prefetch_file_metadata == "remote_only", ) attach_cached_parquet_metadata(ir, cached_parquet_info_map) diff --git a/python/cudf_polars/cudf_polars/streaming/benchmarks/utils.py b/python/cudf_polars/cudf_polars/streaming/benchmarks/utils.py index c430ffc034dd..40670caae6d1 100644 --- a/python/cudf_polars/cudf_polars/streaming/benchmarks/utils.py +++ b/python/cudf_polars/cudf_polars/streaming/benchmarks/utils.py @@ -684,9 +684,7 @@ def serialize(self, engine: StreamingEngine | None) -> dict: config_options = config_options.drop_unserializable() rapidsmpf_options = engine.rapidsmpf_options.get_strings() result["config_options"] = { - "config_options": dataclasses.asdict( - config_options, dict_factory=ConfigOptions.dict_factory - ), + "config_options": dataclasses.asdict(config_options), "rapidsmpf_options": rapidsmpf_options, } # discard unserializable / unnecessary UUIDs diff --git a/python/cudf_polars/cudf_polars/streaming/select.py b/python/cudf_polars/cudf_polars/streaming/select.py index b95bf296c267..3dcb8598d2c8 100644 --- a/python/cudf_polars/cudf_polars/streaming/select.py +++ b/python/cudf_polars/cudf_polars/streaming/select.py @@ -440,7 +440,7 @@ def _( scan_child.skip_rows, scan_child.n_rows, dataclasses.replace( - scan_child.parquet_options, prefetch_file_metadata=False + scan_child.parquet_options, prefetch_file_metadata="never" ), None, ) diff --git a/python/cudf_polars/cudf_polars/utils/config.py b/python/cudf_polars/cudf_polars/utils/config.py index 315aa0c8f8cd..daf2b276e59f 100644 --- a/python/cudf_polars/cudf_polars/utils/config.py +++ b/python/cudf_polars/cudf_polars/utils/config.py @@ -70,11 +70,9 @@ class Unspecified: Sentinel value meaning "no value was explicitly provided". The singleton instance :data:`UNSPECIFIED` is used as the default for every - :class:`StreamingOptions` field, as well as for - ``ParquetOptions.prefetch_file_metadata``. When a field is still - ``UNSPECIFIED`` after construction (i.e. neither an explicit value nor a - matching environment variable was provided), the consuming component decides - on the semantics. + :class:`StreamingOptions` field. When a field is still ``UNSPECIFIED`` after + construction (i.e. neither an explicit value nor a matching environment + variable was provided), the consuming component decides on the semantics. """ _instance: Unspecified | None = None @@ -91,8 +89,7 @@ def __repr__(self) -> str: UNSPECIFIED = Unspecified() -"""Singleton sentinel for all :class:`StreamingOptions` fields, as well as for -``ParquetOptions.prefetch_file_metadata``. +"""Singleton sentinel for all :class:`StreamingOptions` fields. A field set to ``UNSPECIFIED`` after construction means no explicit value and no matching environment variable was found; the consuming component decides on the @@ -221,6 +218,24 @@ def _bool_converter(v: str) -> bool: raise ValueError(f"Invalid boolean value: '{v}'") +PrefetchFileMetadata = Literal["remote_only", "always", "never"] + + +def _prefetch_file_metadata_converter(v: str) -> PrefetchFileMetadata: + lowered = v.lower() + if lowered in {"remote_only", "always", "never"}: + return lowered # type: ignore[return-value] + try: + # Also accept boolean-style values, for parity with other options: + # true/1 means "always", false/0 means "never". + return "always" if _bool_converter(v) else "never" + except ValueError: + raise ValueError( + f"Invalid value for prefetch_file_metadata: '{v}'. " + "Must be one of 'remote_only', 'always', 'never'." + ) from None + + def _quent_context_converter(v: str) -> QuentContext | None: from cudf_polars.quent._context import QuentContext @@ -271,10 +286,14 @@ class ParquetOptions: will also be skipped if ``max_footer_samples`` is 0. prefetch_file_metadata Whether to prefetch parquet file metadata and pass it through - `parquet_metadatas` to avoid rereading file footers. Not supported - by the in-memory executor, where it defaults to disabled. For the - streaming executor, it defaults to being enabled for remote URIs - (e.g. ``s3://``) only; pass ``True`` to also prefetch local files. + `parquet_metadatas` to avoid rereading file footers. One of + ``"remote_only"``, ``"always"``, or ``"never"``. ``"remote_only"`` + (the default) prefetches remote URIs (e.g. ``s3://``) only, and only + for the streaming executor. ``"always"`` prefetches local files too. + ``"never"`` disables prefetching. ``"always"`` is not supported by + the in-memory executor. The environment variable also accepts + boolean-style values (``"1"``/``"0"``, ``"true"``/``"false"``, etc.), + which map to ``"always"``/``"never"`` respectively. use_jit_filter Whether to use JIT compilation for post-read filtering in Parquet scans. When enabled, filter predicates are JIT-compiled to CUDA kernels for @@ -314,11 +333,11 @@ class ParquetOptions: f"{_env_prefix}__MAX_ROW_GROUP_SAMPLES", int, default=1 ) ) - prefetch_file_metadata: bool | Unspecified = dataclasses.field( + prefetch_file_metadata: PrefetchFileMetadata = dataclasses.field( default_factory=_make_default_factory( f"{_env_prefix}__PREFETCH_FILE_METADATA", - _bool_converter, - default=UNSPECIFIED, + _prefetch_file_metadata_converter, + default="remote_only", ) ) use_jit_filter: bool = dataclasses.field( @@ -342,8 +361,10 @@ def __post_init__(self) -> None: # noqa: D105 raise TypeError("max_footer_samples must be an int") if not isinstance(self.max_row_group_samples, int): raise TypeError("max_row_group_samples must be an int") - if not isinstance(self.prefetch_file_metadata, (bool, Unspecified)): - raise TypeError("prefetch_file_metadata must be a bool when specified") + if self.prefetch_file_metadata not in {"remote_only", "always", "never"}: + raise TypeError( + "prefetch_file_metadata must be one of 'auto', 'always', 'never'" + ) if not isinstance(self.use_jit_filter, bool): raise TypeError("use_jit_filter must be a bool") @@ -1002,27 +1023,6 @@ class ConfigOptions(Generic[ExecutorType]): device: int | None = None memory_resource_config: MemoryResourceConfig | None = None - @staticmethod - def dict_factory(items: list[tuple[str, Any]]) -> dict[str, Any]: - """ - ``dict_factory`` for :func:`dataclasses.asdict`. - - Converts any :data:`UNSPECIFIED` value to ``None`` - (e.g. ParquetOptions.prefetch_file_metadata) so the resulting - dict can be serialized with :func:`json.dumps`. - - Parameters - ---------- - items - The ``(key, value)`` pairs for a single dataclass level, as passed - by :func:`dataclasses.asdict`. - - Returns - ------- - A dict with :data:`UNSPECIFIED` values replaced by ``None``. - """ - return {k: (None if isinstance(v, Unspecified) else v) for k, v in items} - def drop_unserializable(self) -> ConfigOptions[ExecutorType]: """ Return a copy safe to pickle to a worker/actor. @@ -1064,7 +1064,9 @@ def from_polars_engine( # Engine-dependent default: only prefetch for the streaming executor. # Skipped if the user or the environment has already set a value. - prefetch_default = UNSPECIFIED if user_executor == "streaming" else False + prefetch_default: PrefetchFileMetadata = ( + "remote_only" if user_executor == "streaming" else "never" + ) prefetch_env_set = ( os.environ.get(f"{ParquetOptions._env_prefix}__PREFETCH_FILE_METADATA") is not None @@ -1080,7 +1082,7 @@ def from_polars_engine( parquet_options = ParquetOptions(**user_parquet_options) else: if ( - isinstance(user_parquet_options.prefetch_file_metadata, Unspecified) + user_parquet_options.prefetch_file_metadata == "remote_only" and not prefetch_env_set ): user_parquet_options = dataclasses.replace( @@ -1115,7 +1117,7 @@ def from_polars_engine( match user_executor: case "in-memory": executor = InMemoryExecutor(**user_executor_options) - if parquet_options.prefetch_file_metadata is True: + if parquet_options.prefetch_file_metadata == "always": raise NotImplementedError( "Prefetching is not supported for the in-memory executor." ) diff --git a/python/cudf_polars/tests/streaming/test_scan.py b/python/cudf_polars/tests/streaming/test_scan.py index a44af628ea1c..1539665390a4 100644 --- a/python/cudf_polars/tests/streaming/test_scan.py +++ b/python/cudf_polars/tests/streaming/test_scan.py @@ -105,7 +105,7 @@ def test_scan_parquet_prefetch_file_metadata( streaming_engine = streaming_engine_factory( StreamingOptions( target_partition_size=target_partition_size, - parquet_options={"prefetch_file_metadata": True}, + parquet_options={"prefetch_file_metadata": "always"}, ), ) make_partitioned_source(df, tmp_path, "parquet", n_files=n_files) @@ -114,7 +114,7 @@ def test_scan_parquet_prefetch_file_metadata( def test_prefetch_file_metadata_non_parquet_scan(df, streaming_engine_factory) -> None: streaming_engine = streaming_engine_factory( - StreamingOptions(parquet_options={"prefetch_file_metadata": True}), + StreamingOptions(parquet_options={"prefetch_file_metadata": "always"}), ) assert_gpu_result_equal(df.lazy().select("x"), engine=streaming_engine) @@ -153,7 +153,7 @@ def test_prefetch_file_metadata_select_fast_count( tmp_path: Path, ) -> None: streaming_engine = streaming_engine_factory( - StreamingOptions(parquet_options={"prefetch_file_metadata": True}), + StreamingOptions(parquet_options={"prefetch_file_metadata": "always"}), ) source = tmp_path / "data.parquet" df.write_parquet(source) @@ -373,7 +373,8 @@ def test_streaming_scan_raises() -> None: def test_scan_path_mismatch_raises() -> None: # This isn't reachable by polars' public API, so we test it directly. scan = _make_parquet_scan( - ["file.parquet"], parquet_options=ParquetOptions(prefetch_file_metadata=True) + ["file.parquet"], + parquet_options=ParquetOptions(prefetch_file_metadata="always"), ) ctx = IRExecutionContext() @@ -401,7 +402,8 @@ def test_scan_path_mismatch_raises() -> None: def test_streaming_scan_missing_prefetch_metadata_raises() -> None: # This isn't reachable by polars' public API, so we test it directly. scan = _make_parquet_scan( - ["file.parquet"], parquet_options=ParquetOptions(prefetch_file_metadata=True) + ["file.parquet"], + parquet_options=ParquetOptions(prefetch_file_metadata="always"), ) fused = FusedScan(scan.schema, scan, scan.paths, scan.parquet_options, []) @@ -412,7 +414,7 @@ def test_streaming_scan_missing_prefetch_metadata_raises() -> None: def test_split_scan_do_evaluate_missing_prefetch_metadata() -> None: paths = ["/some/missing/file.parquet"] - parquet_options = ParquetOptions(prefetch_file_metadata=True) + parquet_options = ParquetOptions(prefetch_file_metadata="always") context = IRExecutionContext() schema = {"x": DataType(pl.Int64())} @@ -448,7 +450,7 @@ def test_prefetch_file_metadata_join( pl.DataFrame({"k": [1, 2, 3], "b": [7, 8, 9]}).write_parquet(p2) engine = streaming_engine_factory( - StreamingOptions(parquet_options={"prefetch_file_metadata": True}), + StreamingOptions(parquet_options={"prefetch_file_metadata": "always"}), ) q = pl.scan_parquet(p1).join(pl.scan_parquet(p2), on="k") @@ -483,7 +485,7 @@ def test_prefetch_file_metadata_with_cached_scan_parent_nodes( ).write_parquet(source) engine = streaming_engine_factory( - StreamingOptions(parquet_options={"prefetch_file_metadata": True}), + StreamingOptions(parquet_options={"prefetch_file_metadata": "always"}), ) cached_scan = pl.scan_parquet(source).cache() diff --git a/python/cudf_polars/tests/test_config.py b/python/cudf_polars/tests/test_config.py index fd184cf2f2c3..87d6e65c5ddb 100644 --- a/python/cudf_polars/tests/test_config.py +++ b/python/cudf_polars/tests/test_config.py @@ -4,6 +4,7 @@ from __future__ import annotations import dataclasses +import json from typing import cast import pytest @@ -36,7 +37,6 @@ MemoryResourceConfig, ParquetOptions, StreamingExecutor, - Unspecified, ) from cudf_polars.utils.cuda_stream import get_cuda_stream @@ -373,7 +373,7 @@ def test_parquet_options_from_env(monkeypatch: pytest.MonkeyPatch) -> None: m.setenv("CUDF_POLARS__PARQUET_OPTIONS__PASS_READ_LIMIT", "200") m.setenv("CUDF_POLARS__PARQUET_OPTIONS__MAX_FOOTER_SAMPLES", "0") m.setenv("CUDF_POLARS__PARQUET_OPTIONS__MAX_ROW_GROUP_SAMPLES", "0") - m.setenv("CUDF_POLARS__PARQUET_OPTIONS__PREFETCH_FILE_METADATA", "1") + m.setenv("CUDF_POLARS__PARQUET_OPTIONS__PREFETCH_FILE_METADATA", "always") m.setenv("CUDF_POLARS__PARQUET_OPTIONS__USE_JIT_FILTER", "1") # Test default @@ -385,15 +385,15 @@ def test_parquet_options_from_env(monkeypatch: pytest.MonkeyPatch) -> None: assert config.parquet_options.pass_read_limit == 200 assert config.parquet_options.max_footer_samples == 0 assert config.parquet_options.max_row_group_samples == 0 - assert config.parquet_options.prefetch_file_metadata is True + assert config.parquet_options.prefetch_file_metadata == "always" assert config.parquet_options.use_jit_filter is True with monkeypatch.context() as m: - # Env must win over the executor-derived default (streaming => True). - m.setenv("CUDF_POLARS__PARQUET_OPTIONS__PREFETCH_FILE_METADATA", "0") + # Env must win over the executor-derived default (streaming => "remote_only"). + m.setenv("CUDF_POLARS__PARQUET_OPTIONS__PREFETCH_FILE_METADATA", "never") engine = pl.GPUEngine(executor="streaming") config = ConfigOptions.from_polars_engine(engine) - assert config.parquet_options.prefetch_file_metadata is False + assert config.parquet_options.prefetch_file_metadata == "never" with monkeypatch.context() as m: m.setenv("CUDF_POLARS__PARQUET_OPTIONS__CHUNKED", "foo") @@ -402,6 +402,21 @@ def test_parquet_options_from_env(monkeypatch: pytest.MonkeyPatch) -> None: ConfigOptions.from_polars_engine(engine) +@pytest.mark.parametrize( + "env_value, expected", + [("1", "always"), ("true", "always"), ("0", "never"), ("false", "never")], +) +def test_prefetch_file_metadata_boolean_env_var( + monkeypatch: pytest.MonkeyPatch, env_value: str, expected: str +) -> None: + # Boolean-style values are accepted for backwards compatibility. + with monkeypatch.context() as m: + m.setenv("CUDF_POLARS__PARQUET_OPTIONS__PREFETCH_FILE_METADATA", env_value) + engine = pl.GPUEngine(executor="streaming") + config = ConfigOptions.from_polars_engine(engine) + assert config.parquet_options.prefetch_file_metadata == expected + + def test_config_option_from_env(monkeypatch: pytest.MonkeyPatch) -> None: with monkeypatch.context() as m: m.setenv("CUDF_POLARS__EXECUTOR__CLUSTER", "default_singleton") @@ -515,21 +530,22 @@ def test_validate_parquet_options(option: str) -> None: def test_prefetch_file_metadata_default() -> None: config = ConfigOptions.from_polars_engine(pl.GPUEngine(executor="streaming")) - assert isinstance(config.parquet_options.prefetch_file_metadata, Unspecified) + assert config.parquet_options.prefetch_file_metadata == "remote_only" config = ConfigOptions.from_polars_engine(pl.GPUEngine(executor="in-memory")) - assert config.parquet_options.prefetch_file_metadata is False + assert config.parquet_options.prefetch_file_metadata == "never" config = ConfigOptions.from_polars_engine( pl.GPUEngine( - executor="streaming", parquet_options={"prefetch_file_metadata": True} + executor="streaming", + parquet_options={"prefetch_file_metadata": "always"}, ) ) - assert config.parquet_options.prefetch_file_metadata is True + assert config.parquet_options.prefetch_file_metadata == "always" def test_parquet_options_object_passthrough() -> None: - parquet_options = ParquetOptions(prefetch_file_metadata=False) + parquet_options = ParquetOptions(prefetch_file_metadata="never") config = ConfigOptions.from_polars_engine( pl.GPUEngine(executor="streaming", parquet_options=parquet_options) ) @@ -541,27 +557,28 @@ def test_parquet_options_object_engine_default() -> None: # doesn't set prefetch_file_metadata on it, we still need to fill in the # right default for the chosen executor. parquet_options = ParquetOptions() - assert isinstance(parquet_options.prefetch_file_metadata, Unspecified) + assert parquet_options.prefetch_file_metadata == "remote_only" config = ConfigOptions.from_polars_engine( pl.GPUEngine(executor="in-memory", parquet_options=parquet_options) ) - assert config.parquet_options.prefetch_file_metadata is False + assert config.parquet_options.prefetch_file_metadata == "never" config = ConfigOptions.from_polars_engine( pl.GPUEngine(executor="streaming", parquet_options=parquet_options) ) - assert isinstance(config.parquet_options.prefetch_file_metadata, Unspecified) + assert config.parquet_options.prefetch_file_metadata == "remote_only" -def test_parquet_options_unspecified_dict_factory() -> None: +def test_parquet_options_prefetch_file_metadata_serializable() -> None: parquet_options = ParquetOptions() config = ConfigOptions.from_polars_engine( pl.GPUEngine(executor="streaming", parquet_options=parquet_options) ) - assert isinstance(config.parquet_options.prefetch_file_metadata, Unspecified) - result = dataclasses.asdict(config, dict_factory=ConfigOptions.dict_factory) - assert result["parquet_options"]["prefetch_file_metadata"] is None + assert config.parquet_options.prefetch_file_metadata == "remote_only" + result = dataclasses.asdict(config) + assert result["parquet_options"]["prefetch_file_metadata"] == "remote_only" + json.dumps(result) def test_validate_raise_on_fail() -> None: diff --git a/python/cudf_polars/tests/test_scan.py b/python/cudf_polars/tests/test_scan.py index b757892b455f..80ad001df957 100644 --- a/python/cudf_polars/tests/test_scan.py +++ b/python/cudf_polars/tests/test_scan.py @@ -179,14 +179,14 @@ def test_scan_parquet_prefetch_file_metadata_in_memory_raises(): ConfigOptions.from_polars_engine( pl.GPUEngine( executor="in-memory", - parquet_options=ParquetOptions(prefetch_file_metadata=True), + parquet_options=ParquetOptions(prefetch_file_metadata="always"), ) ) def test_scan_do_evaluate_missing_prefetch_metadata() -> None: paths = ["/some/missing/file.parquet"] - parquet_options = ParquetOptions(prefetch_file_metadata=True) + parquet_options = ParquetOptions(prefetch_file_metadata="always") context = IRExecutionContext() schema = {"a": DataType(pl.Int64())} diff --git a/python/cudf_polars/tests/test_select.py b/python/cudf_polars/tests/test_select.py index 07405d0d670e..f1e644c4d1b8 100644 --- a/python/cudf_polars/tests/test_select.py +++ b/python/cudf_polars/tests/test_select.py @@ -182,7 +182,7 @@ def test_get_parquet_row_count_from_metadata_no_cache_falls_back(tmp_path) -> No # rather than raising. source = tmp_path / "data.parquet" pl.DataFrame({"a": range(5)}).write_parquet(source) - parquet_options = ParquetOptions(prefetch_file_metadata=True) + parquet_options = ParquetOptions(prefetch_file_metadata="always") row_count = Scan._get_parquet_row_count_from_metadata( [str(source)], @@ -196,7 +196,7 @@ def test_get_parquet_row_count_from_metadata_no_cache_falls_back(tmp_path) -> No def test_get_parquet_row_count_from_metadata_path_mismatch_raises() -> None: paths = ["/some/missing/file.parquet"] - parquet_options = ParquetOptions(prefetch_file_metadata=True) + parquet_options = ParquetOptions(prefetch_file_metadata="always") with pytest.raises( AssertionError, From ba4d977ae509064d1184210cc377193e8581e1db Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Wed, 19 Aug 2026 12:21:37 +0000 Subject: [PATCH 2/3] code coverage --- python/cudf_polars/tests/test_config.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/python/cudf_polars/tests/test_config.py b/python/cudf_polars/tests/test_config.py index 87d6e65c5ddb..aef0af3bac91 100644 --- a/python/cudf_polars/tests/test_config.py +++ b/python/cudf_polars/tests/test_config.py @@ -417,6 +417,19 @@ def test_prefetch_file_metadata_boolean_env_var( assert config.parquet_options.prefetch_file_metadata == expected +def test_prefetch_file_metadata_invalid_env_var( + monkeypatch: pytest.MonkeyPatch, +) -> None: + with monkeypatch.context() as m: + m.setenv("CUDF_POLARS__PARQUET_OPTIONS__PREFETCH_FILE_METADATA", "foo") + engine = pl.GPUEngine(executor="streaming") + with pytest.raises( + ValueError, + match="Invalid value for prefetch_file_metadata: 'foo'", + ): + ConfigOptions.from_polars_engine(engine) + + def test_config_option_from_env(monkeypatch: pytest.MonkeyPatch) -> None: with monkeypatch.context() as m: m.setenv("CUDF_POLARS__EXECUTOR__CLUSTER", "default_singleton") From d5340ae3c5023648c174e1742504d37c133e4ba7 Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Fri, 21 Aug 2026 02:02:00 +0000 Subject: [PATCH 3/3] fix exception message --- python/cudf_polars/cudf_polars/utils/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/cudf_polars/cudf_polars/utils/config.py b/python/cudf_polars/cudf_polars/utils/config.py index daf2b276e59f..72b9e429d512 100644 --- a/python/cudf_polars/cudf_polars/utils/config.py +++ b/python/cudf_polars/cudf_polars/utils/config.py @@ -363,7 +363,7 @@ def __post_init__(self) -> None: # noqa: D105 raise TypeError("max_row_group_samples must be an int") if self.prefetch_file_metadata not in {"remote_only", "always", "never"}: raise TypeError( - "prefetch_file_metadata must be one of 'auto', 'always', 'never'" + "prefetch_file_metadata must be one of 'remote_only', 'always', 'never'" ) if not isinstance(self.use_jit_filter, bool): raise TypeError("use_jit_filter must be a bool")