Skip to content

Add pylibcudf bindings for fetch_byte_ranges_to_device - #23543

Open
Matt711 wants to merge 16 commits into
NVIDIA:mainfrom
Matt711:fea/pylibcudf/fetch-byte-ranges
Open

Add pylibcudf bindings for fetch_byte_ranges_to_device#23543
Matt711 wants to merge 16 commits into
NVIDIA:mainfrom
Matt711:fea/pylibcudf/fetch-byte-ranges

Conversation

@Matt711

@Matt711 Matt711 commented Aug 4, 2026

Copy link
Copy Markdown
Member

Description

Adds a sync wrapper for fetch_byte_ranges_to_device. Because the way it's used #23317, we get no benefit from resolving the futures later in cudf-polars.

Depends on #23541

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@Matt711 Matt711 added feature request New feature or request non-breaking Non-breaking change labels Aug 4, 2026
@copy-pr-bot

copy-pr-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@Matt711 Matt711 changed the title Add pylibcudf bindings for fetch_byte_ranges_to_device Add pylibcudf bindings for fetch_byte_ranges_to_device Aug 4, 2026
@github-actions github-actions Bot added libcudf Affects libcudf (C++/CUDA) code. Python Affects Python cuDF API. CMake CMake build issue pylibcudf Issues specific to the pylibcudf package labels Aug 4, 2026
@GPUtester GPUtester moved this to In Progress in cuDF Python Aug 4, 2026
@Matt711

Matt711 commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

/ok to test eab58d0

@Matt711
Matt711 marked this pull request as ready for review August 12, 2026 20:58
@Matt711
Matt711 requested review from a team as code owners August 12, 2026 20:58
@Matt711
Matt711 requested review from shrshi and vyasr August 12, 2026 20:58
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0dff6a34-0617-498d-8749-19fe3eab5bbe

📥 Commits

Reviewing files that changed from the base of the PR and between 3dd055e and 53df649.

📒 Files selected for processing (2)
  • python/pylibcudf/pylibcudf/libcudf/io/datasource.pxd
  • python/pylibcudf/pylibcudf/libcudf/utilities/span.pxd
🚧 Files skipped from review as they are similar to previous changes (1)
  • python/pylibcudf/pylibcudf/libcudf/io/datasource.pxd

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added Python-accessible Parquet I/O utilities for fetching byte ranges to device memory and page-index data to host memory.
    • Added optional CUDA stream and device memory resource support for device transfers.
  • Bug Fixes
    • Invalid, negative, or out-of-bounds byte ranges now raise errors instead of proceeding with I/O.
  • Documentation
    • Added API documentation for the Parquet I/O utilities and improved a metadata cross-reference.

Walkthrough

The PR adds pylibcudf bindings for Parquet byte-range and page-index fetching. It validates invalid device byte ranges before allocation, adds test coverage, and exposes the module through builds, exports, and API documentation.

Changes

Parquet I/O bindings

Layer / File(s) Summary
Native range validation and tests
cpp/src/io/parquet/io_utils/parquet_io_utils.cpp, cpp/tests/io/experimental/hybrid_scan_filters_test.cpp
Device byte-range loading rejects negative and out-of-bounds ranges. Tests cover invalid ranges and a boundary-valid range.
Cython API and type declarations
python/pylibcudf/pylibcudf/io/parquet_io_utils.*, python/pylibcudf/pylibcudf/libcudf/io/*.pxd, python/pylibcudf/pylibcudf/libcudf/utilities/span.pxd
New APIs fetch device byte ranges as owning gpumemoryview objects and page-index ranges as Python bytes.
Package and documentation integration
python/pylibcudf/pylibcudf/io/CMakeLists.txt, python/pylibcudf/pylibcudf/io/__init__.py, docs/cudf/source/pylibcudf/api_docs/io/*, python/pylibcudf/pylibcudf/io/parquet_metadata.pyx
The module is built, exported, documented, and referenced with a fully qualified API name.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Mergeability Score: 🔵 Low · up to 53df6

The new span bindings may not fully match the underlying C++ API for const spans, which could limit valid calls or cause compatibility issues. This is a localized, mergeable risk with explicit owner follow-up to verify the declarations.

Possibly related PRs

  • NVIDIA/cudf#23643: Introduces annotation and typing conventions used by the new Parquet I/O APIs.

Suggested reviewers: vyasr, shrshi

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding pylibcudf bindings for fetch_byte_ranges_to_device.
Description check ✅ Passed The description explains the synchronous wrapper and its intended cudf-polars use, which matches the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (2)
python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx (1)

66-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the additional failure modes.

The Raises section lists only the single-source ValueError. The native layer now rejects negative and out-of-bounds byte ranges, so invalid byte_ranges also raise. Add that case so callers know both validation paths.

As per path instructions, "Completeness: Check if API changes (parameters, return values, errors) are documented".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx` around lines 66 - 70,
Update the Raises documentation for the relevant parquet I/O utility to include
ValueError when byte_ranges contains negative or out-of-bounds ranges, while
retaining the existing source_info validation case.

Source: Path instructions

python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd (1)

41-47: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Use libcudf_exception_handler for the shim declaration.

Line 47 declares except +. Line 55 declares except +libcudf_exception_handler. The shim calls fetch_byte_ranges_to_device_async and fut.get(), so libcudf exceptions can propagate through it. With plain except +, cudf::logic_error and cudf::cuda_error are translated to generic Python exceptions instead of the cuDF-specific types.

♻️ Proposed change
     pair[vector[device_buffer], vector[device_span[const_uint8_t]]] \
         cpp_fetch_byte_ranges_to_device(
             datasource& source,
             host_span[const_byte_range_info] byte_ranges,
             cuda_stream_view stream,
             device_async_resource_ref mr,
-        ) except +
+        ) except +libcudf_exception_handler

Based on learnings, "Exceptions not handled correctly across Python/C++ boundary (missing +libcudf_exception_handler if not noexcept)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd` around lines 41 -
47, Update the cpp_fetch_byte_ranges_to_device shim declaration to use the
libcudf_exception_handler exception policy instead of plain except +, matching
the adjacent shim declaration and preserving cuDF-specific exception
translation.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/tests/io/experimental/hybrid_scan_filters_test.cpp`:
- Around line 1777-1800: Extend FetchByteRangesInvalidRanges with an
EXPECT_THROW case using a negative byte_range_info size, and add a valid fetch
case whose range ends exactly at byte 1024. Preserve the existing invalid offset
and out-of-bounds end checks while verifying the boundary-ending range is
accepted.

In `@docs/cudf/source/pylibcudf/api_docs/io/index.rst`:
- Line 20: Update the toctree entry in the IO API documentation from
experimental to ../experimental/index.rst, referencing the sibling experimental
document rather than a path under the IO directory.

In `@docs/cudf/source/pylibcudf/api_docs/io/parquet_io_utils.rst`:
- Around line 5-6: Update the module docstring in parquet_io_utils.pyx to change
“IO utilities for the Parquet.” to “IO utilities for Parquet.”, leaving the
automodule directive unchanged.

In `@python/pylibcudf/pylibcudf/io/parquet_io_utils.pxd`:
- Around line 8-18: Update the declaration of fetch_byte_ranges_to_device to use
except +libcudf_exception_handler instead of the generic except +, matching the
throwing cpp_fetch_byte_ranges_to_device wrapper. Leave the existing
synchronization and buffer ownership behavior unchanged.

In `@python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx`:
- Around line 142-151: Update the page-index retrieval flow after the nogil
block to check whether buf is null before accessing data() or size(), and raise
the appropriate Python exception for an empty buffer. Remove the redundant
move() wrapper around cpp_fetch_page_index_to_host while preserving the existing
conversion to bytes for valid buffers.
- Around line 94-108: Update the result-building logic around
cpp_fetch_byte_ranges_to_device to handle empty fetched.first safely, retain
every returned device_buffer with a separate owner, and associate each span in
fetched.second with its owning buffer before calculating offsets. Use the owning
buffer’s base pointer for each gpumemoryview.byte_slice; if exactly one buffer
is guaranteed, validate that assumption explicitly before indexing.

In `@python/pylibcudf/pylibcudf/libcudf/io/datasource.pxd`:
- Around line 15-17: Update the `buffer` declarations in the Cython `cppclass`
to match `datasource::buffer`: make both `data()` and `size()` const-qualified,
remove `noexcept`, and add `except +libcudf_exception_handler` while importing
the exception handler for translation.

In `@python/pylibcudf/pylibcudf/libcudf/utilities/span.pxd`:
- Line 18: Update the device_span declarations in span.pxd to use size_t for the
constructor’s size parameter and size() return type, and mark both data() and
size() as const noexcept. Remove the int32_t sizing declaration to preserve
Python buffer sizes beyond INT32_MAX and align with cuda::std::span.

---

Nitpick comments:
In `@python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx`:
- Around line 66-70: Update the Raises documentation for the relevant parquet
I/O utility to include ValueError when byte_ranges contains negative or
out-of-bounds ranges, while retaining the existing source_info validation case.

In `@python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd`:
- Around line 41-47: Update the cpp_fetch_byte_ranges_to_device shim declaration
to use the libcudf_exception_handler exception policy instead of plain except +,
matching the adjacent shim declaration and preserving cuDF-specific exception
translation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a394cc51-3b44-41ab-a4b2-979f46837654

📥 Commits

Reviewing files that changed from the base of the PR and between 40ba83d and 09c4ad3.

📒 Files selected for processing (13)
  • cpp/src/io/parquet/io_utils/parquet_io_utils.cpp
  • cpp/tests/io/experimental/hybrid_scan_filters_test.cpp
  • docs/cudf/source/pylibcudf/api_docs/io/index.rst
  • docs/cudf/source/pylibcudf/api_docs/io/parquet_io_utils.rst
  • python/pylibcudf/pylibcudf/io/CMakeLists.txt
  • python/pylibcudf/pylibcudf/io/__init__.py
  • python/pylibcudf/pylibcudf/io/parquet_io_utils.pxd
  • python/pylibcudf/pylibcudf/io/parquet_io_utils.pyi
  • python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx
  • python/pylibcudf/pylibcudf/io/parquet_metadata.pyx
  • python/pylibcudf/pylibcudf/libcudf/io/datasource.pxd
  • python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd
  • python/pylibcudf/pylibcudf/libcudf/utilities/span.pxd

Comment thread cpp/tests/io/experimental/hybrid_scan_filters_test.cpp
Comment thread docs/cudf/source/pylibcudf/api_docs/io/index.rst Outdated
Comment thread docs/cudf/source/pylibcudf/api_docs/io/parquet_io_utils.rst
Comment thread python/pylibcudf/pylibcudf/io/parquet_io_utils.pxd
Comment thread python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx
Comment thread python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx
Comment thread python/pylibcudf/pylibcudf/libcudf/io/datasource.pxd
Comment thread python/pylibcudf/pylibcudf/libcudf/utilities/span.pxd Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd (1)

21-47: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add Python tests and a benchmark for the new Parquet utility bindings.

Cover multiple and empty ranges, invalid ranges, exception propagation, page-index results, and gpumemoryview lifetime. Add a benchmark for fetch_byte_ranges_to_device and its synchronous fut.get() path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd` around lines 21 -
47, Add Python tests and a benchmark for the `cpp_fetch_byte_ranges_to_device`
binding, covering multiple ranges, empty ranges, invalid ranges, exception
propagation, page-index results, and `gpumemoryview` lifetime. Benchmark both
`fetch_byte_ranges_to_device` and the synchronous `fut.get()` path, reusing
existing Parquet test and benchmark utilities where available.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd`:
- Around line 21-47: Add Python tests and a benchmark for the
`cpp_fetch_byte_ranges_to_device` binding, covering multiple ranges, empty
ranges, invalid ranges, exception propagation, page-index results, and
`gpumemoryview` lifetime. Benchmark both `fetch_byte_ranges_to_device` and the
synchronous `fut.get()` path, reusing existing Parquet test and benchmark
utilities where available.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6400a10d-1544-4260-8f95-219afe4efd37

📥 Commits

Reviewing files that changed from the base of the PR and between 09c4ad3 and 3dd055e.

📒 Files selected for processing (6)
  • cpp/tests/io/experimental/hybrid_scan_filters_test.cpp
  • docs/cudf/source/pylibcudf/api_docs/io/index.rst
  • python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx
  • python/pylibcudf/pylibcudf/libcudf/io/datasource.pxd
  • python/pylibcudf/pylibcudf/libcudf/io/parquet_io_utils.pxd
  • python/pylibcudf/pylibcudf/libcudf/utilities/span.pxd
🚧 Files skipped from review as they are similar to previous changes (4)
  • docs/cudf/source/pylibcudf/api_docs/io/index.rst
  • python/pylibcudf/pylibcudf/libcudf/io/datasource.pxd
  • cpp/tests/io/experimental/hybrid_scan_filters_test.cpp
  • python/pylibcudf/pylibcudf/io/parquet_io_utils.pyx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CMake CMake build issue feature request New feature or request libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change pylibcudf Issues specific to the pylibcudf package Python Affects Python cuDF API.

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants