Repository: narwhals-dev/narwhals

Issue:
feat: series.rename
I keep reaching for this and realising it doesn't exist

reference: https://docs.pola.rs/api/python/stable/reference/series/api/polars.Series.rename.html

Discussion:
raisadz: > Thanks @raisadz 🚀
> 
> It looks good! I left a comment to simplify a bit the logic. I think `./utils/generate_backend_completeness.py` may need some love to render that `rename` is implemented for all series. But I would be ok to leave that as a follow up as well 👌

Thank you for your review @FBruzzesi !

Patch:
diff --git a/docs/api-reference/series.md b/docs/api-reference/series.md
index 5adaa57a..e8572dda 100644
--- a/docs/api-reference/series.md
+++ b/docs/api-reference/series.md
@@ -43,6 +43,7 @@
         - null_count
         - pipe
         - quantile
+        - rename
         - round
         - sample
         - scatter
diff --git a/narwhals/series.py b/narwhals/series.py
index ae78eef7..ab8b012b 100644
--- a/narwhals/series.py
+++ b/narwhals/series.py
@@ -1187,10 +1187,12 @@ class Series:
         Examples:
             >>> import pandas as pd
             >>> import polars as pl
+            >>> import pyarrow as pa
             >>> import narwhals as nw
             >>> s = [1, 2, 3]
             >>> s_pd = pd.Series(s, name="foo")
             >>> s_pl = pl.Series("foo", s)
+            >>> s_pa = pa.chunked_array([s])
 
             We define a library agnostic function:
 
@@ -1198,7 +1200,7 @@ class Series:
             ... def func(s):
             ...     return s.alias("bar")
 
-            We can then pass either pandas or Polars to `func`:
+            We can then pass any supported library such as pandas, Polars, or PyArrow:
 
             >>> func(s_pd)
             0    1
@@ -1213,9 +1215,70 @@ class Series:
                2
                3
             ]
+            >>> func(s_pa)  # doctest: +ELLIPSIS
+            <pyarrow.lib.ChunkedArray object at 0x...>
+            [
+              [
+                1,
+                2,
+                3
+              ]
+            ]
         """
         return self._from_compliant_series(self._compliant_series.alias(name=name))
 
+    def rename(self, name: str) -> Self:
+        """
+        Rename the Series.
+
+        Alias for `Series.alias()`.
+
+        Arguments:
+            name: The new name.
+
+        Examples:
+            >>> import pandas as pd
+            >>> import polars as pl
+            >>> import pyarrow as pa
+            >>> import narwhals as nw
+            >>> s = [1, 2, 3]
+            >>> s_pd = pd.Series(s, name="foo")
+            >>> s_pl = pl.Series("foo", s)
+            >>> s_pa = pa.chunked_array([s])
+
+            We define a library agnostic function:
+
+            >>> @nw.narwhalify
+            ... def func(s):
+            ...     return s.rename("bar")
+
+            We can then pass any supported library such as pandas, Polars, or PyArrow:
+
+            >>> func(s_pd)
+            0    1
+            1    2
+            2    3
+            Name: bar, dtype: int64
+            >>> func(s_pl)  # doctest: +NORMALIZE_WHITESPACE
+            shape: (3,)
+            Series: 'bar' [i64]
+            [
+               1
+               2
+               3
+            ]
+            >>> func(s_pa)  # doctest: +ELLIPSIS
+            <pyarrow.lib.ChunkedArray object at 0x...>
+            [
+              [
+                1,
+                2,
+                3
+              ]
+            ]
+        """
+        return self.alias(name=name)
+
     def sort(self, *, descending: bool = False, nulls_last: bool = False) -> Self:
         """
         Sort this Series. Place null values first.
diff --git a/utils/check_api_reference.py b/utils/check_api_reference.py
index d11c2bc9..410956e0 100644
--- a/utils/check_api_reference.py
+++ b/utils/check_api_reference.py
@@ -12,22 +12,23 @@ ret = 0
 NAMESPACES = {"dt", "str", "cat", "name"}
 EXPR_ONLY_METHODS = {"over"}
 SERIES_ONLY_METHODS = {
-    "to_arrow",
-    "to_dummies",
-    "to_pandas",
-    "to_list",
-    "to_numpy",
     "dtype",
-    "name",
-    "shape",
-    "to_frame",
     "is_empty",
     "is_sorted",
-    "value_counts",
-    "zip_with",
     "item",
+    "name",
+    "rename",
     "scatter",
+    "shape",
+    "to_arrow",
+    "to_dummies",
+    "to_frame",
+    "to_list",
     "to_native",
+    "to_numpy",
+    "to_pandas",
+    "value_counts",
+    "zip_with",
     "__iter__",
 }
 BASE_DTYPES = {"NumericType", "DType", "TemporalType"}


Test patch:
diff --git a/tests/series_only/alias_rename_test.py b/tests/series_only/alias_rename_test.py
new file mode 100644
index 00000000..4fa8a999
--- /dev/null
+++ b/tests/series_only/alias_rename_test.py
@@ -0,0 +1,13 @@
+import narwhals as nw
+from tests.utils import Constructor
+from tests.utils import compare_dicts
+
+
+def test_alias_rename(constructor_eager: Constructor) -> None:
+    data = [1, 2, 3]
+    expected = {"bar": data}
+    series = nw.from_native(constructor_eager({"foo": data}), eager_only=True)["foo"]
+    result = series.alias("bar").to_frame()
+    compare_dicts(result, expected)
+    result = series.rename("bar").to_frame()
+    compare_dicts(result, expected)