Skip to content

Preview an exploration result without converting the whole frame - #2058

Merged
ghostiee-11 merged 5 commits into
mainfrom
feat/sql-source-dataframe-backend
Aug 27, 2026
Merged

Preview an exploration result without converting the whole frame#2058
ghostiee-11 merged 5 commits into
mainfrom
feat/sql-source-dataframe-backend

Conversation

@ghostiee-11

Copy link
Copy Markdown
Collaborator

The exploration SQL tool read its result through execute, which is contracted to return pandas, so a source set to build polars or pyarrow paid for a full copy of the result before the model saw five rows of it. It reads through fetch now and converts only the cells it renders, taking a 5M row preview from 1.09s and 468MB to 0.48s and 70MB.

Fixes #2041

numpy has no decimal and no date, so both sit in an object column, and the
summary reads an object column as categorical: a money column loses its
mean and range and comes out as an enum of decimal.Decimal, which
yaml.safe_load cannot read back at all.

Cast both to the types numpy does have before the summary. Inferred from
the values rather than the source dtype, because pandas produces such a
column for a DECIMAL result of its own, so this is not only about frames
arriving from another dataframe library.
BaseSQLSource gains a dataframe_backend param and a fetch method that get
reads through, so the data path can hand back polars or pyarrow while
execute stays on pandas for the schema and metadata queries, which read
results with .iloc and pandas dtypes. DuckDB and DataFusion build the
requested frame themselves rather than converting a pandas one: on a 5M row
DuckDB table that takes the fetch from 857ms and 566MB to 229ms and 73MB
for arrow, and 628ms and 358MB for polars.

Nothing changes by default, since to_backend returns the frame it was given
when no backend is named. A geometry result stays pandas whatever is asked
for, because geometry only survives as a GeoDataFrame and narwhals has no
geometry dtype, so any other library would hold the column as opaque bytes
and drop it from the schema. The consumers that were not already behind an
as_pandas boundary are guarded: the layout download writers, the AI export
and docx table, the DuckDB mirrors, the source preview and
result_to_dataframe.
fetch_arrow_table is deprecated in duckdb 1.5 and the suite turns that
warning into an error, while to_arrow_table does not exist on a connection
before 1.5. arrow() is present throughout, but answers with a Table up to
1.3 and a RecordBatchReader from 1.4, and Pipeline.data rejects the reader,
so the result goes through pa.table either way. Verified against 1.2, 1.3,
1.4 and 1.5.
execute_exploration_sql read through execute, which is contracted to return
pandas, so a source set to build polars or pyarrow paid for a full copy of
the result before the model saw five rows of it. It reads through fetch now,
and format_exploration_result takes a frame from any library: the shape and
the column names come off the frame itself, and only the cells actually
rendered are converted.

Dates and decimals are normalised on the way out. Both land in an object
column, which the dtype line reports as str, and which of the two arrives
varies by library, since pandas converts a DECIMAL to float itself while
polars and pyarrow keep it. That normaliser is named for what it does now
rather than for its first caller, since the summary path is no longer the
only one using it.
sanitize_column_names copied the whole frame to relabel its columns. rename
gives the same columns and the same isolation from the caller's frame, and
skips the copy outright on a pandas that has copy-on-write. Covers the
helper, which had no tests.
@codecov

codecov Bot commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.54140% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.75%. Comparing base (ef07729) to head (362752c).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
lumen/tests/sources/test_duckdb.py 92.15% 4 Missing ⚠️
lumen/ai/agents/sql.py 86.66% 2 Missing ⚠️
lumen/tests/sources/test_base.py 88.23% 2 Missing ⚠️
lumen/ui/sources.py 0.00% 2 Missing ⚠️
lumen/ai/utils.py 92.85% 1 Missing ⚠️
lumen/layout.py 50.00% 1 Missing ⚠️
lumen/sources/bigquery.py 0.00% 1 Missing ⚠️
lumen/sources/snowflake.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2058      +/-   ##
==========================================
+ Coverage   75.24%   75.75%   +0.50%     
==========================================
  Files         212      214       +2     
  Lines       39182    39965     +783     
==========================================
+ Hits        29484    30276     +792     
+ Misses       9698     9689       -9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ghostiee-11
ghostiee-11 merged commit bffaca2 into main Aug 27, 2026
14 checks passed
@ghostiee-11
ghostiee-11 deleted the feat/sql-source-dataframe-backend branch August 27, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

describe_data and the other AI description helpers still run on pandas

2 participants