Skip to content

Commit

Permalink
fix: add native_namespace to interchange level of support (#1172)
Browse files Browse the repository at this point in the history
  • Loading branch information
FBruzzesi authored Oct 14, 2024
1 parent 25df02f commit 2e7afa5
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 0 deletions.
6 changes: 6 additions & 0 deletions narwhals/_duckdb/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
from typing import TYPE_CHECKING
from typing import Any

from narwhals.dependencies import get_duckdb
from narwhals.utils import parse_version

if TYPE_CHECKING:
from types import ModuleType

import pandas as pd
import pyarrow as pa
from typing_extensions import Self
Expand Down Expand Up @@ -68,6 +71,9 @@ def __init__(self, df: Any, dtypes: DTypes) -> None:
def __narwhals_dataframe__(self) -> Any:
return self

def __native_namespace__(self: Self) -> ModuleType:
return get_duckdb() # type: ignore[no-any-return]

def __getitem__(self, item: str) -> DuckDBInterchangeSeries:
from narwhals._duckdb.series import DuckDBInterchangeSeries

Expand Down
6 changes: 6 additions & 0 deletions narwhals/_duckdb/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
from typing import Any

from narwhals._duckdb.dataframe import map_duckdb_dtype_to_narwhals_dtype
from narwhals.dependencies import get_duckdb

if TYPE_CHECKING:
from types import ModuleType

from narwhals.typing import DTypes


Expand All @@ -17,6 +20,9 @@ def __init__(self, df: Any, dtypes: DTypes) -> None:
def __narwhals_series__(self) -> Any:
return self

def __native_namespace__(self) -> ModuleType:
return get_duckdb() # type: ignore[no-any-return]

def __getattr__(self, attr: str) -> Any:
if attr == "dtype":
return map_duckdb_dtype_to_narwhals_dtype(
Expand Down
7 changes: 7 additions & 0 deletions narwhals/_ibis/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
from typing import TYPE_CHECKING
from typing import Any

from narwhals.dependencies import get_ibis

if TYPE_CHECKING:
from types import ModuleType

import pandas as pd
import pyarrow as pa
from typing_extensions import Self
Expand Down Expand Up @@ -59,6 +63,9 @@ def __init__(self, df: Any, dtypes: DTypes) -> None:
def __narwhals_dataframe__(self) -> Any:
return self

def __native_namespace__(self: Self) -> ModuleType:
return get_ibis() # type: ignore[no-any-return]

def __getitem__(self, item: str) -> IbisInterchangeSeries:
from narwhals._ibis.series import IbisInterchangeSeries

Expand Down
6 changes: 6 additions & 0 deletions narwhals/_ibis/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
from typing import Any

from narwhals._ibis.dataframe import map_ibis_dtype_to_narwhals_dtype
from narwhals.dependencies import get_ibis

if TYPE_CHECKING:
from types import ModuleType

from narwhals.typing import DTypes


Expand All @@ -17,6 +20,9 @@ def __init__(self, df: Any, dtypes: DTypes) -> None:
def __narwhals_series__(self) -> Any:
return self

def __native_namespace__(self) -> ModuleType:
return get_ibis() # type: ignore[no-any-return]

def __getattr__(self, attr: str) -> Any:
if attr == "dtype":
return map_ibis_dtype_to_narwhals_dtype(
Expand Down
8 changes: 8 additions & 0 deletions narwhals/_interchange/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ def __init__(self, df: Any, dtypes: DTypes) -> None:
def __narwhals_dataframe__(self) -> Any:
return self

def __native_namespace__(self: Self) -> NoReturn:
msg = (
"Cannot access native namespace for metadata-only dataframes with unknown backend."
"If you would like to see this kind of object supported in Narwhals, please "
"open a feature request at https://github.com/narwhals-dev/narwhals/issues."
)
raise NotImplementedError(msg)

def __getitem__(self, item: str) -> InterchangeSeries:
from narwhals._interchange.series import InterchangeSeries

Expand Down
9 changes: 9 additions & 0 deletions narwhals/_interchange/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from typing import TYPE_CHECKING
from typing import Any
from typing import NoReturn

from narwhals._interchange.dataframe import map_interchange_dtype_to_narwhals_dtype

Expand All @@ -17,6 +18,14 @@ def __init__(self, df: Any, dtypes: DTypes) -> None:
def __narwhals_series__(self) -> Any:
return self

def __native_namespace__(self) -> NoReturn:
msg = (
"Cannot access native namespace for metadata-only series with unknown backend. "
"If you would like to see this kind of object supported in Narwhals, please "
"open a feature request at https://github.com/narwhals-dev/narwhals/issues."
)
raise NotImplementedError(msg)

def __getattr__(self, attr: str) -> Any:
if attr == "dtype":
return map_interchange_dtype_to_narwhals_dtype(
Expand Down
52 changes: 52 additions & 0 deletions tests/frame/interchange_native_namespace_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import duckdb
import polars as pl
import pytest

import narwhals.stable.v1 as nw

data = {"a": [1, 2, 3], "b": [4.5, 6.7, 8.9], "z": ["x", "y", "w"]}


def test_interchange() -> None:
df_pl = pl.DataFrame(data)
df = nw.from_native(df_pl.__dataframe__(), eager_or_interchange_only=True)
series = df["a"]

with pytest.raises(
NotImplementedError,
match="Cannot access native namespace for metadata-only dataframes with unknown backend",
):
df.__native_namespace__()

with pytest.raises(
NotImplementedError,
match="Cannot access native namespace for metadata-only series with unknown backend",
):
series.__native_namespace__()


def test_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)
series = df["a"]

assert df.__native_namespace__() == ibis
assert series.__native_namespace__() == ibis


def test_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)
series = df["a"]

assert df.__native_namespace__() == duckdb
assert series.__native_namespace__() == duckdb

0 comments on commit 2e7afa5

Please sign in to comment.