Skip to content

feat(python): expose DataOverlay commit operation#7540

Merged
wjones127 merged 3 commits into
mainfrom
will/overlay-python-commit
Jul 15, 2026
Merged

feat(python): expose DataOverlay commit operation#7540
wjones127 merged 3 commits into
mainfrom
will/overlay-python-commit

Conversation

@wjones127

@wjones127 wjones127 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Exposes the DataOverlay commit operation to Python so overlays can be created and committed from Python (needed to benchmark and use data overlay files without dropping into Rust). Mirrors the existing DataReplacement binding.

What's here

  • LanceOperation.DataOverlay with DataOverlayFile and DataOverlayGroup. A DataOverlayFile carries the value DataFile plus exactly one of shared_offsets (dense coverage shared by every field) or field_offsets (sparse, one offset set per field). The commit stamps committed_version; passing both/neither coverage is rejected with a clear error.
  • PyO3 conversions (both directions) in python/src/transaction.rs.
  • Fills in the overlays field on the Python FragmentMetadata -> Fragment conversion, which OSS-1322 left unset (Python metadata doesn't carry overlays — they're committed via DataOverlay).

Tests

test_data_overlay_* in test_dataset.py: dense round-trip resolves on read; newest overlay wins; sparse per-field coverage resolves fields independently; and the exactly-one-coverage validation rejects both/neither.

Stacking

Stacked on #7536 (OSS-1324 read path) — base retargets automatically when it lands. Next PR (benchmarks) stacks on this.

Note: the python/src/fragment.rs one-liner arguably belongs in the OSS-1322 PR (#7535), which added Fragment.overlays without updating the binding; included here so the stack compiles.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added cell-level DataOverlay operations to append fragment overlays without rewriting entire fragments.
    • Supports dense and sparse overlays, with newest overlapping values taking precedence.
    • Persists overlay metadata on fragments and carries optional committed version stamps.
  • Bug Fixes
    • Preserves overlay metadata correctly through JSON serialization and Python↔Rust round-trips.
  • Tests
    • Added end-to-end coverage for dense/sparse overlays, precedence behavior, metadata round-tripping, and offset validation.
  • Documentation/Chores
    • Updated fragment metadata repr expectations and improved default max_bytes_per_file for fragment writing.

@github-actions github-actions Bot added A-python Python bindings enhancement New feature or request labels Jun 30, 2026
@wjones127
wjones127 force-pushed the will/overlay-python-commit branch from d1e3be6 to d1fa12b Compare June 30, 2026 23:12
@wjones127
wjones127 force-pushed the will/oss-1324-take-can-read-overlays branch from 3ba338b to a7d4508 Compare July 6, 2026 20:44
@wjones127
wjones127 force-pushed the will/overlay-python-commit branch from d1fa12b to 43cc06a Compare July 6, 2026 20:44
@wjones127
wjones127 force-pushed the will/oss-1324-take-can-read-overlays branch 3 times, most recently from a7cfcf0 to 72cc6d2 Compare July 8, 2026 17:13
@wjones127
wjones127 force-pushed the will/overlay-python-commit branch from 43cc06a to 91b3987 Compare July 8, 2026 18:40
Comment thread python/python/lance/dataset.py Outdated
Comment on lines +5993 to +5994
shared_offsets: Optional[List[int]] = None
field_offsets: Optional[List[List[int]]] = None

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

note: this could certainly be more efficient. I filed a follow up: #7695

Comment thread python/python/lance/dataset.py Outdated
Comment on lines +5993 to +5994
shared_offsets: Optional[List[int]] = None
field_offsets: Optional[List[List[int]]] = None

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

suggestion: it might be more pythonic if we had one field and accepted either type signature. Then we differentiate which it is based on the type.

@wjones127
wjones127 force-pushed the will/overlay-python-commit branch from 91b3987 to ecfb29c Compare July 8, 2026 22:13
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds cell-level data overlay operations, fragment metadata persistence, Python-Rust interoperability, and end-to-end coverage for dense, sparse, precedence, round-trip, and validation behavior.

Changes

Data Overlay Support

Layer / File(s) Summary
Overlay contracts and fragment metadata
python/python/lance/dataset.py, python/python/lance/fragment.py
Defines overlay files, groups, and operations; stores overlay metadata in fragment JSON; adds the default fragment file-size constant.
Rust overlay interoperability
python/src/transaction.rs, python/src/fragment.rs
Converts overlay coverage, groups, operations, and fragment metadata between Python and Rust.
Overlay behavior validation
python/python/tests/test_dataset.py, python/python/tests/test_fragment.py
Tests dense and sparse overlays, newest-wins precedence, metadata round trips, invalid offsets, and updated fragment metadata representation.

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

Sequence Diagram(s)

sequenceDiagram
  participant Dataset
  participant DataOverlay
  participant PyO3Bindings
  participant RustOperation
  participant FragmentMetadata
  Dataset->>DataOverlay: create overlay groups
  DataOverlay->>PyO3Bindings: convert groups and coverage
  PyO3Bindings->>RustOperation: construct DataOverlay operation
  RustOperation->>FragmentMetadata: preserve overlay metadata
  FragmentMetadata->>PyO3Bindings: serialize fragment overlays
  PyO3Bindings->>Dataset: reconstruct overlay metadata
Loading

Possibly related PRs

Suggested reviewers: xuanwo, yanghua, jackye1995

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: exposing the Python DataOverlay commit operation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch will/overlay-python-commit

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

@wjones127
wjones127 marked this pull request as ready for review July 8, 2026 22:48
@wjones127
wjones127 requested a review from westonpace July 8, 2026 22:48

@westonpace westonpace left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just some minor nits

Comment thread python/python/lance/dataset.py Outdated
Comment thread python/python/lance/dataset.py Outdated
Comment thread python/python/lance/dataset.py Outdated
Comment thread python/src/fragment.rs Outdated
Comment on lines +828 to +831
// Python's FragmentMetadata does not carry overlays; they are added
// to a fragment via the DataOverlay commit operation, not through
// fragment metadata round-trips.
overlays: Vec::new(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Wouldn't we still want it to round-trip? Most of our functions don't take Fragment as input so it's hard to come up with a good example.

Probably the only example I could think of would be a Merge operation. If I built a "deleting" Merge by taking a set of fragments and dropping one of them then the resulting commit would drop all the overlays from the fragments I keep too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've got it so it can roundtrip now.

wjones127 added a commit that referenced this pull request Jul 13, 2026
Addresses review feedback on #7540:

- Reword the DataOverlayFile/DataOverlay docstrings: offset "list" not "set",
  drop the redundant "no row-offset key column" note, and clarify that the
  latest group wins when multiple groups target the same data.
- Round-trip a fragment's overlays through FragmentMetadata so operations that
  pass existing fragments back (a manual Delete/Update/Merge commit) no longer
  silently drop them. FragmentMetadata gains an `overlays` field wired through
  to_json/from_json and both PyO3 conversions; DataOverlayFile gains
  `committed_version` (None on commit input, populated on read) so overlay
  precedence survives the round-trip.

Adds test_data_overlay_round_trips_through_fragment_metadata covering the
metadata, JSON, and commit round-trips.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wjones127
wjones127 force-pushed the will/oss-1324-take-can-read-overlays branch from 4bb5e39 to 5ff87ce Compare July 13, 2026 19:54
Base automatically changed from will/oss-1324-take-can-read-overlays to main July 15, 2026 17:35
@github-actions

Copy link
Copy Markdown
Contributor

Important

This PR touches the Lance format specification.

Substantive changes to the format specification — the .proto definitions
and the spec docs under docs/src/format/ — require a PMC vote before merge.
Minor edits such as typo fixes, wording, or formatting are excluded; use your
judgment.

If this is a meaningful format change:

  • Start a vote following the Lance community voting process.
    Format specification modifications need 3 binding +1 votes (excluding the
    proposer), held on GitHub Discussions, with a minimum voting period of 1 week.
  • Once the vote passes, link the completed vote in this PR. It should not be
    merged until the vote is linked.

wjones127 and others added 2 commits July 15, 2026 12:40
Adds LanceOperation.DataOverlay (with DataOverlayFile and DataOverlayGroup)
so Python can commit data overlay files, mirroring the existing
DataReplacement binding. A DataOverlayFile carries the value DataFile plus
exactly one of shared_offsets (dense coverage) or field_offsets (sparse,
per-field coverage); the commit stamps committed_version.

Also fills in the overlays field on the Python FragmentMetadata ->
Fragment conversion, which OSS-1322 left unset (overlays are committed via
DataOverlay, not carried through fragment metadata).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses review feedback on #7540:

- Reword the DataOverlayFile/DataOverlay docstrings: offset "list" not "set",
  drop the redundant "no row-offset key column" note, and clarify that the
  latest group wins when multiple groups target the same data.
- Round-trip a fragment's overlays through FragmentMetadata so operations that
  pass existing fragments back (a manual Delete/Update/Merge commit) no longer
  silently drop them. FragmentMetadata gains an `overlays` field wired through
  to_json/from_json and both PyO3 conversions; DataOverlayFile gains
  `committed_version` (None on commit input, populated on read) so overlay
  precedence survives the round-trip.

Adds test_data_overlay_round_trips_through_fragment_metadata covering the
metadata, JSON, and commit round-trips.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wjones127
wjones127 force-pushed the will/overlay-python-commit branch from 6d52845 to 968d024 Compare July 15, 2026 19:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@python/src/transaction.rs`:
- Around line 210-249: The PyLance<DataOverlayFile>::extract implementation must
reject unsorted offsets before constructing OverlayCoverage, rather than
allowing RoaringBitmap::from_iter to reorder them. Validate that the dense
offsets list and every sparse per-field list are strictly ascending, return a
clear ValueError on failure, and preserve the existing dense/sparse parsing
behavior otherwise. The corresponding dataset.py site requires no direct change;
it is covered by this Rust-side validation.
🪄 Autofix (Beta)

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: ASSERTIVE

Plan: Pro Plus

Run ID: 0c7ed629-7e5b-4d27-bb03-c03381753098

📥 Commits

Reviewing files that changed from the base of the PR and between 9effdb1 and 968d024.

📒 Files selected for processing (5)
  • python/python/lance/dataset.py
  • python/python/lance/fragment.py
  • python/python/tests/test_dataset.py
  • python/src/fragment.rs
  • python/src/transaction.rs

Comment thread python/src/transaction.rs
The overlay `offsets` list maps positionally to value rows in `data_file`,
but `RoaringBitmap::from_iter` silently sorts and dedups the offsets, so a
non-ascending or duplicated list would corrupt that mapping without error.
Validate that each dense/sparse offset list is strictly ascending and raise
a clear ValueError otherwise. A proper RoaringBitmap Python binding (#7695)
will supersede this.

Also update `test_fragment_meta` to expect the new `overlays=[]` field in the
`FragmentMetadata` repr, which was failing Python CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (2)
python/python/lance/dataset.py (1)

5994-6062: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add examples and API links for the new public overlay operations.

DataOverlayFile, DataOverlayGroup, and DataOverlay are public APIs but lack usage examples and links to related types or LanceDataset.commit.

As per coding guidelines, “Document all public APIs with examples and links to relevant structs and methods.”

🤖 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/python/lance/dataset.py` around lines 5994 - 6062, Add documentation
examples and cross-references to the public APIs DataOverlayFile,
DataOverlayGroup, and DataOverlay. Show how to construct and use overlay
operations, link related types such as DataFile and FragmentMetadata, and
reference LanceDataset.commit for applying DataOverlay, while preserving the
existing attribute and behavior descriptions.

Source: Coding guidelines

python/src/transaction.rs (1)

234-247: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Report out-of-range offsets as a value error. offsets=[-1] and values above u32::MAX fall through both extraction branches and end up with the generic “must be a list of ints” message. Reject them with a bounds-specific error and add coverage for those cases.

🤖 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/src/transaction.rs` around lines 234 - 247, Update the offsets parsing
flow around the dense and sparse `offsets.extract` branches to detect integer
offsets outside the u32 range and return a PyValueError with a bounds-specific
message instead of the generic type error. Preserve valid dense and sparse
coverage handling, and add tests covering negative offsets and values above
u32::MAX.

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/python/lance/dataset.py`:
- Around line 5994-6062: Add documentation examples and cross-references to the
public APIs DataOverlayFile, DataOverlayGroup, and DataOverlay. Show how to
construct and use overlay operations, link related types such as DataFile and
FragmentMetadata, and reference LanceDataset.commit for applying DataOverlay,
while preserving the existing attribute and behavior descriptions.

In `@python/src/transaction.rs`:
- Around line 234-247: Update the offsets parsing flow around the dense and
sparse `offsets.extract` branches to detect integer offsets outside the u32
range and return a PyValueError with a bounds-specific message instead of the
generic type error. Preserve valid dense and sparse coverage handling, and add
tests covering negative offsets and values above u32::MAX.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1afbc6a3-a664-4ce5-91d1-6167dff20438

📥 Commits

Reviewing files that changed from the base of the PR and between 968d024 and de8c63c.

📒 Files selected for processing (4)
  • python/python/lance/dataset.py
  • python/python/tests/test_dataset.py
  • python/python/tests/test_fragment.py
  • python/src/transaction.rs

@wjones127
wjones127 merged commit 9681621 into main Jul 15, 2026
18 checks passed
@wjones127
wjones127 deleted the will/overlay-python-commit branch July 15, 2026 23:01
wjones127 added a commit that referenced this pull request Jul 21, 2026
… API

`DataOverlayFile` takes a single `offsets` param, not `shared_offsets`, and
the release-build opt-in env var is `LANCE_ENABLE_UNSTABLE_DATA_OVERLAY_FILES`
(not `LANCE_ENABLE_DATA_OVERLAY_FILES`). Both diverged from the benchmark
helper after PR #7540 landed the real Python bindings; commit()'s returned
handle skipped flag validation so this only surfaced on a fresh dataset open.
wjones127 added a commit that referenced this pull request Jul 21, 2026
Exposes the `DataOverlay` commit operation to Python so overlays can be
created and committed from Python (needed to benchmark and use data
overlay files without dropping into Rust). Mirrors the existing
`DataReplacement` binding.

## What's here
- `LanceOperation.DataOverlay` with `DataOverlayFile` and
`DataOverlayGroup`. A `DataOverlayFile` carries the value `DataFile`
plus **exactly one** of `shared_offsets` (dense coverage shared by every
field) or `field_offsets` (sparse, one offset set per field). The commit
stamps `committed_version`; passing both/neither coverage is rejected
with a clear error.
- PyO3 conversions (both directions) in `python/src/transaction.rs`.
- Fills in the `overlays` field on the Python `FragmentMetadata ->
Fragment` conversion, which OSS-1322 left unset (Python metadata doesn't
carry overlays — they're committed via `DataOverlay`).

## Tests
`test_data_overlay_*` in `test_dataset.py`: dense round-trip resolves on
read; newest overlay wins; sparse per-field coverage resolves fields
independently; and the exactly-one-coverage validation rejects
both/neither.

## Stacking
Stacked on **#7536** (OSS-1324 read path) — base retargets automatically
when it lands. Next PR (benchmarks) stacks on this.

> Note: the `python/src/fragment.rs` one-liner arguably belongs in the
OSS-1322 PR (#7535), which added `Fragment.overlays` without updating
the binding; included here so the stack compiles.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added cell-level `DataOverlay` operations to append fragment overlays
without rewriting entire fragments.
- Supports dense and sparse overlays, with newest overlapping values
taking precedence.
- Persists overlay metadata on fragments and carries optional committed
version stamps.
- **Bug Fixes**
- Preserves overlay metadata correctly through JSON serialization and
Python↔Rust round-trips.
- **Tests**
- Added end-to-end coverage for dense/sparse overlays, precedence
behavior, metadata round-tripping, and offset validation.
- **Documentation/Chores**
- Updated fragment metadata `repr` expectations and improved default
`max_bytes_per_file` for fragment writing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9681621)
wjones127 added a commit that referenced this pull request Jul 23, 2026
… API

`DataOverlayFile` takes a single `offsets` param, not `shared_offsets`, and
the release-build opt-in env var is `LANCE_ENABLE_UNSTABLE_DATA_OVERLAY_FILES`
(not `LANCE_ENABLE_DATA_OVERLAY_FILES`). Both diverged from the benchmark
helper after PR #7540 landed the real Python bindings; commit()'s returned
handle skipped flag validation so this only surfaced on a fresh dataset open.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-python Python bindings enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants