Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add native property and deprecate .to_native() method #1301

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api-reference/dataframe.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- join
- join_asof
- lazy
- native
- null_count
- pipe
- rename
Expand Down
1 change: 1 addition & 0 deletions docs/api-reference/lazyframe.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- join_asof
- lazy
- pipe
- native
- rename
- schema
- select
Expand Down
1 change: 1 addition & 0 deletions docs/api-reference/series.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- min
- mode
- name
- native
- n_unique
- null_count
- pipe
Expand Down
2 changes: 1 addition & 1 deletion docs/basics/dataframe_conversion.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Similarly, if your library uses Polars internally, you can convert any user-supp

```python exec="1" source="above" session="conversion" result="python"
def df_to_polars(df: IntoDataFrame) -> pl.DataFrame:
return nw.from_arrow(nw.from_native(df), native_namespace=pl).to_native()
return nw.from_arrow(nw.from_native(df), native_namespace=pl).native


print(df_to_polars(df_duckdb)) # You can only execute this line of code once.
Expand Down
123 changes: 110 additions & 13 deletions narwhals/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
from typing import Sequence
from typing import TypeVar
from typing import overload
from warnings import warn

from narwhals.dependencies import get_polars
from narwhals.dependencies import is_numpy_array
from narwhals.schema import Schema
from narwhals.translate import to_native
from narwhals.utils import flatten
from narwhals.utils import is_sequence_but_not_str
from narwhals.utils import parse_version
Expand Down Expand Up @@ -328,6 +328,54 @@ def _series(self) -> type[Series]:
def _lazyframe(self) -> type[LazyFrame[Any]]:
return LazyFrame

@property
def native(self: Self) -> DataFrameT:
"""
Convert Narwhals DataFrame to native one.

Returns:
Object of class that user started with.

Examples:
>>> import pandas as pd
>>> import polars as pl
>>> import pyarrow as pa
>>> import narwhals as nw
>>> data = {"foo": [1, 2, 3], "bar": [6.0, 7.0, 8.0], "ham": ["a", "b", "c"]}
>>> df_pd = pd.DataFrame(data)
>>> df_pl = pl.DataFrame(data)
>>> df_pa = pa.table(data)

Calling `.native` on a Narwhals DataFrame returns the native object:

>>> nw.from_native(df_pd).native
foo bar ham
0 1 6.0 a
1 2 7.0 b
2 3 8.0 c
>>> nw.from_native(df_pl).native
shape: (3, 3)
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
β”‚ foo ┆ bar ┆ ham β”‚
β”‚ --- ┆ --- ┆ --- β”‚
β”‚ i64 ┆ f64 ┆ str β”‚
β•žβ•β•β•β•β•β•ͺ═════β•ͺ═════║
β”‚ 1 ┆ 6.0 ┆ a β”‚
β”‚ 2 ┆ 7.0 ┆ b β”‚
β”‚ 3 ┆ 8.0 ┆ c β”‚
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
>>> nw.from_native(df_pa).native
pyarrow.Table
foo: int64
bar: double
ham: string
----
foo: [[1,2,3]]
bar: [[6,7,8]]
ham: [["a","b","c"]]
"""
return self._compliant_frame._native_frame # type: ignore[no-any-return]

def __init__(
self,
df: Any,
Expand Down Expand Up @@ -430,7 +478,7 @@ def lazy(self) -> LazyFrame[Any]:
"""
return self._lazyframe(self._compliant_frame.lazy(), level=self._level)

def to_native(self) -> DataFrameT:
def to_native(self: Self) -> DataFrameT:
"""
Convert Narwhals DataFrame to native one.

Expand All @@ -449,12 +497,12 @@ def to_native(self) -> DataFrameT:

Calling `to_native` on a Narwhals DataFrame returns the native object:

>>> nw.from_native(df_pd).to_native()
>>> nw.from_native(df_pd).to_native() # doctest:+SKIP
foo bar ham
0 1 6.0 a
1 2 7.0 b
2 3 8.0 c
>>> nw.from_native(df_pl).to_native()
>>> nw.from_native(df_pl).to_native() # doctest:+SKIP
shape: (3, 3)
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
β”‚ foo ┆ bar ┆ ham β”‚
Expand All @@ -465,7 +513,7 @@ def to_native(self) -> DataFrameT:
β”‚ 2 ┆ 7.0 ┆ b β”‚
β”‚ 3 ┆ 8.0 ┆ c β”‚
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
>>> nw.from_native(df_pa).to_native()
>>> nw.from_native(df_pa).to_native() # doctest:+SKIP
pyarrow.Table
foo: int64
bar: double
Expand All @@ -475,8 +523,13 @@ def to_native(self) -> DataFrameT:
bar: [[6,7,8]]
ham: [["a","b","c"]]
"""

return self._compliant_frame._native_frame # type: ignore[no-any-return]
warn(
"Use `.native` property instead. `.to_native()` is "
"deprecated and it will be removed in future versions",
DeprecationWarning,
stacklevel=2,
)
return self.native

def to_pandas(self) -> pd.DataFrame:
"""
Expand Down Expand Up @@ -2765,6 +2818,45 @@ class LazyFrame(BaseFrame[FrameT]):
def _dataframe(self) -> type[DataFrame[Any]]:
return DataFrame

@property
def native(self: Self) -> FrameT:
"""
Convert Narwhals LazyFrame to native one.

Returns:
Object of class that user started with.

Examples:
>>> import pandas as pd
>>> import polars as pl
>>> import pyarrow as pa
>>> import narwhals as nw
>>> data = {"foo": [1, 2, 3], "bar": [6.0, 7.0, 8.0], "ham": ["a", "b", "c"]}
>>> df_pd = pd.DataFrame(data)
>>> df_pl = pl.LazyFrame(data)
>>> df_pa = pa.table(data)

Calling `.native` on a Narwhals DataFrame returns the native object:

>>> nw.from_native(df_pd).lazy().native
foo bar ham
0 1 6.0 a
1 2 7.0 b
2 3 8.0 c
>>> nw.from_native(df_pl).native.collect()
shape: (3, 3)
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
β”‚ foo ┆ bar ┆ ham β”‚
β”‚ --- ┆ --- ┆ --- β”‚
β”‚ i64 ┆ f64 ┆ str β”‚
β•žβ•β•β•β•β•β•ͺ═════β•ͺ═════║
β”‚ 1 ┆ 6.0 ┆ a β”‚
β”‚ 2 ┆ 7.0 ┆ b β”‚
β”‚ 3 ┆ 8.0 ┆ c β”‚
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
"""
return self._compliant_frame._native_frame # type: ignore[no-any-return]

def __init__(
self,
df: Any,
Expand Down Expand Up @@ -2820,7 +2912,7 @@ def collect(self) -> DataFrame[Any]:
| Use `.to_native` to see native output |
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
>>> df = lf.group_by("a").agg(nw.all().sum()).collect()
>>> df.to_native().sort("a")
>>> df.native.sort("a")
shape: (3, 3)
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
β”‚ a ┆ b ┆ c β”‚
Expand All @@ -2837,7 +2929,7 @@ def collect(self) -> DataFrame[Any]:
level=self._level,
)

def to_native(self) -> FrameT:
def to_native(self: Self) -> FrameT:
"""
Convert Narwhals LazyFrame to native one.

Expand All @@ -2856,12 +2948,12 @@ def to_native(self) -> FrameT:

Calling `to_native` on a Narwhals DataFrame returns the native object:

>>> nw.from_native(df_pd).lazy().to_native()
>>> nw.from_native(df_pd).lazy().to_native() # doctest:+SKIP
foo bar ham
0 1 6.0 a
1 2 7.0 b
2 3 8.0 c
>>> nw.from_native(df_pl).to_native().collect()
>>> nw.from_native(df_pl).to_native().collect() # doctest:+SKIP
shape: (3, 3)
β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
β”‚ foo ┆ bar ┆ ham β”‚
Expand All @@ -2873,8 +2965,13 @@ def to_native(self) -> FrameT:
β”‚ 3 ┆ 8.0 ┆ c β”‚
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
"""

return to_native(narwhals_object=self, strict=True)
warn(
"Use `.native` property instead. `.to_native()` is "
"deprecated and it will be removed in future versions",
DeprecationWarning,
stacklevel=2,
)
return self.native

# inherited
def pipe(self, function: Callable[[Any], Self], *args: Any, **kwargs: Any) -> Self:
Expand Down
55 changes: 51 additions & 4 deletions narwhals/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from typing import Sequence
from typing import TypeVar
from typing import overload
from warnings import warn

from narwhals.utils import parse_version

Expand Down Expand Up @@ -41,6 +42,46 @@ def _dataframe(self) -> type[DataFrame[Any]]:

return DataFrame

@property
def native(self: Self) -> Any:
"""
Convert Narwhals series to native series.

Returns:
Series of class that user started with.

Examples:
>>> import pandas as pd
>>> import polars as pl
>>> import narwhals as nw
>>> s = [1, 2, 3]
>>> s_pd = pd.Series(s)
>>> s_pl = pl.Series(s)

We define a library agnostic function:

>>> @nw.narwhalify
... def func(s):
... return s.native

We can then pass either pandas or Polars to `func`:

>>> func(s_pd)
0 1
1 2
2 3
dtype: int64
>>> func(s_pl) # doctest: +NORMALIZE_WHITESPACE
shape: (3,)
Series: '' [i64]
[
1
2
3
]
"""
return self._compliant_series._native_series

def __init__(
self: Self,
series: Any,
Expand Down Expand Up @@ -97,7 +138,7 @@ def __arrow_c_stream__(self, requested_schema: object | None = None) -> object:
ca = pa.chunked_array([self.to_arrow()])
return ca.__arrow_c_stream__(requested_schema=requested_schema)

def to_native(self) -> Any:
def to_native(self: Self) -> Any:
"""
Convert Narwhals series to native series.

Expand All @@ -120,12 +161,12 @@ def to_native(self) -> Any:

We can then pass either pandas or Polars to `func`:

>>> func(s_pd)
>>> func(s_pd) # doctest:+SKIP
0 1
1 2
2 3
dtype: int64
>>> func(s_pl) # doctest: +NORMALIZE_WHITESPACE
>>> func(s_pl) # doctest:+SKIP
shape: (3,)
Series: '' [i64]
[
Expand All @@ -134,7 +175,13 @@ def to_native(self) -> Any:
3
]
"""
return self._compliant_series._native_series
warn(
"Use `.native` property instead. `.to_native()` is "
"deprecated and it will be removed in future versions",
DeprecationWarning,
stacklevel=2,
)
return self.native

def scatter(self, indices: int | Sequence[int], values: Any) -> Self:
"""
Expand Down
Loading
Loading