Repository: narwhals-dev/narwhals
Pull request #2378 (2025-04-12 15:17:26)

feat: Remove "unstable" marking from rolling_* and ewm_mean
These have been in for a while, and we've now figured out how to support them for lazy backends

They're not marked as "unstable" anymore in Polars

I'd say...let's remove "unstable" ourselves too

<!--
# 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
- [ ] 🔧 Optimization
- [ ] 📝 Documentation
- [ ] ✅ Test
- [ ] 🐳 Other

## Related issues

- Related issue #\<issue number\>
- Closes #\<issue number\>

## Checklist

- [ ] Code follows style guide (ruff)
- [ ] Tests added
- [ ] Documented the changes

## If you have comments or can explain your changes, please do so below



Patch:
diff --git a/narwhals/_compliant/expr.py b/narwhals/_compliant/expr.py
index 9ae4b663..2f30c96b 100644
--- a/narwhals/_compliant/expr.py
+++ b/narwhals/_compliant/expr.py
@@ -37,7 +37,6 @@ from narwhals.dtypes import DType
 from narwhals.utils import _StoresCompliant
 from narwhals.utils import deprecated
 from narwhals.utils import not_implemented
-from narwhals.utils import unstable
 
 if not TYPE_CHECKING:  # pragma: no cover
     if sys.version_info >= (3, 9):
@@ -197,7 +196,6 @@ class CompliantExpr(Protocol38[CompliantFrameT, CompliantSeriesOrNativeExprT_co]
     @property
     def struct(self) -> Any: ...
 
-    @unstable
     def ewm_mean(
         self,
         *,
@@ -210,7 +208,6 @@ class CompliantExpr(Protocol38[CompliantFrameT, CompliantSeriesOrNativeExprT_co]
         ignore_nulls: bool,
     ) -> Self: ...
 
-    @unstable
     def rolling_sum(
         self,
         window_size: int,
@@ -219,7 +216,6 @@ class CompliantExpr(Protocol38[CompliantFrameT, CompliantSeriesOrNativeExprT_co]
         center: bool,
     ) -> Self: ...
 
-    @unstable
     def rolling_mean(
         self,
         window_size: int,
@@ -228,7 +224,6 @@ class CompliantExpr(Protocol38[CompliantFrameT, CompliantSeriesOrNativeExprT_co]
         center: bool,
     ) -> Self: ...
 
-    @unstable
     def rolling_var(
         self,
         window_size: int,
@@ -238,7 +233,6 @@ class CompliantExpr(Protocol38[CompliantFrameT, CompliantSeriesOrNativeExprT_co]
         ddof: int,
     ) -> Self: ...
 
-    @unstable
     def rolling_std(
         self,
         window_size: int,
diff --git a/narwhals/_compliant/series.py b/narwhals/_compliant/series.py
index 5ebcb80c..28083829 100644
--- a/narwhals/_compliant/series.py
+++ b/narwhals/_compliant/series.py
@@ -142,7 +142,6 @@ class CompliantSeries(
     def cum_sum(self, *, reverse: bool) -> Self: ...
     def diff(self) -> Self: ...
     def drop_nulls(self) -> Self: ...
-    @unstable
     def ewm_mean(
         self,
         *,
@@ -199,7 +198,6 @@ class CompliantSeries(
         *,
         return_dtype: DType | type[DType] | None,
     ) -> Self: ...
-    @unstable
     def rolling_mean(
         self,
         window_size: int,
@@ -207,7 +205,6 @@ class CompliantSeries(
         min_samples: int,
         center: bool,
     ) -> Self: ...
-    @unstable
     def rolling_std(
         self,
         window_size: int,
@@ -216,7 +213,6 @@ class CompliantSeries(
         center: bool,
         ddof: int,
     ) -> Self: ...
-    @unstable
     def rolling_sum(
         self,
         window_size: int,
@@ -224,7 +220,6 @@ class CompliantSeries(
         min_samples: int,
         center: bool,
     ) -> Self: ...
-    @unstable
     def rolling_var(
         self,
         window_size: int,
diff --git a/narwhals/expr.py b/narwhals/expr.py
index 49c80f31..fade3eb1 100644
--- a/narwhals/expr.py
+++ b/narwhals/expr.py
@@ -453,10 +453,6 @@ class Expr:
     ) -> Self:
         r"""Compute exponentially-weighted moving average.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         Arguments:
             com: Specify decay in terms of center of mass, $\gamma$, with <br> $\alpha = \frac{1}{1+\gamma}\forall\gamma\geq0$
             span: Specify decay in terms of span, $\theta$, with <br> $\alpha = \frac{2}{\theta + 1} \forall \theta \geq 1$
@@ -2210,10 +2206,6 @@ class Expr:
     ) -> Self:
         """Apply a rolling sum (moving sum) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their sum.
 
@@ -2276,10 +2268,6 @@ class Expr:
     ) -> Self:
         """Apply a rolling mean (moving mean) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their mean.
 
@@ -2343,10 +2331,6 @@ class Expr:
     ) -> Self:
         """Apply a rolling variance (moving variance) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their variance.
 
@@ -2409,10 +2393,6 @@ class Expr:
     ) -> Self:
         """Apply a rolling standard deviation (moving standard deviation) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their standard deviation.
 
diff --git a/narwhals/series.py b/narwhals/series.py
index c3a57795..4073ec84 100644
--- a/narwhals/series.py
+++ b/narwhals/series.py
@@ -394,10 +394,6 @@ class Series(Generic[IntoSeriesT]):
     ) -> Self:
         r"""Compute exponentially-weighted moving average.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         Arguments:
             com: Specify decay in terms of center of mass, $\gamma$, with <br> $\alpha = \frac{1}{1+\gamma}\forall\gamma\geq0$
             span: Specify decay in terms of span, $\theta$, with <br> $\alpha = \frac{2}{\theta + 1} \forall \theta \geq 1$
@@ -2246,10 +2242,6 @@ class Series(Generic[IntoSeriesT]):
     ) -> Self:
         """Apply a rolling sum (moving sum) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their sum.
 
@@ -2304,10 +2296,6 @@ class Series(Generic[IntoSeriesT]):
     ) -> Self:
         """Apply a rolling mean (moving mean) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their mean.
 
@@ -2367,10 +2355,6 @@ class Series(Generic[IntoSeriesT]):
     ) -> Self:
         """Apply a rolling variance (moving variance) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their variance.
 
@@ -2430,10 +2414,6 @@ class Series(Generic[IntoSeriesT]):
     ) -> Self:
         """Apply a rolling standard deviation (moving standard deviation) over the values.
 
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
         A window of length `window_size` will traverse the values. The resulting values
         will be aggregated to their standard deviation.
 
diff --git a/narwhals/stable/v1/__init__.py b/narwhals/stable/v1/__init__.py
index 92245b26..ea310d8a 100644
--- a/narwhals/stable/v1/__init__.py
+++ b/narwhals/stable/v1/__init__.py
@@ -437,262 +437,6 @@ class Series(NwSeries[IntoSeriesT]):
             sort=sort, parallel=parallel, name=name, normalize=normalize
         )
 
-    def ewm_mean(
-        self: Self,
-        *,
-        com: float | None = None,
-        span: float | None = None,
-        half_life: float | None = None,
-        alpha: float | None = None,
-        adjust: bool = True,
-        min_samples: int = 1,
-        ignore_nulls: bool = False,
-    ) -> Self:
-        r"""Compute exponentially-weighted moving average.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        Arguments:
-            com: Specify decay in terms of center of mass, $\gamma$, with <br> $\alpha = \frac{1}{1+\gamma}\forall\gamma\geq0$
-            span: Specify decay in terms of span, $\theta$, with <br> $\alpha = \frac{2}{\theta + 1} \forall \theta \geq 1$
-            half_life: Specify decay in terms of half-life, $\tau$, with <br> $\alpha = 1 - \exp \left\{ \frac{ -\ln(2) }{ \tau } \right\} \forall \tau > 0$
-            alpha: Specify smoothing factor alpha directly, $0 < \alpha \leq 1$.
-            adjust: Divide by decaying adjustment factor in beginning periods to account for imbalance in relative weightings
-
-                - When `adjust=True` (the default) the EW function is calculated
-                  using weights $w_i = (1 - \alpha)^i$
-                - When `adjust=False` the EW function is calculated recursively by
-                  $$
-                  y_0=x_0
-                  $$
-                  $$
-                  y_t = (1 - \alpha)y_{t - 1} + \alpha x_t
-                  $$
-            min_samples: Minimum number of observations in window required to have a value (otherwise result is null).
-            ignore_nulls: Ignore missing values when calculating weights.
-
-                - When `ignore_nulls=False` (default), weights are based on absolute
-                  positions.
-                  For example, the weights of $x_0$ and $x_2$ used in
-                  calculating the final weighted average of $[x_0, None, x_2]$ are
-                  $(1-\alpha)^2$ and $1$ if `adjust=True`, and
-                  $(1-\alpha)^2$ and $\alpha$ if `adjust=False`.
-                - When `ignore_nulls=True`, weights are based
-                  on relative positions. For example, the weights of
-                  $x_0$ and $x_2$ used in calculating the final weighted
-                  average of $[x_0, None, x_2]$ are
-                  $1-\alpha$ and $1$ if `adjust=True`,
-                  and $1-\alpha$ and $\alpha$ if `adjust=False`.
-
-        Returns:
-            Series
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Series.ewm_mean` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().ewm_mean(
-            com=com,
-            span=span,
-            half_life=half_life,
-            alpha=alpha,
-            adjust=adjust,
-            min_samples=min_samples,
-            ignore_nulls=ignore_nulls,
-        )
-
-    def rolling_sum(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-    ) -> Self:
-        """Apply a rolling sum (moving sum) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their sum.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`
-            center: Set the labels at the center of the window.
-
-        Returns:
-            A new series.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Series.rolling_sum` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_sum(
-            window_size=window_size,
-            min_samples=min_samples,
-            center=center,
-        )
-
-    def rolling_mean(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-    ) -> Self:
-        """Apply a rolling mean (moving mean) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their mean.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`
-            center: Set the labels at the center of the window.
-
-        Returns:
-            A new series.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Series.rolling_mean` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_mean(
-            window_size=window_size,
-            min_samples=min_samples,
-            center=center,
-        )
-
-    def rolling_var(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-        ddof: int = 1,
-    ) -> Self:
-        """Apply a rolling variance (moving variance) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their variance.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`.
-            center: Set the labels at the center of the window.
-            ddof: Delta Degrees of Freedom; the divisor for a length N window is N - ddof.
-
-        Returns:
-            A new series.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Series.rolling_var` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_var(
-            window_size=window_size,
-            min_samples=min_samples,
-            center=center,
-            ddof=ddof,
-        )
-
-    def rolling_std(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-        ddof: int = 1,
-    ) -> Self:
-        """Apply a rolling standard deviation (moving standard deviation) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their standard deviation.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`.
-            center: Set the labels at the center of the window.
-            ddof: Delta Degrees of Freedom; the divisor for a length N window is N - ddof.
-
-        Returns:
-            A new series.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Series.rolling_std` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_std(
-            window_size=window_size,
-            min_samples=min_samples,
-            center=center,
-            ddof=ddof,
-        )
-
     def hist(
         self: Self,
         bins: list[float | int] | None = None,
@@ -733,259 +477,6 @@ class Expr(NwExpr):
     def _l1_norm(self: Self) -> Self:
         return super()._taxicab_norm()
 
-    def ewm_mean(
-        self: Self,
-        *,
-        com: float | None = None,
-        span: float | None = None,
-        half_life: float | None = None,
-        alpha: float | None = None,
-        adjust: bool = True,
-        min_samples: int = 1,
-        ignore_nulls: bool = False,
-    ) -> Self:
-        r"""Compute exponentially-weighted moving average.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        Arguments:
-            com: Specify decay in terms of center of mass, $\gamma$, with <br> $\alpha = \frac{1}{1+\gamma}\forall\gamma\geq0$
-            span: Specify decay in terms of span, $\theta$, with <br> $\alpha = \frac{2}{\theta + 1} \forall \theta \geq 1$
-            half_life: Specify decay in terms of half-life, $\tau$, with <br> $\alpha = 1 - \exp \left\{ \frac{ -\ln(2) }{ \tau } \right\} \forall \tau > 0$
-            alpha: Specify smoothing factor alpha directly, $0 < \alpha \leq 1$.
-            adjust: Divide by decaying adjustment factor in beginning periods to account for imbalance in relative weightings
-
-                - When `adjust=True` (the default) the EW function is calculated
-                  using weights $w_i = (1 - \alpha)^i$
-                - When `adjust=False` the EW function is calculated recursively by
-                  $$
-                  y_0=x_0
-                  $$
-                  $$
-                  y_t = (1 - \alpha)y_{t - 1} + \alpha x_t
-                  $$
-            min_samples: Minimum number of observations in window required to have a value, (otherwise result is null).
-            ignore_nulls: Ignore missing values when calculating weights.
-
-                - When `ignore_nulls=False` (default), weights are based on absolute
-                  positions.
-                  For example, the weights of $x_0$ and $x_2$ used in
-                  calculating the final weighted average of $[x_0, None, x_2]$ are
-                  $(1-\alpha)^2$ and $1$ if `adjust=True`, and
-                  $(1-\alpha)^2$ and $\alpha$ if `adjust=False`.
-                - When `ignore_nulls=True`, weights are based
-                  on relative positions. For example, the weights of
-                  $x_0$ and $x_2$ used in calculating the final weighted
-                  average of $[x_0, None, x_2]$ are
-                  $1-\alpha$ and $1$ if `adjust=True`,
-                  and $1-\alpha$ and $\alpha$ if `adjust=False`.
-
-        Returns:
-            Expr
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Expr.ewm_mean` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().ewm_mean(
-            com=com,
-            span=span,
-            half_life=half_life,
-            alpha=alpha,
-            adjust=adjust,
-            min_samples=min_samples,
-            ignore_nulls=ignore_nulls,
-        )
-
-    def rolling_sum(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-    ) -> Self:
-        """Apply a rolling sum (moving sum) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their sum.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`
-            center: Set the labels at the center of the window.
-
-        Returns:
-            A new expression.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Expr.rolling_sum` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_sum(
-            window_size=window_size,
-            min_samples=min_samples,
-            center=center,
-        )
-
-    def rolling_mean(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-    ) -> Self:
-        """Apply a rolling mean (moving mean) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their mean.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`
-            center: Set the labels at the center of the window.
-
-        Returns:
-            A new expression.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Expr.rolling_mean` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_mean(
-            window_size=window_size,
-            min_samples=min_samples,
-            center=center,
-        )
-
-    def rolling_var(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-        ddof: int = 1,
-    ) -> Self:
-        """Apply a rolling variance (moving variance) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their variance.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`.
-            center: Set the labels at the center of the window.
-            ddof: Delta Degrees of Freedom; the divisor for a length N window is N - ddof.
-
-        Returns:
-            A new expression.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Expr.rolling_var` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_var(
-            window_size=window_size, min_samples=min_samples, center=center, ddof=ddof
-        )
-
-    def rolling_std(
-        self: Self,
-        window_size: int,
-        *,
-        min_samples: int | None = None,
-        center: bool = False,
-        ddof: int = 1,
-    ) -> Self:
-        """Apply a rolling standard deviation (moving standard deviation) over the values.
-
-        !!! warning
-            This functionality is considered **unstable**. It may be changed at any point
-            without it being considered a breaking change.
-
-        A window of length `window_size` will traverse the values. The resulting values
-        will be aggregated to their standard deviation.
-
-        The window at a given row will include the row itself and the `window_size - 1`
-        elements before it.
-
-        Arguments:
-            window_size: The length of the window in number of elements. It must be a
-                strictly positive integer.
-            min_samples: The number of values in the window that should be non-null before
-                computing a result. If set to `None` (default), it will be set equal to
-                `window_size`. If provided, it must be a strictly positive integer, and
-                less than or equal to `window_size`
-            center: Set the labels at the center of the window.
-            ddof: Delta Degrees of Freedom; the divisor for a length N window is N - ddof.
-
-        Returns:
-            A new expression.
-        """
-        from narwhals.exceptions import NarwhalsUnstableWarning
-        from narwhals.utils import find_stacklevel
-
-        msg = (
-            "`Expr.rolling_std` is being called from the stable API although considered "
-            "an unstable feature."
-        )
-        warn(message=msg, category=NarwhalsUnstableWarning, stacklevel=find_stacklevel())
-        return super().rolling_std(
-            window_size=window_size,
-            min_samples=min_samples,
-            center=center,
-            ddof=ddof,
-        )
-
     def head(self: Self, n: int = 10) -> Self:
         r"""Get the first `n` rows.
 


Test patch:
diff --git a/tests/expr_and_series/ewm_test.py b/tests/expr_and_series/ewm_test.py
index 34941c6d..28f35bba 100644
--- a/tests/expr_and_series/ewm_test.py
+++ b/tests/expr_and_series/ewm_test.py
@@ -9,9 +9,6 @@ from tests.utils import assert_equal_data
 data = {"a": [1, 1, 2], "b": [1, 2, 3]}
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.ewm_mean` is being called from the stable API although considered an unstable feature."
-)
 def test_ewm_mean_expr(
     request: pytest.FixtureRequest, constructor_eager: ConstructorEager
 ) -> None:
@@ -27,9 +24,6 @@ def test_ewm_mean_expr(
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Series.ewm_mean` is being called from the stable API although considered an unstable feature."
-)
 def test_ewm_mean_series(
     request: pytest.FixtureRequest, constructor_eager: ConstructorEager
 ) -> None:
@@ -42,9 +36,6 @@ def test_ewm_mean_series(
     assert_equal_data({"a": result}, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.ewm_mean` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("adjust", "expected"),
     [
@@ -78,9 +69,6 @@ def test_ewm_mean_expr_adjust(
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.ewm_mean` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("ignore_nulls", "expected"),
     [
@@ -122,9 +110,6 @@ def test_ewm_mean_nulls(
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.ewm_mean` is being called from the stable API although considered an unstable feature."
-)
 def test_ewm_mean_params(
     request: pytest.FixtureRequest,
     constructor_eager: ConstructorEager,
@@ -162,9 +147,6 @@ def test_ewm_mean_params(
         df.select(nw.col("a").ewm_mean(span=1.5, half_life=0.75, ignore_nulls=False))
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.ewm_mean` is being called from the stable API although considered an unstable feature."
-)
 def test_ewm_mean_cudf_raise() -> None:  # pragma: no cover
     pytest.importorskip("cudf")
     import cudf
diff --git a/tests/expr_and_series/rolling_mean_test.py b/tests/expr_and_series/rolling_mean_test.py
index 29084ad4..0ff497aa 100644
--- a/tests/expr_and_series/rolling_mean_test.py
+++ b/tests/expr_and_series/rolling_mean_test.py
@@ -40,9 +40,6 @@ kwargs_and_expected: dict[str, dict[str, Any]] = {
 }
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_mean` is being called from the stable API although considered an unstable feature."
-)
 def test_rolling_mean_expr(constructor_eager: ConstructorEager) -> None:
     df = nw.from_native(constructor_eager(data))
     result = df.select(
@@ -100,9 +97,6 @@ def test_rolling_mean_hypothesis(center: bool, values: list[float]) -> None:  #
     assert_equal_data(result, expected_dict)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_mean` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center"),
     [
@@ -158,9 +152,6 @@ def test_rolling_mean_expr_lazy_grouped(
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_mean` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center"),
     [
diff --git a/tests/expr_and_series/rolling_std_test.py b/tests/expr_and_series/rolling_std_test.py
index 5f9b5572..95b62692 100644
--- a/tests/expr_and_series/rolling_std_test.py
+++ b/tests/expr_and_series/rolling_std_test.py
@@ -66,9 +66,6 @@ kwargs_and_expected = (
 )
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_std` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize("kwargs_and_expected", kwargs_and_expected)
 def test_rolling_std_expr(
     constructor_eager: ConstructorEager,
@@ -108,9 +105,6 @@ def test_rolling_std_series(
     assert_equal_data(result, {name: expected})
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_std` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center", "ddof"),
     [
@@ -231,9 +225,6 @@ def test_rolling_std_expr_lazy_ungrouped(
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_std` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center", "ddof"),
     [
diff --git a/tests/expr_and_series/rolling_sum_test.py b/tests/expr_and_series/rolling_sum_test.py
index d7a040ee..5db870bb 100644
--- a/tests/expr_and_series/rolling_sum_test.py
+++ b/tests/expr_and_series/rolling_sum_test.py
@@ -41,9 +41,6 @@ kwargs_and_expected: dict[str, dict[str, Any]] = {
 }
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_sum` is being called from the stable API although considered an unstable feature."
-)
 def test_rolling_sum_expr(constructor_eager: ConstructorEager) -> None:
     df = nw.from_native(constructor_eager(data))
     result = df.select(
@@ -57,9 +54,6 @@ def test_rolling_sum_expr(constructor_eager: ConstructorEager) -> None:
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_sum` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center"),
     [
@@ -106,9 +100,6 @@ def test_rolling_sum_expr_lazy_ungrouped(
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_sum` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center"),
     [
@@ -180,9 +171,6 @@ def test_rolling_sum_series(constructor_eager: ConstructorEager) -> None:
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_sum` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("window_size", "min_samples", "context"),
     [
diff --git a/tests/expr_and_series/rolling_var_test.py b/tests/expr_and_series/rolling_var_test.py
index 46e18216..a708ce8b 100644
--- a/tests/expr_and_series/rolling_var_test.py
+++ b/tests/expr_and_series/rolling_var_test.py
@@ -58,9 +58,6 @@ kwargs_and_expected = (
 )
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_var` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize("kwargs_and_expected", kwargs_and_expected)
 def test_rolling_var_expr(
     request: pytest.FixtureRequest,
@@ -174,9 +171,6 @@ def test_rolling_var_hypothesis_polars(center: bool, values: list[float]) -> Non
     assert_equal_data(result, expected_dict)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_var` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center", "ddof"),
     [
@@ -241,9 +235,6 @@ def test_rolling_var_expr_lazy_ungrouped(
     assert_equal_data(result, expected)
 
 
-@pytest.mark.filterwarnings(
-    "ignore:`Expr.rolling_var` is being called from the stable API although considered an unstable feature."
-)
 @pytest.mark.parametrize(
     ("expected_a", "window_size", "min_samples", "center", "ddof"),
     [