Repository: narwhals-dev/narwhals
Pull request #2677 (2025-06-13 13:16:24)

chore: Remove unused utility functions
## What type of PR is this? (check all applicable)

- [x] 💾 Refactor
- [ ] ✨ Feature
- [ ] 🐛 Bug Fix
- [ ] 🔧 Optimization
- [ ] 📝 Documentation
- [ ] ✅ Test
- [ ] 🐳 Other


## If you have comments or can explain your changes, please do so below

While working on something else I spotted this 🤷🏼‍♀️


Patch:
diff --git a/docs/api-reference/expr.md b/docs/api-reference/expr.md
index 834497a3..f278bc3b 100644
--- a/docs/api-reference/expr.md
+++ b/docs/api-reference/expr.md
@@ -36,6 +36,7 @@
         - is_nan
         - is_null
         - is_unique
+        - kurtosis
         - len
         - log
         - map_batches
@@ -60,6 +61,7 @@
         - shift
         - sort
         - skew
+        - sqrt
         - std
         - sum
         - tail
diff --git a/docs/api-reference/series.md b/docs/api-reference/series.md
index abe3f3e4..040548cc 100644
--- a/docs/api-reference/series.md
+++ b/docs/api-reference/series.md
@@ -45,6 +45,7 @@
         - is_sorted
         - is_unique
         - item
+        - kurtosis
         - len
         - log
         - max
@@ -71,6 +72,7 @@
         - shift
         - sort
         - skew
+        - sqrt
         - std
         - sum
         - tail
diff --git a/narwhals/_arrow/expr.py b/narwhals/_arrow/expr.py
index af7993c5..b64bfd66 100644
--- a/narwhals/_arrow/expr.py
+++ b/narwhals/_arrow/expr.py
@@ -202,4 +202,7 @@ class ArrowExpr(EagerExpr["ArrowDataFrame", ArrowSeries]):
     def exp(self) -> Self:
         return self._reuse_series("exp")
 
+    def sqrt(self) -> Self:
+        return self._reuse_series("sqrt")
+
     ewm_mean = not_implemented()
diff --git a/narwhals/_arrow/series.py b/narwhals/_arrow/series.py
index 02596202..fb514b0d 100644
--- a/narwhals/_arrow/series.py
+++ b/narwhals/_arrow/series.py
@@ -394,6 +394,19 @@ class ArrowSeries(EagerSeries["ChunkedArrayAny"]):
             biased_population_skewness = pc.divide(m3, pc.power(m2, lit(1.5)))
             return maybe_extract_py_scalar(biased_population_skewness, _return_py_scalar)
 
+    def kurtosis(self, *, _return_py_scalar: bool = True) -> float | None:
+        ser_not_null = self.native.drop_null()
+        if len(ser_not_null) == 0:
+            return None
+        elif len(ser_not_null) == 1:
+            return float("nan")
+        else:
+            m = pc.subtract(ser_not_null, pc.mean(ser_not_null))
+            m2 = pc.mean(pc.power(m, lit(2)))
+            m4 = pc.mean(pc.power(m, lit(4)))
+            k = pc.subtract(pc.divide(m4, pc.power(m2, lit(2))), lit(3))
+            return maybe_extract_py_scalar(k, _return_py_scalar)
+
     def count(self, *, _return_py_scalar: bool = True) -> int:
         return maybe_extract_py_scalar(pc.count(self.native), _return_py_scalar)
 
@@ -1160,6 +1173,9 @@ class ArrowSeries(EagerSeries["ChunkedArrayAny"]):
     def exp(self) -> Self:
         return self._with_native(pc.exp(self.native))
 
+    def sqrt(self) -> Self:
+        return self._with_native(pc.sqrt(self.native))
+
     @property
     def dt(self) -> ArrowSeriesDateTimeNamespace:
         return ArrowSeriesDateTimeNamespace(self)
diff --git a/narwhals/_compliant/expr.py b/narwhals/_compliant/expr.py
index 965469ee..14fdad97 100644
--- a/narwhals/_compliant/expr.py
+++ b/narwhals/_compliant/expr.py
@@ -127,6 +127,7 @@ class CompliantExpr(Protocol38[CompliantFrameT, CompliantSeriesOrNativeExprT_co]
     def sum(self) -> Self: ...
     def median(self) -> Self: ...
     def skew(self) -> Self: ...
+    def kurtosis(self) -> Self: ...
     def std(self, *, ddof: int) -> Self: ...
     def var(self, *, ddof: int) -> Self: ...
     def n_unique(self) -> Self: ...
@@ -140,6 +141,7 @@ class CompliantExpr(Protocol38[CompliantFrameT, CompliantSeriesOrNativeExprT_co]
     ) -> Self: ...
     def diff(self) -> Self: ...
     def exp(self) -> Self: ...
+    def sqrt(self) -> Self: ...
     def unique(self) -> Self: ...
     def len(self) -> Self: ...
     def log(self, base: float) -> Self: ...
@@ -613,6 +615,9 @@ class EagerExpr(
     def skew(self) -> Self:
         return self._reuse_series("skew", returns_scalar=True)
 
+    def kurtosis(self) -> Self:
+        return self._reuse_series("kurtosis", returns_scalar=True)
+
     def any(self) -> Self:
         return self._reuse_series("any", returns_scalar=True)
 
diff --git a/narwhals/_compliant/series.py b/narwhals/_compliant/series.py
index 706fd2b3..ea5720bd 100644
--- a/narwhals/_compliant/series.py
+++ b/narwhals/_compliant/series.py
@@ -175,6 +175,7 @@ class CompliantSeries(
         ignore_nulls: bool,
     ) -> Self: ...
     def exp(self) -> Self: ...
+    def sqrt(self) -> Self: ...
     def fill_null(
         self,
         value: Self | NonNestedLiteral,
@@ -204,6 +205,7 @@ class CompliantSeries(
     def is_sorted(self, *, descending: bool) -> bool: ...
     def is_unique(self) -> Self: ...
     def item(self, index: int | None) -> Any: ...
+    def kurtosis(self) -> float | None: ...
     def len(self) -> int: ...
     def log(self, base: float) -> Self: ...
     def max(self) -> Any: ...
diff --git a/narwhals/_dask/expr.py b/narwhals/_dask/expr.py
index aa51997b..5f37bfb5 100644
--- a/narwhals/_dask/expr.py
+++ b/narwhals/_dask/expr.py
@@ -326,6 +326,9 @@ class DaskExpr(
     def skew(self) -> Self:
         return self._with_callable(lambda expr: expr.skew().to_series(), "skew")
 
+    def kurtosis(self) -> Self:
+        return self._with_callable(lambda expr: expr.kurtosis().to_series(), "kurtosis")
+
     def shift(self, n: int) -> Self:
         return self._with_callable(lambda expr: expr.shift(n), "shift")
 
@@ -660,6 +663,11 @@ class DaskExpr(
 
         return self._with_callable(da.exp, "exp")
 
+    def sqrt(self) -> Self:
+        import dask.array as da
+
+        return self._with_callable(da.sqrt, "sqrt")
+
     @property
     def str(self) -> DaskExprStringNamespace:
         return DaskExprStringNamespace(self)
diff --git a/narwhals/_duckdb/expr.py b/narwhals/_duckdb/expr.py
index b3d55f31..79df3ca2 100644
--- a/narwhals/_duckdb/expr.py
+++ b/narwhals/_duckdb/expr.py
@@ -414,6 +414,9 @@ class DuckDBExpr(LazyExpr["DuckDBLazyFrame", "Expression"]):
 
         return self._with_callable(func)
 
+    def kurtosis(self) -> Self:
+        return self._with_callable(lambda expr: FunctionExpression("kurtosis_pop", expr))
+
     def median(self) -> Self:
         return self._with_callable(lambda expr: FunctionExpression("median", expr))
 
@@ -878,6 +881,14 @@ class DuckDBExpr(LazyExpr["DuckDBLazyFrame", "Expression"]):
 
         return self._with_elementwise(_exp)
 
+    def sqrt(self) -> Self:
+        def _sqrt(expr: Expression) -> Expression:
+            return when(expr < lit(0), lit(float("nan"))).otherwise(
+                FunctionExpression("sqrt", expr)
+            )
+
+        return self._with_elementwise(_sqrt)
+
     @property
     def str(self) -> DuckDBExprStringNamespace:
         return DuckDBExprStringNamespace(self)
diff --git a/narwhals/_ibis/expr.py b/narwhals/_ibis/expr.py
index 4fc8c79e..4c1ddc1d 100644
--- a/narwhals/_ibis/expr.py
+++ b/narwhals/_ibis/expr.py
@@ -673,6 +673,12 @@ class IbisExpr(LazyExpr["IbisLazyFrame", "ir.Column"]):
 
         return self._with_callable(_exp)
 
+    def sqrt(self) -> Self:
+        def _sqrt(expr: ir.NumericColumn) -> ir.Value:
+            return ibis.cases((expr < lit(0), lit(float("nan"))), else_=expr.sqrt())
+
+        return self._with_callable(_sqrt)
+
     @property
     def str(self) -> IbisExprStringNamespace:
         return IbisExprStringNamespace(self)
@@ -695,4 +701,5 @@ class IbisExpr(LazyExpr["IbisLazyFrame", "ir.Column"]):
 
     # NOTE: https://github.com/ibis-project/ibis/issues/11176
     skew = not_implemented()
+    kurtosis = not_implemented()
     unique = not_implemented()
diff --git a/narwhals/_pandas_like/expr.py b/narwhals/_pandas_like/expr.py
index 0cd9958d..d58d39be 100644
--- a/narwhals/_pandas_like/expr.py
+++ b/narwhals/_pandas_like/expr.py
@@ -400,3 +400,6 @@ class PandasLikeExpr(EagerExpr["PandasLikeDataFrame", PandasLikeSeries]):
 
     def exp(self) -> Self:
         return self._reuse_series("exp")
+
+    def sqrt(self) -> Self:
+        return self._reuse_series("sqrt")
diff --git a/narwhals/_pandas_like/series.py b/narwhals/_pandas_like/series.py
index 0ea4e833..fa943b34 100644
--- a/narwhals/_pandas_like/series.py
+++ b/narwhals/_pandas_like/series.py
@@ -532,6 +532,18 @@ class PandasLikeSeries(EagerSeries[Any]):
             m3 = (m**3).mean()
             return m3 / (m2**1.5) if m2 != 0 else float("nan")
 
+    def kurtosis(self) -> float | None:
+        ser_not_null = self.native.dropna()
+        if len(ser_not_null) == 0:
+            return None
+        elif len(ser_not_null) == 1:
+            return float("nan")
+        else:
+            m = ser_not_null - ser_not_null.mean()
+            m2 = (m**2).mean()
+            m4 = (m**4).mean()
+            return m4 / (m2**2) - 3.0 if m2 != 0 else float("nan")
+
     def len(self) -> int:
         return len(self.native)
 
@@ -1082,6 +1094,9 @@ class PandasLikeSeries(EagerSeries[Any]):
             result_native = np.exp(native)
         return self._with_native(result_native)
 
+    def sqrt(self) -> Self:
+        return self._with_native(self.native.pow(0.5))
+
     @property
     def str(self) -> PandasLikeSeriesStringNamespace:
         return PandasLikeSeriesStringNamespace(self)
diff --git a/narwhals/_polars/expr.py b/narwhals/_polars/expr.py
index eb5b5f26..449a9df5 100644
--- a/narwhals/_polars/expr.py
+++ b/narwhals/_polars/expr.py
@@ -288,6 +288,7 @@ class PolarsExpr:
     is_last_distinct: Method[Self]
     is_null: Method[Self]
     is_unique: Method[Self]
+    kurtosis: Method[Self]
     len: Method[Self]
     log: Method[Self]
     max: Method[Self]
@@ -303,6 +304,7 @@ class PolarsExpr:
     sample: Method[Self]
     shift: Method[Self]
     skew: Method[Self]
+    sqrt: Method[Self]
     std: Method[Self]
     sum: Method[Self]
     sort: Method[Self]
diff --git a/narwhals/_polars/series.py b/narwhals/_polars/series.py
index 2a4325ef..82055564 100644
--- a/narwhals/_polars/series.py
+++ b/narwhals/_polars/series.py
@@ -92,6 +92,7 @@ INHERITED_METHODS = frozenset(
         "is_sorted",
         "is_unique",
         "item",
+        "kurtosis",
         "len",
         "log",
         "max",
@@ -106,6 +107,7 @@ INHERITED_METHODS = frozenset(
         "sample",
         "shift",
         "skew",
+        "sqrt",
         "std",
         "sum",
         "tail",
@@ -642,6 +644,7 @@ class PolarsSeries:
     is_sorted: Method[bool]
     is_unique: Method[Self]
     item: Method[Any]
+    kurtosis: Method[float | None]
     len: Method[int]
     log: Method[Self]
     max: Method[Any]
@@ -656,6 +659,7 @@ class PolarsSeries:
     sample: Method[Self]
     shift: Method[Self]
     skew: Method[float | None]
+    sqrt: Method[Self]
     std: Method[float]
     sum: Method[float]
     tail: Method[Self]
diff --git a/narwhals/_spark_like/expr.py b/narwhals/_spark_like/expr.py
index 5c42dbb8..0f60ab98 100644
--- a/narwhals/_spark_like/expr.py
+++ b/narwhals/_spark_like/expr.py
@@ -663,6 +663,9 @@ class SparkLikeExpr(LazyExpr["SparkLikeLazyFrame", "Column"]):
     def skew(self) -> Self:
         return self._with_callable(self._F.skewness)
 
+    def kurtosis(self) -> Self:
+        return self._with_callable(self._F.kurtosis)
+
     def n_unique(self) -> Self:
         def _n_unique(expr: Column) -> Column:
             return self._F.count_distinct(expr) + self._F.max(
@@ -909,6 +912,14 @@ class SparkLikeExpr(LazyExpr["SparkLikeLazyFrame", "Column"]):
 
         return self._with_elementwise(_exp)
 
+    def sqrt(self) -> Self:
+        def _sqrt(expr: Column) -> Column:
+            return self._F.when(expr < 0, self._F.lit(float("nan"))).otherwise(
+                self._F.sqrt(expr)
+            )
+
+        return self._with_elementwise(_sqrt)
+
     @property
     def str(self) -> SparkLikeExprStringNamespace:
         return SparkLikeExprStringNamespace(self)
diff --git a/narwhals/_utils.py b/narwhals/_utils.py
index 6d948260..6bb14811 100644
--- a/narwhals/_utils.py
+++ b/narwhals/_utils.py
@@ -640,18 +640,6 @@ def _import_native_namespace(module_name: str) -> ModuleType:
     return import_module(module_name)
 
 
-def remove_prefix(text: str, prefix: str) -> str:  # pragma: no cover
-    if text.startswith(prefix):
-        return text[len(prefix) :]
-    return text
-
-
-def remove_suffix(text: str, suffix: str) -> str:  # pragma: no cover
-    if text.endswith(suffix):
-        return text[: -len(suffix)]
-    return text  # pragma: no cover
-
-
 def flatten(args: Any) -> list[Any]:
     return list(args[0] if (len(args) == 1 and _is_iterable(args[0])) else args)
 
diff --git a/narwhals/expr.py b/narwhals/expr.py
index fcd48f19..97504a3d 100644
--- a/narwhals/expr.py
+++ b/narwhals/expr.py
@@ -680,6 +680,30 @@ class Expr:
         """
         return self._with_aggregation(lambda plx: self._to_compliant_expr(plx).skew())
 
+    def kurtosis(self) -> Self:
+        """Compute the kurtosis (Fisher's definition) without bias correction.
+
+        Kurtosis is the fourth central moment divided by the square of the variance.
+        The Fisher's definition is used where 3.0 is subtracted from the result to give 0.0 for a normal distribution.
+
+        Returns:
+            An expression representing the kurtosis (Fisher's definition) without bias correction of the column.
+
+        Examples:
+            >>> import pandas as pd
+            >>> import narwhals as nw
+            >>> df_native = pd.DataFrame({"a": [1, 2, 3, 4, 5], "b": [1, 1, 2, 10, 100]})
+            >>> df = nw.from_native(df_native)
+            >>> df.select(nw.col("a", "b").kurtosis())
+            ┌──────────────────┐
+            |Narwhals DataFrame|
+            |------------------|
+            |      a         b |
+            | 0 -1.3  0.210657 |
+            └──────────────────┘
+        """
+        return self._with_aggregation(lambda plx: self._to_compliant_expr(plx).kurtosis())
+
     def sum(self) -> Expr:
         """Return the sum value.
 
@@ -2516,6 +2540,32 @@ class Expr:
         """
         return self._with_elementwise_op(lambda plx: self._to_compliant_expr(plx).exp())
 
+    def sqrt(self) -> Self:
+        r"""Compute the square root.
+
+        Returns:
+            A new expression.
+
+        Examples:
+            >>> import pyarrow as pa
+            >>> import narwhals as nw
+            >>> df_native = pa.table({"values": [1, 4, 9]})
+            >>> df = nw.from_native(df_native)
+            >>> result = df.with_columns(sqrt=nw.col("values").sqrt())
+            >>> result
+            ┌──────────────────┐
+            |Narwhals DataFrame|
+            |------------------|
+            |pyarrow.Table     |
+            |values: int64     |
+            |sqrt: double      |
+            |----              |
+            |values: [[1,4,9]] |
+            |sqrt: [[1,2,3]]   |
+            └──────────────────┘
+        """
+        return self._with_elementwise_op(lambda plx: self._to_compliant_expr(plx).sqrt())
+
     @property
     def str(self) -> ExprStringNamespace[Self]:
         return ExprStringNamespace(self)
diff --git a/narwhals/series.py b/narwhals/series.py
index 92b784bb..599f0133 100644
--- a/narwhals/series.py
+++ b/narwhals/series.py
@@ -602,6 +602,25 @@ class Series(Generic[IntoSeriesT]):
         """
         return self._compliant_series.skew()
 
+    def kurtosis(self) -> float | None:
+        """Compute the kurtosis (Fisher's definition) without bias correction.
+
+        Kurtosis is the fourth central moment divided by the square of the variance.
+        The Fisher's definition is used where 3.0 is subtracted from the result to give 0.0 for a normal distribution.
+
+        Returns:
+            The kurtosis (Fisher's definition) without bias correction of the column.
+
+        Examples:
+            >>> import polars as pl
+            >>> import narwhals as nw
+            >>>
+            >>> s_native = pl.Series([1, 1, 2, 10, 100])
+            >>> nw.from_native(s_native, series_only=True).kurtosis()
+            0.2106571340718002
+        """
+        return self._compliant_series.kurtosis()
+
     def count(self) -> int:
         """Returns the number of non-null elements in the Series.
 
@@ -2644,6 +2663,29 @@ class Series(Generic[IntoSeriesT]):
         """
         return self._with_compliant(self._compliant_series.exp())
 
+    def sqrt(self) -> Self:
+        r"""Compute the square root.
+
+        Returns:
+            A new series.
+
+        Examples:
+            >>> import pandas as pd
+            >>> import narwhals as nw
+            >>> s_native = pd.Series([1, 4, 9], name="a")
+            >>> s = nw.from_native(s_native, series_only=True)
+            >>> s.sqrt()
+            ┌───────────────────────┐
+            |    Narwhals Series    |
+            |-----------------------|
+            |0    1.0               |
+            |1    2.0               |
+            |2    3.0               |
+            |Name: a, dtype: float64|
+            └───────────────────────┘
+        """
+        return self._with_compliant(self._compliant_series.sqrt())
+
     @property
     def str(self) -> SeriesStringNamespace[Self]:
         return SeriesStringNamespace(self)
diff --git a/utils/check_api_reference.py b/utils/check_api_reference.py
index a996af04..6aad1fae 100644
--- a/utils/check_api_reference.py
+++ b/utils/check_api_reference.py
@@ -10,7 +10,6 @@ from typing import Any, Iterator
 import polars as pl
 
 import narwhals as nw
-from narwhals._utils import remove_prefix
 
 LOWERCASE = tuple(string.ascii_lowercase)
 
@@ -33,6 +32,12 @@ def iter_api_reference_names(tp: type[Any]) -> Iterator[str]:
         yield name
 
 
+def remove_prefix(text: str, prefix: str) -> str:
+    if text.startswith(prefix):
+        return text[len(prefix) :]
+    return text
+
+
 ret = 0
 
 NAMESPACES = {"dt", "str", "cat", "name", "list", "struct"}


Test patch:
diff --git a/tests/expr_and_series/kurtosis_test.py b/tests/expr_and_series/kurtosis_test.py
new file mode 100644
index 00000000..55727445
--- /dev/null
+++ b/tests/expr_and_series/kurtosis_test.py
@@ -0,0 +1,55 @@
+from __future__ import annotations
+
+import pytest
+
+import narwhals as nw
+from tests.utils import Constructor, ConstructorEager, assert_equal_data
+
+
+@pytest.mark.parametrize(
+    ("data", "expected"),
+    [
+        ([], None),
+        ([1], None),
+        ([1, 2], -2.0),
+        ([0.0, 0.0, 0.0], None),
+        ([1, 2, 3, 2, 1], -1.153061),
+    ],
+)
+def test_kurtosis_series(
+    constructor_eager: ConstructorEager, data: list[float], expected: float | None
+) -> None:
+    result = nw.from_native(constructor_eager({"a": data}), eager_only=True)[
+        "a"
+    ].kurtosis()
+    assert_equal_data({"a": [result]}, {"a": [expected]})
+
+
+@pytest.mark.parametrize(
+    ("data", "expected"),
+    [
+        ([], None),
+        ([1], None),
+        ([1, 2], -2.0),
+        ([0.0, 0.0, 0.0], None),
+        ([1, 2, 3, 2, 1], -1.153061),
+    ],
+    ids=range(5),
+)
+@pytest.mark.filterwarnings("ignore:.*invalid value:RuntimeWarning:dask")
+def test_kurtosis_expr(
+    constructor: Constructor,
+    data: list[float],
+    expected: float | None,
+    request: pytest.FixtureRequest,
+) -> None:
+    if "ibis" in str(constructor):
+        # https://github.com/ibis-project/ibis/issues/11341
+        request.applymarker(pytest.mark.xfail)
+
+    if "pyspark" in str(constructor) and int(request.node.callspec.id[-1]) == 0:
+        # Can not infer schema from empty dataset.
+        pytest.skip()
+
+    result = nw.from_native(constructor({"a": data})).select(nw.col("a").kurtosis())
+    assert_equal_data(result, {"a": [expected]})
diff --git a/tests/expr_and_series/sqrt_test.py b/tests/expr_and_series/sqrt_test.py
new file mode 100644
index 00000000..8702ea04
--- /dev/null
+++ b/tests/expr_and_series/sqrt_test.py
@@ -0,0 +1,50 @@
+from __future__ import annotations
+
+import pandas as pd
+import pytest
+
+import narwhals.stable.v1 as nw
+from tests.utils import PANDAS_VERSION, Constructor, ConstructorEager, assert_equal_data
+
+data = {"a": [-1, 0, 1, 2, 4]}
+
+expected = [float("nan"), 0, 1, 1.414213, 2]
+
+
+@pytest.mark.filterwarnings("ignore::RuntimeWarning")
+def test_sqrt_expr(constructor: Constructor) -> None:
+    df = nw.from_native(constructor(data))
+    result = df.select(nw.col("a").sqrt())
+    assert_equal_data(result, {"a": expected})
+
+
+@pytest.mark.filterwarnings("ignore::RuntimeWarning")
+def test_sqrt_series(constructor_eager: ConstructorEager) -> None:
+    series = nw.from_native(constructor_eager(data), eager_only=True)["a"]
+    result = series.sqrt()
+    assert_equal_data({"a": result}, {"a": expected})
+
+
+def test_sqrt_dtype_pandas() -> None:
+    s = pd.Series([1.0, 2.0], name="a", dtype="float32", index=[8, 7])
+    result = nw.from_native(s, series_only=True).sqrt().to_native()
+    expected = pd.Series([1, 1.414213], name="a", dtype="float32", index=[8, 7])
+    pd.testing.assert_series_equal(result, expected)
+
+
+@pytest.mark.skipif(PANDAS_VERSION < (2, 0, 0), reason="nullable types require pandas2+")
+def test_sqrt_dtype_pandas_nullable() -> None:
+    s = pd.Series([1.0, None, 2.0], name="a", dtype="Float32", index=[8, 7, 6])
+    result = nw.from_native(s, series_only=True).sqrt().to_native()
+    expected = pd.Series([1, None, 1.414213], name="a", dtype="Float32", index=[8, 7, 6])
+    pd.testing.assert_series_equal(result, expected)
+
+
+@pytest.mark.skipif(PANDAS_VERSION < (2, 1, 0), reason="nullable types require pandas2+")
+def test_sqrt_dtype_pandas_pyarrow() -> None:
+    s = pd.Series([1.0, None, 2.0], name="a", dtype="Float32[pyarrow]", index=[8, 7, 6])
+    result = nw.from_native(s, series_only=True).sqrt().to_native()
+    expected = pd.Series(
+        [1, None, 1.414213], name="a", dtype="Float64[pyarrow]", index=[8, 7, 6]
+    )
+    pd.testing.assert_series_equal(result, expected)