Skip to content

feat: notebook/Arrow interop, DataFrame ergonomics, and function breadth - #169

Open
lukekim wants to merge 3 commits into
trunkfrom
feat/audit-completion
Open

feat: notebook/Arrow interop, DataFrame ergonomics, and function breadth#169
lukekim wants to merge 3 commits into
trunkfrom
feat/audit-completion

Conversation

@lukekim

@lukekim lukekim commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Completes the remaining pure-SQL-client items from the DataFusion parity audit (following #167 and #168), in one PR. All function names were verified against DataFusion's documented function set before implementing.

Interop / display (the headline)

  • _repr_html_ — a SpiceDataFrame now renders a preview (first rows) as an HTML table in Jupyter/notebooks
  • __arrow_c_stream__ — exposes results via the Arrow C stream (PyCapsule) protocol, so Arrow-native consumers ingest a SpiceDataFrame directly:
    pa.table(df)            # or pa.RecordBatchReader.from_stream(df)
    pl.DataFrame(df)        # polars
    duckdb.sql("SELECT * FROM df")
  • df["a"] / df[["a", "b"]] — column selection via __getitem__
  • intersect(other, all=True) / except_(other, all=True)INTERSECT ALL / EXCEPT ALL

Function breadth (functions)

  • math: sin/cos/tan/asin/acos/atan/atan2, sinh/cosh/tanh/cot, log2, log10, cbrt, trunc, signum, pi, degrees, radians, gcd, lcm, factorial, nanvl, isnan, iszero
  • strings: ltrim/rtrim/btrim, lpad, rpad, initcap, left, right, reverse, repeat, translate, concat_ws, split_part, strpos, regexp_replace, ascii, chr, to_hex
  • date/time: to_timestamp, to_date, from_unixtime, to_unixtime, make_date, to_char
  • null: nvl

Explicitly deferred (and why)

Audit items I did not ship, because they can't be done correctly from the client alone or I couldn't verify them against a runtime — shipping them would risk runtime-failing SQL or dead code:

  • Flight do_put local-data ingestion — the biggest functional gap (today from_pandas inlines rows as VALUES), but it needs the Spice runtime to accept an uploaded ephemeral table. Requires runtime-side support + a live runtime to verify. Best as its own PR with runtime coordination.
  • Async client / execute_stream — a substantial transport change (async Flight); worth its own focused PR.
  • cosine_distance / dot_product / inner_product — native availability isn't confirmed across DataFusion versions (see Support array_dot_product/list_dot_product apache/datafusion#12475). array_distance (shipped in feat: array & struct support + DataFrame unnest / joins / describe #168) covers L2.
  • distinct_on / union_by_nameDISTINCT ON / UNION BY NAME support in the target runtime is unverified; deferred rather than emit uncertain SQL.

Testing

  • SQL-composition tests for every new function + the DataFrame methods (incl. an __arrow_c_stream__ round-trip through pa.RecordBatchReader.from_stream, and a _repr_html_ that asserts the preview uses a LIMIT query)
  • Full non-runtime gate green: 407 unit tests, ruff ✓, flake8 ✓, black ✓, mypy ✓ (3.11–3.14), pylint 9.24/10, bandit 0 issues

🤖 Generated with Claude Code

Completes the remaining pure-SQL-client items from the DataFusion parity
audit.

Interop / display (SpiceDataFrame):
- _repr_html_: render a preview (first rows) as an HTML table in notebooks
- __arrow_c_stream__: expose results via the Arrow C stream (PyCapsule)
  protocol, so pyarrow.table(df) / polars.DataFrame(df) / DuckDB can ingest
  a SpiceDataFrame directly
- __getitem__: column selection, df["a"] / df[["a", "b"]]
- intersect/except_ gain an `all` flag (INTERSECT ALL / EXCEPT ALL)

functions (names verified against DataFusion's function set):
- math: sin/cos/tan/asin/acos/atan/atan2, sinh/cosh/tanh/cot, log2, log10,
  cbrt, trunc, signum, pi, degrees, radians, gcd, lcm, factorial, nanvl,
  isnan, iszero
- strings: ltrim/rtrim/btrim, lpad, rpad, initcap, left, right, reverse,
  repeat, translate, concat_ws, split_part, strpos, regexp_replace, ascii,
  chr, to_hex
- date/time: to_timestamp, to_date, from_unixtime, to_unixtime, make_date,
  to_char
- null: nvl

Deferred (need runtime support or unverifiable — see PR description):
Flight do_put local-data ingestion, async client, cosine_distance/
dot_product, distinct_on/union_by_name.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Luke Kim <80174+lukekim@users.noreply.github.com>
Comment thread spicepy/_dataframe.py Fixed
@lukekim lukekim self-assigned this Jul 15, 2026
@lukekim lukekim added the enhancement New feature or request label Jul 15, 2026
Per code-quality review: SpiceDataFrame.__getitem__ should raise a
LookupError subclass for a bad key. Change the empty-list branch to
KeyError.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Luke Kim <80174+lukekim@users.noreply.github.com>

Copilot AI 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.

Pull request overview

Expands the SpicePy client-side SQL builder to improve notebook/Arrow interoperability and DataFrame ergonomics, while broadening the functions surface area to match more of DataFusion’s built-in function set.

Changes:

  • Add notebook/interop features to SpiceDataFrame (_repr_html_, __arrow_c_stream__, and df[...] column selection).
  • Extend set operations to support INTERSECT ALL / EXCEPT ALL.
  • Add many new SQL function wrappers across math/strings/datetime/null handling, with accompanying unit tests for a subset.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
spicepy/_dataframe.py Adds DataFrame interop/display helpers, column-selection indexing, and ALL variants for set ops.
spicepy/functions.py Introduces additional SQL function wrappers (math/string/datetime/null).
tests/test_dataframe.py Adds unit tests for new DataFrame behaviors (__getitem__, set-op all, HTML repr, Arrow C stream).
tests/test_functions.py Adds SQL-composition tests for some (but not all) newly added functions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread spicepy/_dataframe.py
Comment thread spicepy/functions.py
Comment thread tests/test_functions.py
- SpiceDataFrame.__getitem__ now validates that every element of a
  column-selection list is a str, raising TypeError early instead of a
  cryptic failure at SQL-render time.
- Add SQL-composition tests for the remaining new math/string/date
  functions (cos/tan/asin/acos/atan/sinh/cosh/tanh/cot, cbrt, radians,
  factorial, isnan, iszero, lcm, nanvl; ltrim/rtrim/btrim/rpad/right/
  repeat/translate/strpos/ascii/chr/to_hex; to_unixtime, to_char).

to_timestamp/to_date intentionally keep their variadic *formats:
DataFusion accepts multiple candidate Chrono formats and uses the first
that parses (mirrors datafusion-python's to_timestamp(arg, *formatters)).

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Luke Kim <80174+lukekim@users.noreply.github.com>
@lukekim
lukekim enabled auto-merge (squash) July 16, 2026 03:53
@lukekim
lukekim requested a review from sgrebnov July 26, 2026 01:04
@lukekim lukekim added this to the v4.0.0 milestone Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants