Repository: narwhals-dev/narwhals
Pull request #1025 (2024-09-20 13:18:38)

Implementing to_native in lazyframe
<!--
# Thanks for contributing a pull request! 
## Please make sure you see our contribution guidelines: https://github.com/narwhals-dev/narwhals/blob/main/CONTRIBUTING.md
-->

## What type of PR is this? (check all applicable)

- [ ] 💾 Refactor
- [ ] ✨ Feature
- [ ] 🐛 Bug Fix
- [x] 🔧 Optimization
- [ ] 📝 Documentation
- [ ] ✅ Test
- [ ] 🐳 Other

## Related issues 

- Related issue # 
- Closes #

## Checklist

- [x] Code follows style guide (ruff)
- [x] Tests added 
- [x] Documented the changes

## If you have comments or can explain your changes, please do so below.




Patch:
diff --git a/docs/api-reference/lazyframe.md b/docs/api-reference/lazyframe.md
index 5d472bab..89a8282a 100644
--- a/docs/api-reference/lazyframe.md
+++ b/docs/api-reference/lazyframe.md
@@ -23,6 +23,7 @@
         - select
         - sort
         - tail
+        - to_native
         - unique
         - with_columns
         - with_row_index
diff --git a/narwhals/dataframe.py b/narwhals/dataframe.py
index 2a7a94cf..83ebdcdc 100644
--- a/narwhals/dataframe.py
+++ b/narwhals/dataframe.py
@@ -14,6 +14,7 @@ from typing import overload
 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
@@ -319,14 +320,14 @@ class DataFrame(BaseFrame[FrameT]):
         return self._compliant_frame.__array__(dtype, copy=copy)
 
     def __repr__(self) -> str:  # pragma: no cover
-        header = " Narwhals DataFrame                            "
+        header = " Narwhals DataFrame                    "
         length = len(header)
         return (
             "┌"
             + "─" * length
             + "┐\n"
             + f"|{header}|\n"
-            + "| Use `narwhals.to_native` to see native output |\n"
+            + "| Use `.to_native` to see native output |\n"
             + "└"
             + "─" * length
             + "┘"
@@ -2640,14 +2641,14 @@ class LazyFrame(BaseFrame[FrameT]):
             raise AssertionError(msg)
 
     def __repr__(self) -> str:  # pragma: no cover
-        header = " Narwhals LazyFrame                            "
+        header = " Narwhals LazyFrame                    "
         length = len(header)
         return (
             "┌"
             + "─" * length
             + "┐\n"
             + f"|{header}|\n"
-            + "| Use `narwhals.to_native` to see native output |\n"
+            + "| Use `.to_native` to see native output |\n"
             + "└"
             + "─" * length
             + "┘"
@@ -2676,12 +2677,12 @@ class LazyFrame(BaseFrame[FrameT]):
             ... )
             >>> lf = nw.from_native(lf_pl)
             >>> lf
-            ┌───────────────────────────────────────────────┐
-            | Narwhals LazyFrame                            |
-            | Use `narwhals.to_native` to see native output |
-            └───────────────────────────────────────────────┘
+            ┌───────────────────────────────────────┐
+            | Narwhals LazyFrame                    |
+            | Use `.to_native` to see native output |
+            └───────────────────────────────────────┘
             >>> df = lf.group_by("a").agg(nw.all().sum()).collect()
-            >>> nw.to_native(df).sort("a")
+            >>> df.to_native().sort("a")
             shape: (3, 3)
             ┌─────┬─────┬─────┐
             │ a   ┆ b   ┆ c   │
@@ -2698,6 +2699,45 @@ class LazyFrame(BaseFrame[FrameT]):
             level=self._level,
         )
 
+    def to_native(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 `to_native` on a Narwhals DataFrame returns the native object:
+
+            >>> nw.from_native(df_pd).lazy().to_native()
+               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()
+            shape: (3, 3)
+            ┌─────┬─────┬─────┐
+            │ foo ┆ bar ┆ ham │
+            │ --- ┆ --- ┆ --- │
+            │ i64 ┆ f64 ┆ str │
+            ╞═════╪═════╪═════╡
+            │ 1   ┆ 6.0 ┆ a   │
+            │ 2   ┆ 7.0 ┆ b   │
+            │ 3   ┆ 8.0 ┆ c   │
+            └─────┴─────┴─────┘
+        """
+
+        return to_native(narwhals_object=self, strict=True)
+
     # inherited
     def pipe(self, function: Callable[[Any], Self], *args: Any, **kwargs: Any) -> Self:
         """
diff --git a/narwhals/stable/v1.py b/narwhals/stable/v1.py
index 676b30f2..0f34c88f 100644
--- a/narwhals/stable/v1.py
+++ b/narwhals/stable/v1.py
@@ -322,12 +322,12 @@ class LazyFrame(NwLazyFrame[IntoFrameT]):
             ... )
             >>> lf = nw.from_native(lf_pl)
             >>> lf
-            ┌───────────────────────────────────────────────┐
-            | Narwhals LazyFrame                            |
-            | Use `narwhals.to_native` to see native output |
-            └───────────────────────────────────────────────┘
+            ┌───────────────────────────────────────┐
+            | Narwhals LazyFrame                    |
+            | Use `.to_native` to see native output |
+            └───────────────────────────────────────┘
             >>> df = lf.group_by("a").agg(nw.all().sum()).collect()
-            >>> nw.to_native(df).sort("a")
+            >>> df.to_native().sort("a")
             shape: (3, 3)
             ┌─────┬─────┬─────┐
             │ a   ┆ b   ┆ c   │
diff --git a/utils/generate_backend_completeness.py b/utils/generate_backend_completeness.py
index 1d6ee417..7f2e23ca 100644
--- a/utils/generate_backend_completeness.py
+++ b/utils/generate_backend_completeness.py
@@ -53,8 +53,10 @@ def parse_module(module_name: str, backend: str, nw_class_name: str) -> list[str
             predicate=lambda c: inspect.isclass(c) and c.__name__.endswith(nw_class_name),
         )
         methods_ = (
-            get_class_methods(class_[0][1]) if class_ else []
-        ) + DIRECTLY_IMPLEMENTED_METHODS
+            get_class_methods(class_[0][1]) + DIRECTLY_IMPLEMENTED_METHODS
+            if class_
+            else []
+        )
 
     except ModuleNotFoundError:
         methods_ = []


Test patch:
diff --git a/tests/frame/to_native_test.py b/tests/frame/to_native_test.py
index 236403e2..d8f4132b 100644
--- a/tests/frame/to_native_test.py
+++ b/tests/frame/to_native_test.py
@@ -3,9 +3,9 @@ from typing import Any
 import narwhals.stable.v1 as nw
 
 
-def test_to_native(constructor_eager: Any) -> None:
+def test_to_native(constructor: Any) -> None:
     data = {"a": [1, 3, 2], "b": [4, 4, 6], "z": [7.1, 8, 9]}
-    df_raw = constructor_eager(data)
-    df = nw.from_native(df_raw, eager_only=True)
+    df_raw = constructor(data)
+    df = nw.from_native(df_raw)
 
     assert isinstance(df.to_native(), df_raw.__class__)