Repository navigation
Arrow decoupling: openqvd-arrow crate, PyCapsule Table, abi3 - #54
Merged
Merged
Conversation
This was referenced Oct 25, 2026
…3; optional pyarrow
…olumn list; duckdb default connection; floors CI job; dependabot arrow majors; rust-version 1.88; clippy all-targets
Nathan-D-R
force-pushed
the
feat/arrow-decoupling
branch
from
October 25, 2026 13:16
6067d6f to
fe8b7f9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second PR of the final major round. Stacked on #53 (API foundation); the base is that branch and retargets to main when #53 merges.
A new Arrow major no longer forces a new openqvd major, on the Rust side or the Python side.
What changes
Rust
openqvdhas no Arrow dependency and noarrowfeature.Qvd::column(i) -> ColumnData(aColumnType, one converted value per distinct symbol, the symbol index of each row),Qvd::select_rows(&[Filter]),Filter,ColumnFilter.openqvd-arrow: featuresarrow-59andarrow-60, modulesopenqvd_arrow::v59/v60, built from one source file with renamed dependencies. Both can be enabled at once. A new Arrow major is a new feature plus one macro line. Each module hasto_record_batch(&Qvd, &BatchOptions),record_batch_to_write_tableandrecord_batches_to_write_table(all batches).Python
pyo3-arrowis gone. The extension implements the Arrow PyCapsule interface itself (__arrow_c_stream__,__arrow_c_schema__on export;__arrow_c_stream__and__arrow_c_array__on import). The Arrow dependency is private to the extension and never appears in a signature.openqvd.readreturnsopenqvd.Table:num_rows,column_names,warnings, the two capsule methods, and lazyto_pyarrow(),to_polars(),to_pandas().openqvd.writetakes anything that exports Arrow data.pyarrow,polars,pandas,duckdb). Floors were measured by running the suite against the minimums: pyarrow 15, Polars 1.10, pandas 2.2, DuckDB 1.2.pyo3featureabi3-py310); the PyPy classifier is dropped.Dependabot #38, #39, #40 (arrow-array / arrow-cast / arrow-schema 59 to 60)
Covered:
arrow-60is a feature ofopenqvd-arrow, and the Python extension builds against Arrow 60 directly (no pyo3-arrow, which is what made those PRs fail). All tests pass with 59 and 60 enabled together. I am closing the three with a pointer to this PR.API breaks (one commit each: core, arrow crate, Python)
Qvd::to_record_batch*andrecord_batch_to_write_tableat the crate root are removed in favor ofopenqvd-arrow;Filter/ColumnFilterbuilt withFilter::new;openqvd.readreturnsTable, notpyarrow.Table; pyarrow no longer installed by default. See CHANGELOG.Findings fixed here
writekept only the first batch): every batch is converted. Test:test_every_batch_is_written,every_batch_is_converted.filters_select_rows_by_symbol_index. The typed-value half (1.0vs1) follows in a later PR.ReadOptions::columnsisFieldNotDecoded, not an all-NULL column. Test:undecoded_column_is_an_error_not_nulls.Qvd::rows()still yieldsNonefor such fields (documented).Tests changed
test_core.pyreads through.to_pyarrow();test_duckdb.pyusesTable.column_names. New:tests/columns.rs,openqvd-arrow/tests/versions.rs(same suite per Arrow major),test_table.py.Corpus
Python read of all 1,145
.qvdfiles in /mnt/nas/data/QVD compared with the 2.0.0 gate run (Oct 20): 0 differences in status, row counts, Arrow types or per-column value hashes. 52 files error in both runs; only the text of the error differs. Rustvalidate_all: 1,044 ok, 3 known damaged fixtures. Nothing newly errors.Lenient mode
None added.
Loom
pl.from_arrow(openqvd.read(...))now returns a Series, not a DataFrame. Loom must switch totable.to_polars()orpl.DataFrame(table); its other uses keep working. Full list in the report.Docs-site and release-PR edits needed
docs/: Rust quickstart (openqvd-arrow,ColumnData), Python quickstart (Table, extras, floors), install page (abi3, no PyPy)..github/workflows/publish.yml: publishopenqvd-arrowafteropenqvd(cargo publish -p openqvd-arrow); drop--find-interpreterfrom the wheel build since wheels are abi3.RELEASING.md: three crates now share the version;crates/openqvd-arrowdependency line onopenqvd.ci.ymlneeds no change (--all-featuresbuilds both Arrow majors).Review fixes
Qvd::rows()yieldsErr(FieldNotDecoded)first and ends when any field is undecoded;to_write_table()errors up front (testrows_and_to_write_table_refuse_undecoded_columns). The text above that saysrows()still yieldsNoneis superseded.arrow-*majors and groups minors/patches.read(columns=[])returns a zero-column table with the row count (test_empty_column_list_gives_a_table_with_rows_and_no_columns).to_relation(path)withoutconuses DuckDB's default connection;view_nameneedscon. New CI jobpython-floorsinstalls pyarrow 15.0.0, polars 1.10.0, pandas 2.2.0, duckdb 1.2.0 on Ubuntu / Python 3.12 and runs pytest; clippy now runs with--all-targets. N9:rust-versionis 1.88.