Skip to content

Commit

Permalink
feat: add .select (by str) for duckdb and ibis
Browse files Browse the repository at this point in the history
  • Loading branch information
FBruzzesi committed Oct 28, 2024
1 parent c0a26be commit 8b35999
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
19 changes: 19 additions & 0 deletions narwhals/_duckdb/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,22 @@ def __getitem__(self, item: str) -> DuckDBInterchangeSeries:
self._native_frame.select(item), dtypes=self._dtypes
)

def select(
self: Self,
*exprs: Any,
**named_exprs: Any,
) -> Self:
if named_exprs or not all(isinstance(x, str) for x in exprs): # pragma: no cover
msg = (
"`select`-ing not by name is not supported for DuckDB backend.\n\n"
"If you would like to see this kind of object better supported in "
"Narwhals, please open a feature request "
"at https://github.com/narwhals-dev/narwhals/issues."
)
raise NotImplementedError(msg)

return self._from_native_frame(self._native_frame.select(*exprs))

def __getattr__(self, attr: str) -> Any:
if attr == "schema":
return {
Expand Down Expand Up @@ -120,3 +136,6 @@ def to_pandas(self: Self) -> pd.DataFrame:

def to_arrow(self: Self) -> pa.Table:
return self._native_frame.arrow()

def _from_native_frame(self: Self, df: Any) -> Self:
return self.__class__(df, dtypes=self._dtypes)
21 changes: 21 additions & 0 deletions narwhals/_ibis/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,24 @@ def to_pandas(self: Self) -> pd.DataFrame:
def to_arrow(self: Self) -> pa.Table:
return self._native_frame.to_pyarrow()

def select(
self: Self,
*exprs: Any,
**named_exprs: Any,
) -> Self:
if named_exprs or not all(isinstance(x, str) for x in exprs): # pragma: no cover
msg = (
"`select`-ing not by name is not supported for Ibis backend.\n\n"
"If you would like to see this kind of object better supported in "
"Narwhals, please open a feature request "
"at https://github.com/narwhals-dev/narwhals/issues."
)
raise NotImplementedError(msg)

import ibis.selectors as s

return self._from_native_frame(self._native_frame.select(s.cols(*exprs)))

def __getattr__(self, attr: str) -> Any:
if attr == "schema":
return {
Expand All @@ -98,3 +116,6 @@ def __getattr__(self, attr: str) -> Any:
"at https://github.com/narwhals-dev/narwhals/issues."
)
raise NotImplementedError(msg)

def _from_native_frame(self: Self, df: Any) -> Self:
return self.__class__(df, dtypes=self._dtypes)
46 changes: 46 additions & 0 deletions tests/frame/interchange_select_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from __future__ import annotations

import duckdb
import polars as pl
import pytest

import narwhals.stable.v1 as nw

data = {"a": [1, 2, 3], "b": [4.0, 5.0, 6.1], "z": ["x", "y", "z"]}


def test_interchange() -> None:
df_pl = pl.DataFrame(data)
df = nw.from_native(df_pl.__dataframe__(), eager_or_interchange_only=True)
with pytest.raises(
NotImplementedError,
match="Attribute select is not supported for metadata-only dataframes",
):
df.select("a", "z")


def test_interchange_ibis(
tmpdir: pytest.TempdirFactory,
) -> None: # pragma: no cover
ibis = pytest.importorskip("ibis")
df_pl = pl.DataFrame(data)

filepath = str(tmpdir / "file.parquet") # type: ignore[operator]
df_pl.write_parquet(filepath)

tbl = ibis.read_parquet(filepath)
df = nw.from_native(tbl, eager_or_interchange_only=True)

out_cols = df.select("a", "z").schema.names()

assert out_cols == ["a", "z"]


def test_interchange_duckdb() -> None:
df_pl = pl.DataFrame(data) # noqa: F841
rel = duckdb.sql("select * from df_pl")
df = nw.from_native(rel, eager_or_interchange_only=True)

out_cols = df.select("a", "z").schema.names()

assert out_cols == ["a", "z"]

0 comments on commit 8b35999

Please sign in to comment.