Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 0.1.5 instead.

narwhals-datafusion

CI PyPI version PEP 740 Downloads

Apache DataFusion backend for Narwhals, implemented as an out-of-tree plugin via the narwhals.plugins entry-point system.

Usage

import narwhals as nw
import pyarrow as pa
from datafusion import SessionContext

ctx = SessionContext()
df = ctx.from_arrow(pa.table({"a": [1, 2, 3], "b": ["x", "y", "x"]}))

lf = nw.from_native(df)  # -> nw.LazyFrame, dispatched to this plugin
result = (
    lf.group_by("b")
    .agg(nw.col("a").sum())
    .sort("b")
    .collect(backend="pyarrow")
)

Everything stays lazy until .collect(): narwhals expressions are translated to datafusion.Expr, frame verbs to datafusion.DataFrame methods, and the plan executes in DataFusion's Rust engine. Dtypes are pyarrow end-to-end.

Architecture

The backend sits on narwhals' shared SQL layer (narwhals._sql), the same abstraction DuckDB, Ibis, and Spark use. It subclasses narwhals' private internals (narwhals._sql, narwhals._compliant), so it is tested against one exact release, vendored as the narwhals/ git submodule (currently 2.25), and the dependency pins are floors only. The plugin provides:

Module Class
dataframe.py DataFusionLazyFrame — frame verbs over datafusion.DataFrame
expr.py DataFusionExpr — the six SQLExpr hooks + backend specifics
namespace.py DataFusionNamespace — the four SQLNamespace primitives, IO, horizontal fns
group_by.py, selectors.py, expr_str/dt/list/struct.py supporting surface
utils.py function-name remapping, window/sort builders, dtype bridge (delegates to narwhals._arrow)

mode, skew, kurtosis via datafusion-extra-functions

DataFusion core deliberately keeps its function library lean, so aggregates like mode/skewness/kurtosis live in the contrib datafusion-extra-functions crate (Rust-only, no wheel on PyPI). The datafusion-extra-functions-ffi package — a prebuilt wheel, installed through the extra-functions extra — exposes its aggregate UDFs to datafusion-python via the __datafusion_aggregate_udf__ PyCapsule protocol; they back Expr.mode, Expr.skew, and Expr.kurtosis:

pip install "narwhals-datafusion[extra-functions]"

Without the extra those three methods raise NotImplementedError and everything else works. The shim's FFI ABI is tied to the datafusion major it was compiled against (currently 54), which the wheel's own dependency pin enforces.

API coverage

Status of the narwhals public API on this backend (narwhals==2.25, datafusion==54). ⚠️ entries work with the caveat in parentheses; details in Known limitations.

Namespace ✅ Supported ⚠️ Partial ❌ Not supported
Expr abs alias all any any_value ceil clip cos count cum_count cum_max cum_min cum_sum diff exp fill_nan first floor is_between is_close is_duplicated is_finite is_first_distinct is_in is_last_distinct is_nan is_null is_unique last len log max mean median min null_count over pipe rank rolling_mean rolling_std rolling_sum rolling_var round shift sin sqrt std sum var cast (no Enum) · fill_null (no strategy + limit) · kurtosis ([extra-functions] extra) · mode ([extra-functions] extra, keep="any" only) · n_unique (not over windows) · replace_strict (explicit default required) · skew ([extra-functions] extra) cum_prod quantile
Expr.str contains ends_with head len_chars pad_end pad_start replace_all slice split starts_with strip_chars strip_chars_end strip_chars_start tail to_lowercase to_time to_uppercase zfill to_date/to_datetime (explicit format required) · to_titlecase (no word breaks on digits) replace (use replace_all)
Expr.dt convert_time_zone date day hour microsecond millisecond minute month nanosecond ordinal_day second to_string truncate weekday year replace_time_zone (None/"UTC" only) offset_by timestamp total_microseconds total_milliseconds total_minutes total_nanoseconds total_seconds
Expr.list contains get len max min sort unique (maintain_order=False only) mean median sum
Expr.struct field
LazyFrame collect collect_schema drop drop_nulls filter group_by head join rename select sort top_k unique unpivot with_columns with_row_index explode (single column) · sink_parquet (file path only) join_asof

Not listed: methods narwhals itself doesn't support on any lazy/SQL backend (Expr.filter, Expr.drop_nulls, Expr.unique, Expr.map_batches, Expr.ewm_mean, LazyFrame.tail, LazyFrame.gather_every).

Known limitations (as of datafusion 54)

  • join_asof, exact quantile, cum_prod, list.sum/mean/median, dt.total_*, dt.offset_by, dt.timestamp, str.replace, Enum casts — no engine support; raise NotImplementedError.
  • mode, skew, kurtosis need the extra-functions extra (see above); without it they raise NotImplementedError naming it.
  • n_unique().over(...) raises: DataFusion silently ignores DISTINCT inside window aggregates, which would return wrong results. (The same engine quirk drops ORDER BY/IGNORE NULLS declared inside window aggregates — this backend moves those modifiers onto the window itself.)
  • fill_null(strategy=..., limit=n) raises: bounded window frames with first_value/last_value need retract_batch, unimplemented engine-side.
  • replace_time_zone supports None (strip) and "UTC" only; use convert_time_zone for instant-preserving conversions.
  • str.to_datetime/to_date require an explicit format.
  • replace_strict requires an explicit default.
  • nw.scan_csv/nw.scan_parquet cannot dispatch to a plugin backend yet (narwhals gap); read with a DataFusion SessionContext and pass the frame to nw.from_native.
  • str.to_titlecase uses initcap, which doesn't break words on digits.
  • No row-order guarantees except after sort (standard for SQL engines): concat may interleave its inputs and backward fill_null may reorder rows. Sort explicitly when order matters.

Development

git submodule update --init      # narwhals, pinned to the targeted release
uv sync --group tests --extra extra-functions

See CONTRIBUTING.md for the full workflow.

Running narwhals' own test suite against this backend

The narwhals repo is vendored as a git submodule pinned to the targeted release:

git submodule update --init
uv run --group tests python run_tests.py    # known failures deselected

For the full, unfiltered run:

uv run --group tests pytest narwhals/tests -c narwhals/pyproject.toml \
    -p narwhals_datafusion.testing -p env --use-external-constructor

Regenerate the deselect list after fixing tests or bumping the submodule with uv run --group tests python update_run_tests.py.

Release files for narwhals-datafusion 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for narwhals-datafusion 0.1.2
File Size Uploaded
narwhals_datafusion-0.1.2.tar.gz 22.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for narwhals-datafusion 0.1.2
File Interpreter ABI Platform
narwhals_datafusion-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 51.3 kB

Release files / narwhals_datafusion-0.1.2.tar.gz

Download URL narwhals_datafusion-0.1.2.tar.gz
Size 22.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e392a13f804b3b2c0b64ff05e402b01b8c4818fb6457c19855d6b0ab86d88d27
BLAKE2b-256 checksum
How to use checksums
0594ddf6877a76f04bd025ce301d5f920a4a3bd20849ecae23f8da9f81697e07
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / narwhals_datafusion-0.1.2-py3-none-any.whl

Download URL narwhals_datafusion-0.1.2-py3-none-any.whl
Size 28.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3eecbaa0dfe22c4c142a18368ce5f6a7d998fd5b5f183573f328b13937bf4ffb
BLAKE2b-256 checksum
How to use checksums
75c266541b8d53fc7c4ba4b23d195c76d40afa81366e125971dc5c344ca297e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.5

2 release files

0.1.4

2 release files

This release

0.1.2 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page