Repository: narwhals-dev/narwhals
Pull request #2217 (2025-03-15 14:09:18)

chore: Deprecate `native_namespace` in favour of `backend` in `scan_parquet`
## What type of PR is this? (check all applicable)

- [ ] 💾 Refactor
- [ ] ✨ Feature
- [ ] 🐛 Bug Fix
- [ ] 🔧 Optimization
- [ ] 📝 Documentation
- [ ] ✅ Test
- [x] 🐳 Other

## Related issues

- Related issue #1888

## 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/narwhals/functions.py b/narwhals/functions.py
index 3d057eef..cb0ccf32 100644
--- a/narwhals/functions.py
+++ b/narwhals/functions.py
@@ -905,17 +905,31 @@ def _scan_csv_impl(
     return from_native(native_frame).lazy()
 
 
+@deprecate_native_namespace(warn_version="1.31.0", required=True)
 def read_parquet(
     source: str,
     *,
-    native_namespace: ModuleType,
+    backend: ModuleType | Implementation | str | None = None,
+    native_namespace: ModuleType | None = None,  # noqa: ARG001
     **kwargs: Any,
 ) -> DataFrame[Any]:
     """Read into a DataFrame from a parquet file.
 
     Arguments:
         source: Path to a file.
+        backend: The eager backend for DataFrame creation.
+            `backend` can be specified in various ways:
+
+            - As `Implementation.<BACKEND>` with `BACKEND` being `PANDAS`, `PYARROW`,
+                `POLARS`, `MODIN` or `CUDF`.
+            - As a string: `"pandas"`, `"pyarrow"`, `"polars"`, `"modin"` or `"cudf"`.
+            - Directly as a module `pandas`, `pyarrow`, `polars`, `modin` or `cudf`.
         native_namespace: The native library to use for DataFrame creation.
+
+            **Deprecated** (v1.31.0):
+                Please use `backend` instead. Note that `native_namespace` is still available
+                (and won't emit a deprecation warning) if you use `narwhals.stable.v1`,
+                see [perfect backwards compatibility policy](../backcompat.md/).
         kwargs: Extra keyword arguments which are passed to the native parquet reader.
             For example, you could use
             `nw.read_parquet('file.parquet', native_namespace=pd, engine='pyarrow')`.
@@ -927,7 +941,7 @@ def read_parquet(
         >>> import pyarrow as pa
         >>> import narwhals as nw
         >>>
-        >>> nw.read_parquet("file.parquet", native_namespace=pa)  # doctest:+SKIP
+        >>> nw.read_parquet("file.parquet", backend="pyarrow")  # doctest:+SKIP
         ┌──────────────────┐
         |Narwhals DataFrame|
         |------------------|
@@ -939,13 +953,15 @@ def read_parquet(
         |c: [[0.2,0.1]]    |
         └──────────────────┘
     """
-    return _read_parquet_impl(source, native_namespace=native_namespace, **kwargs)
+    backend = cast("ModuleType | Implementation | str", backend)
+    return _read_parquet_impl(source, backend=backend, **kwargs)
 
 
 def _read_parquet_impl(
-    source: str, *, native_namespace: ModuleType, **kwargs: Any
+    source: str, *, backend: ModuleType | Implementation | str, **kwargs: Any
 ) -> DataFrame[Any]:
-    implementation = Implementation.from_native_namespace(native_namespace)
+    implementation = Implementation.from_backend(backend)
+    native_namespace = implementation.to_native_namespace()
     native_frame: NativeFrame
     if implementation in {
         Implementation.POLARS,
@@ -970,8 +986,13 @@ def _read_parquet_impl(
     return from_native(native_frame, eager_only=True)
 
 
+@deprecate_native_namespace(warn_version="1.31.0", required=True)
 def scan_parquet(
-    source: str, *, native_namespace: ModuleType, **kwargs: Any
+    source: str,
+    *,
+    backend: ModuleType | Implementation | str | None = None,
+    native_namespace: ModuleType | None = None,  # noqa: ARG001
+    **kwargs: Any,
 ) -> LazyFrame[Any]:
     """Lazily read from a parquet file.
 
@@ -980,7 +1001,19 @@ def scan_parquet(
 
     Arguments:
         source: Path to a file.
+        backend: The eager backend for DataFrame creation.
+            `backend` can be specified in various ways:
+
+            - As `Implementation.<BACKEND>` with `BACKEND` being `PANDAS`, `PYARROW`,
+                `POLARS`, `MODIN` or `CUDF`.
+            - As a string: `"pandas"`, `"pyarrow"`, `"polars"`, `"modin"` or `"cudf"`.
+            - Directly as a module `pandas`, `pyarrow`, `polars`, `modin` or `cudf`.
         native_namespace: The native library to use for DataFrame creation.
+
+            **Deprecated** (v1.31.0):
+                Please use `backend` instead. Note that `native_namespace` is still available
+                (and won't emit a deprecation warning) if you use `narwhals.stable.v1`,
+                see [perfect backwards compatibility policy](../backcompat.md/).
         kwargs: Extra keyword arguments which are passed to the native parquet reader.
             For example, you could use
             `nw.scan_parquet('file.parquet', native_namespace=pd, engine='pyarrow')`.
@@ -992,9 +1025,7 @@ def scan_parquet(
         >>> import dask.dataframe as dd
         >>> import narwhals as nw
         >>>
-        >>> nw.scan_parquet(
-        ...     "file.parquet", native_namespace=dd
-        ... ).collect()  # doctest:+SKIP
+        >>> nw.scan_parquet("file.parquet", backend="dask").collect()  # doctest:+SKIP
         ┌──────────────────┐
         |Narwhals DataFrame|
         |------------------|
@@ -1003,13 +1034,15 @@ def scan_parquet(
         |     1  2   5     |
         └──────────────────┘
     """
-    return _scan_parquet_impl(source, native_namespace=native_namespace, **kwargs)
+    backend = cast("ModuleType | Implementation | str", backend)
+    return _scan_parquet_impl(source, backend=backend, **kwargs)
 
 
 def _scan_parquet_impl(
-    source: str, *, native_namespace: ModuleType, **kwargs: Any
+    source: str, *, backend: ModuleType | Implementation | str, **kwargs: Any
 ) -> LazyFrame[Any]:
-    implementation = Implementation.from_native_namespace(native_namespace)
+    implementation = Implementation.from_backend(backend)
+    native_namespace = implementation.to_native_namespace()
     native_frame: NativeFrame | NativeLazyFrame
     if implementation is Implementation.POLARS:
         native_frame = native_namespace.scan_parquet(source, **kwargs)
diff --git a/narwhals/stable/v1/__init__.py b/narwhals/stable/v1/__init__.py
index 8a636ae2..3ba0c88f 100644
--- a/narwhals/stable/v1/__init__.py
+++ b/narwhals/stable/v1/__init__.py
@@ -2382,14 +2382,31 @@ def scan_csv(
     )
 
 
+@deprecate_native_namespace(required=True)
 def read_parquet(
-    source: str, *, native_namespace: ModuleType, **kwargs: Any
+    source: str,
+    *,
+    backend: ModuleType | Implementation | str | None = None,
+    native_namespace: ModuleType | None = None,  # noqa: ARG001
+    **kwargs: Any,
 ) -> DataFrame[Any]:
     """Read into a DataFrame from a parquet file.
 
     Arguments:
         source: Path to a file.
+        backend: The eager backend for DataFrame creation.
+            `backend` can be specified in various ways:
+
+            - As `Implementation.<BACKEND>` with `BACKEND` being `PANDAS`, `PYARROW`,
+                `POLARS`, `MODIN` or `CUDF`.
+            - As a string: `"pandas"`, `"pyarrow"`, `"polars"`, `"modin"` or `"cudf"`.
+            - Directly as a module `pandas`, `pyarrow`, `polars`, `modin` or `cudf`.
         native_namespace: The native library to use for DataFrame creation.
+
+            **Deprecated** (v1.31.0):
+                Please use `backend` instead. Note that `native_namespace` is still available
+                (and won't emit a deprecation warning) if you use `narwhals.stable.v1`,
+                see [perfect backwards compatibility policy](../backcompat.md/).
         kwargs: Extra keyword arguments which are passed to the native parquet reader.
             For example, you could use
             `nw.read_parquet('file.parquet', native_namespace=pd, engine='pyarrow')`.
@@ -2397,13 +2414,19 @@ def read_parquet(
     Returns:
         DataFrame.
     """
+    backend = cast("ModuleType | Implementation | str", backend)
     return _stableify(  # type: ignore[no-any-return]
-        _read_parquet_impl(source, native_namespace=native_namespace, **kwargs)
+        _read_parquet_impl(source, backend=backend, **kwargs)
     )
 
 
+@deprecate_native_namespace(required=True)
 def scan_parquet(
-    source: str, *, native_namespace: ModuleType, **kwargs: Any
+    source: str,
+    *,
+    backend: ModuleType | Implementation | str | None = None,
+    native_namespace: ModuleType | None = None,  # noqa: ARG001
+    **kwargs: Any,
 ) -> LazyFrame[Any]:
     """Lazily read from a parquet file.
 
@@ -2412,7 +2435,19 @@ def scan_parquet(
 
     Arguments:
         source: Path to a file.
+        backend: The eager backend for DataFrame creation.
+            `backend` can be specified in various ways:
+
+            - As `Implementation.<BACKEND>` with `BACKEND` being `PANDAS`, `PYARROW`,
+                `POLARS`, `MODIN` or `CUDF`.
+            - As a string: `"pandas"`, `"pyarrow"`, `"polars"`, `"modin"` or `"cudf"`.
+            - Directly as a module `pandas`, `pyarrow`, `polars`, `modin` or `cudf`.
         native_namespace: The native library to use for DataFrame creation.
+
+            **Deprecated** (v1.31.0):
+                Please use `backend` instead. Note that `native_namespace` is still available
+                (and won't emit a deprecation warning) if you use `narwhals.stable.v1`,
+                see [perfect backwards compatibility policy](../backcompat.md/).
         kwargs: Extra keyword arguments which are passed to the native parquet reader.
             For example, you could use
             `nw.scan_parquet('file.parquet', native_namespace=pd, engine='pyarrow')`.
@@ -2420,8 +2455,9 @@ def scan_parquet(
     Returns:
         LazyFrame.
     """
+    backend = cast("ModuleType | Implementation | str", backend)
     return _stableify(  # type: ignore[no-any-return]
-        _scan_parquet_impl(source, native_namespace=native_namespace, **kwargs)
+        _scan_parquet_impl(source, backend=backend, **kwargs)
     )
 
 


Test patch:
diff --git a/tests/read_scan_test.py b/tests/read_scan_test.py
index 1f72250b..e6dc82f0 100644
--- a/tests/read_scan_test.py
+++ b/tests/read_scan_test.py
@@ -118,8 +118,8 @@ def test_read_parquet(
     filepath = str(tmpdir / "file.parquet")  # type: ignore[operator]
     df_pl.write_parquet(filepath)
     df = nw.from_native(constructor_eager(data))
-    native_namespace = nw.get_native_namespace(df)
-    result = nw.read_parquet(filepath, native_namespace=native_namespace)
+    backend = nw.get_native_namespace(df)
+    result = nw.read_parquet(filepath, backend=backend)
     assert_equal_data(result, data)
     assert isinstance(result, nw.DataFrame)
 
@@ -132,8 +132,8 @@ def test_read_parquet_v1(
     filepath = str(tmpdir / "file.parquet")  # type: ignore[operator]
     df_pl.write_parquet(filepath)
     df = nw_v1.from_native(constructor_eager(data))
-    native_namespace = nw_v1.get_native_namespace(df)
-    result = nw_v1.read_parquet(filepath, native_namespace=native_namespace)
+    backend = nw_v1.get_native_namespace(df)
+    result = nw_v1.read_parquet(filepath, backend=backend)
     assert_equal_data(result, data)
     assert isinstance(result, nw_v1.DataFrame)
 
@@ -143,7 +143,7 @@ def test_read_parquet_kwargs(tmpdir: pytest.TempdirFactory) -> None:
     df_pl = pl.DataFrame(data)
     filepath = str(tmpdir / "file.parquet")  # type: ignore[operator]
     df_pl.write_parquet(filepath)
-    result = nw.read_parquet(filepath, native_namespace=pd, engine="pyarrow")
+    result = nw.read_parquet(filepath, backend=pd, engine="pyarrow")
     assert_equal_data(result, data)
 
 
@@ -159,8 +159,8 @@ def test_scan_parquet(
     filepath = str(tmpdir / "file.parquet")  # type: ignore[operator]
     df_pl.write_parquet(filepath)
     df = nw.from_native(constructor(data))
-    native_namespace = nw.get_native_namespace(df)
-    result = nw.scan_parquet(filepath, native_namespace=native_namespace)
+    backend = nw.get_native_namespace(df)
+    result = nw.scan_parquet(filepath, backend=backend)
     assert_equal_data(result, data)
     assert isinstance(result, nw.LazyFrame)
 
@@ -177,8 +177,8 @@ def test_scan_parquet_v1(
     filepath = str(tmpdir / "file.parquet")  # type: ignore[operator]
     df_pl.write_parquet(filepath)
     df = nw_v1.from_native(constructor(data))
-    native_namespace = nw_v1.get_native_namespace(df)
-    result = nw_v1.scan_parquet(filepath, native_namespace=native_namespace)
+    backend = nw_v1.get_native_namespace(df)
+    result = nw_v1.scan_parquet(filepath, backend=backend)
     assert_equal_data(result, data)
     assert isinstance(result, nw_v1.LazyFrame)
 
@@ -188,5 +188,5 @@ def test_scan_parquet_kwargs(tmpdir: pytest.TempdirFactory) -> None:
     df_pl = pl.DataFrame(data)
     filepath = str(tmpdir / "file.parquet")  # type: ignore[operator]
     df_pl.write_parquet(filepath)
-    result = nw.scan_parquet(filepath, native_namespace=pd, engine="pyarrow")
+    result = nw.scan_parquet(filepath, backend=pd, engine="pyarrow")
     assert_equal_data(result, data)