From 103116c8b176c78d89609cbc7673e9eaf32f370d Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:33:26 +0200 Subject: [PATCH 1/6] enh: deprecate `nw.new_series` in favour of `Series.from_arraylike` --- docs/backcompat.md | 6 ++++++ narwhals/functions.py | 9 +++++++++ narwhals/series.py | 16 +++++++++++++++- tests/new_series_test.py | 12 ++++++++++-- tests/v1_test.py | 4 +++- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/docs/backcompat.md b/docs/backcompat.md index 911b852a03..c7f3e73975 100644 --- a/docs/backcompat.md +++ b/docs/backcompat.md @@ -111,6 +111,12 @@ Which should you use? In general we recommend: ## `main` vs `stable.v1` +- Since Narwhals 1.42.0: + + - The DataFrame Interchange Protocol is no longer supported in the + main Narwhals namespace. + - `nw.new_series` is deprecated in favour of `nw.Series.from_arraylike`. + - Since Narwhals 1.35: - pandas' ordered categoricals get mapped to `nw.Enum` instead of `nw.Categorical`. diff --git a/narwhals/functions.py b/narwhals/functions.py index 7a12e4e5e5..50071be86f 100644 --- a/narwhals/functions.py +++ b/narwhals/functions.py @@ -31,6 +31,7 @@ is_compliant_expr, is_eager_allowed, is_sequence_but_not_str, + issue_deprecation_warning, parse_version, supports_arrow_c_stream, validate_laziness, @@ -219,6 +220,14 @@ def new_series( |Name: a, dtype: int32| └─────────────────────┘ """ + issue_deprecation_warning( + "`new_series` is deprecated in the main `narwhals` namespace.\n\n" + "You may want to:\n" + " - Use `Series.from_arraylike` instead.\n" + " - Use `narwhals.stable.v1`, where it is still supported.\n" + " - See https://narwhals-dev.github.io/narwhals/backcompat\n", + "1.42.0", + ) backend = cast("ModuleType | Implementation | str", backend) return _new_series_impl(name, values, dtype, backend=backend) diff --git a/narwhals/series.py b/narwhals/series.py index 77029510ad..fec784170f 100644 --- a/narwhals/series.py +++ b/narwhals/series.py @@ -16,6 +16,7 @@ from narwhals.dependencies import is_numpy_scalar from narwhals.dtypes import _validate_dtype from narwhals.exceptions import ComputeError +from narwhals.functions import _new_series_impl from narwhals.series_cat import SeriesCatNamespace from narwhals.series_dt import SeriesDateTimeNamespace from narwhals.series_list import SeriesListNamespace @@ -75,7 +76,9 @@ class Series(Generic[IntoSeriesT]): - If the object is a generic sequence (e.g. a list or a tuple of values), you can create a series via [`narwhals.new_series`][], e.g.: ```py - narwhals.new_series(name="price", values=[10.5, 9.4, 1.2], backend="pandas") + import narwhals as nw + + nw.Series.from_arraylike(name="price", values=[10.5, 9.4], backend="pandas") ``` """ @@ -97,6 +100,17 @@ def __init__( msg = f"Expected Polars Series or an object which implements `__narwhals_series__`, got: {type(series)}." raise AssertionError(msg) + @classmethod + def from_arraylike( + cls, + name: str, + values: Any, + dtype: DType | type[DType] | None = None, + *, + backend: ModuleType | Implementation | str, + ) -> Series[Any]: + return _new_series_impl(name, values, dtype, backend=backend) + @property def implementation(self) -> Implementation: """Return implementation of native Series. diff --git a/tests/new_series_test.py b/tests/new_series_test.py index f37e419688..9d58740d9e 100644 --- a/tests/new_series_test.py +++ b/tests/new_series_test.py @@ -17,10 +17,18 @@ def test_new_series(constructor_eager: ConstructorEager) -> None: assert result.dtype == nw.Int64 assert_equal_data(result.to_frame(), expected) - result = nw.new_series("b", [4, 1, 2], nw.Int32, backend=nw.get_native_namespace(s)) + with pytest.deprecated_call(): + result = nw.new_series( + "b", [4, 1, 2], nw.Int32, backend=nw.get_native_namespace(s) + ) expected = {"b": [4, 1, 2]} assert result.dtype == nw.Int32 assert_equal_data(result.to_frame(), expected) + result = nw.Series.from_arraylike( + "b", [4, 1, 2], nw.Int32, backend=nw.get_native_namespace(s) + ) + assert result.dtype == nw.Int32 + assert_equal_data(result.to_frame(), expected) def test_new_series_v1(constructor_eager: ConstructorEager) -> None: @@ -46,4 +54,4 @@ def test_new_series_dask() -> None: df = nw.from_native(dd.from_pandas(pd.DataFrame({"a": [1, 2, 3]}))) with pytest.raises(ValueError, match="lazy-only"): - nw.new_series("a", [1, 2, 3], backend=nw.get_native_namespace(df)) + nw_v1.new_series("a", [1, 2, 3], backend=nw.get_native_namespace(df)) diff --git a/tests/v1_test.py b/tests/v1_test.py index 858bc9f0f2..f0ec2170fb 100644 --- a/tests/v1_test.py +++ b/tests/v1_test.py @@ -78,7 +78,9 @@ def test_constructors() -> None: pytest.importorskip("pyarrow") if PANDAS_VERSION < (2, 2): pytest.skip() - assert nw_v1.new_series("a", [1, 2, 3], backend="pandas").to_list() == [1, 2, 3] + result_s = nw_v1.new_series("a", [1, 2, 3], backend="pandas") + assert result_s.to_list() == [1, 2, 3] + assert isinstance(result_s, nw_v1.Series) arr: np.ndarray[tuple[int, int], Any] = np.array([[1, 2], [3, 4]]) # pyright: ignore[reportAssignmentType] result = nw_v1.from_numpy(arr, schema=["a", "b"], backend="pandas") assert_equal_data(result, {"a": [1, 3], "b": [2, 4]}) From f5610718e99edd9cd2993dfeb6bfd0b13aa25bc7 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:55:07 +0200 Subject: [PATCH 2/6] catch all dep calls --- tests/new_series_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/new_series_test.py b/tests/new_series_test.py index 9d58740d9e..f9625192c0 100644 --- a/tests/new_series_test.py +++ b/tests/new_series_test.py @@ -10,7 +10,8 @@ def test_new_series(constructor_eager: ConstructorEager) -> None: s = nw.from_native(constructor_eager({"a": [1, 2, 3]}), eager_only=True)["a"] - result = nw.new_series("b", [4, 1, 2], backend=nw.get_native_namespace(s)) + with pytest.deprecated_call(): + result = nw.new_series("b", [4, 1, 2], backend=nw.get_native_namespace(s)) expected = {"b": [4, 1, 2]} # all supported libraries auto-infer this to be int64, we can always special-case # something different if necessary From 94ae410c1cc66bc055d519f5b9a3a16e33e85528 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:38:25 +0200 Subject: [PATCH 3/6] from_arraylike -> from_iterable --- docs/backcompat.md | 2 +- narwhals/functions.py | 2 +- narwhals/series.py | 4 ++-- tests/new_series_test.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/backcompat.md b/docs/backcompat.md index c7f3e73975..ce4de8fdb5 100644 --- a/docs/backcompat.md +++ b/docs/backcompat.md @@ -115,7 +115,7 @@ Which should you use? In general we recommend: - The DataFrame Interchange Protocol is no longer supported in the main Narwhals namespace. - - `nw.new_series` is deprecated in favour of `nw.Series.from_arraylike`. + - `nw.new_series` is deprecated in favour of `nw.Series.from_iterable`. - Since Narwhals 1.35: diff --git a/narwhals/functions.py b/narwhals/functions.py index 50071be86f..7538183910 100644 --- a/narwhals/functions.py +++ b/narwhals/functions.py @@ -223,7 +223,7 @@ def new_series( issue_deprecation_warning( "`new_series` is deprecated in the main `narwhals` namespace.\n\n" "You may want to:\n" - " - Use `Series.from_arraylike` instead.\n" + " - Use `Series.from_iterable` instead.\n" " - Use `narwhals.stable.v1`, where it is still supported.\n" " - See https://narwhals-dev.github.io/narwhals/backcompat\n", "1.42.0", diff --git a/narwhals/series.py b/narwhals/series.py index fec784170f..8c9a6fe26f 100644 --- a/narwhals/series.py +++ b/narwhals/series.py @@ -78,7 +78,7 @@ class Series(Generic[IntoSeriesT]): ```py import narwhals as nw - nw.Series.from_arraylike(name="price", values=[10.5, 9.4], backend="pandas") + nw.Series.from_iterable(name="price", values=[10.5, 9.4], backend="pandas") ``` """ @@ -101,7 +101,7 @@ def __init__( raise AssertionError(msg) @classmethod - def from_arraylike( + def from_iterable( cls, name: str, values: Any, diff --git a/tests/new_series_test.py b/tests/new_series_test.py index f9625192c0..68bce4c91a 100644 --- a/tests/new_series_test.py +++ b/tests/new_series_test.py @@ -25,7 +25,7 @@ def test_new_series(constructor_eager: ConstructorEager) -> None: expected = {"b": [4, 1, 2]} assert result.dtype == nw.Int32 assert_equal_data(result.to_frame(), expected) - result = nw.Series.from_arraylike( + result = nw.Series.from_iterable( "b", [4, 1, 2], nw.Int32, backend=nw.get_native_namespace(s) ) assert result.dtype == nw.Int32 From 70559f1f21121c7d932cd2d30fe25bcd6816c70e Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Thu, 5 Jun 2025 12:55:06 +0200 Subject: [PATCH 4/6] doctest --- narwhals/functions.py | 7 ++++++- narwhals/series.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/narwhals/functions.py b/narwhals/functions.py index 7538183910..149aa42a71 100644 --- a/narwhals/functions.py +++ b/narwhals/functions.py @@ -180,6 +180,11 @@ def new_series( ) -> Series[Any]: """Instantiate Narwhals Series from iterable (e.g. list or array). + Warning: + `LazyFrame.gather_every` is deprecated and will be removed in a future version. + Note: this will remain available in `narwhals.stable.v1`. + See [stable api](../backcompat.md/) for more information. + Arguments: name: Name of resulting Series. values: Values of make Series from. @@ -206,7 +211,7 @@ def new_series( Examples: >>> import pandas as pd - >>> import narwhals as nw + >>> import narwhals.stable.v1 as nw >>> >>> values = [4, 1, 2, 3] >>> nw.new_series(name="a", values=values, dtype=nw.Int32, backend=pd) diff --git a/narwhals/series.py b/narwhals/series.py index 8c9a6fe26f..13bf083606 100644 --- a/narwhals/series.py +++ b/narwhals/series.py @@ -109,6 +109,43 @@ def from_iterable( *, backend: ModuleType | Implementation | str, ) -> Series[Any]: + """Instantiate Narwhals Series from iterable (e.g. list or array). + + Arguments: + name: Name of resulting Series. + values: Values of make Series from. + dtype: (Narwhals) dtype. If not provided, the native library + may auto-infer it from `values`. + backend: specifies which eager backend instantiate to. + + `backend` can be specified in various ways + + - As `Implementation.` 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`. + + Returns: + A new Series + + Examples: + >>> import pandas as pd + >>> import narwhals as nw + >>> + >>> values = [4, 1, 2, 3] + >>> nw.Series.from_iterable( + ... name="a", values=values, dtype=nw.Int32, backend=pd + ... ) + ┌─────────────────────┐ + | Narwhals Series | + |---------------------| + |0 4 | + |1 1 | + |2 2 | + |3 3 | + |Name: a, dtype: int32| + └─────────────────────┘ + """ return _new_series_impl(name, values, dtype, backend=backend) @property From 29ecf961ae131316fb1f792145c65f02fcaf6383 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:01:35 +0200 Subject: [PATCH 5/6] fixup deprecated warning --- narwhals/functions.py | 3 ++- narwhals/stable/v1/__init__.py | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/narwhals/functions.py b/narwhals/functions.py index 149aa42a71..3b53aeb212 100644 --- a/narwhals/functions.py +++ b/narwhals/functions.py @@ -181,7 +181,8 @@ def new_series( """Instantiate Narwhals Series from iterable (e.g. list or array). Warning: - `LazyFrame.gather_every` is deprecated and will be removed in a future version. + `new_series` is deprecated and will be removed in a future version. + Please use `Series.from_iterable` instead. Note: this will remain available in `narwhals.stable.v1`. See [stable api](../backcompat.md/) for more information. diff --git a/narwhals/stable/v1/__init__.py b/narwhals/stable/v1/__init__.py index 0d7b39588f..d2d173c5eb 100644 --- a/narwhals/stable/v1/__init__.py +++ b/narwhals/stable/v1/__init__.py @@ -1474,6 +1474,12 @@ def new_series( ) -> Series[Any]: """Instantiate Narwhals Series from iterable (e.g. list or array). + Warning: + `new_series` is deprecated and will be removed in a future version. + Please use `Series.from_iterable` instead. + Note: this will remain available in `narwhals.stable.v1`. + See [stable api](../backcompat.md/) for more information. + Arguments: name: Name of resulting Series. values: Values of make Series from. From 559e3d14f1adc3e20a18e211e53128905f7672bf Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:11:40 +0200 Subject: [PATCH 6/6] silence deprecation warning for tubular --- .github/workflows/downstream_tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/downstream_tests.yml b/.github/workflows/downstream_tests.yml index c608413d8b..cc6e0181fb 100644 --- a/.github/workflows/downstream_tests.yml +++ b/.github/workflows/downstream_tests.yml @@ -284,7 +284,8 @@ jobs: - name: Run pytest run: | cd tubular - pytest tests --config-file=pyproject.toml + # remove `-W ignore` once they address `new_series` deprecation + pytest tests --config-file=pyproject.toml -W ignore plotly: strategy: