Skip to content

enh: deprecate nw.new_series in favour of Series.from_iterable #2642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/downstream_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions docs/backcompat.md
Original file line number Diff line number Diff line change
Expand Up @@ -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_iterable`.

- Since Narwhals 1.35:

- pandas' ordered categoricals get mapped to `nw.Enum` instead of `nw.Categorical`.
Expand Down
17 changes: 16 additions & 1 deletion narwhals/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -179,6 +180,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.
Expand All @@ -205,7 +212,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)
Expand All @@ -219,6 +226,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_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",
)
backend = cast("ModuleType | Implementation | str", backend)
return _new_series_impl(name, values, dtype, backend=backend)

Expand Down
53 changes: 52 additions & 1 deletion narwhals/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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_iterable(name="price", values=[10.5, 9.4], backend="pandas")
```
"""

Expand All @@ -97,6 +100,54 @@ def __init__(
msg = f"Expected Polars Series or an object which implements `__narwhals_series__`, got: {type(series)}."
raise AssertionError(msg)

@classmethod
def from_iterable(
cls,
name: str,
values: Any,
dtype: DType | type[DType] | None = None,
*,
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.<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`.

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
def implementation(self) -> Implementation:
"""Return implementation of native Series.
Expand Down
6 changes: 6 additions & 0 deletions narwhals/stable/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 12 additions & 3 deletions tests/new_series_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,26 @@

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
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_iterable(
"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:
Expand All @@ -46,4 +55,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))
4 changes: 3 additions & 1 deletion tests/v1_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]})
Expand Down
Loading