|
47 | 47 | is_numpy_array_1d_int, |
48 | 48 | is_pandas_like_dataframe, |
49 | 49 | is_pandas_like_series, |
| 50 | + is_polars_series, |
50 | 51 | ) |
51 | 52 | from narwhals.exceptions import ColumnNotFoundError, DuplicateError, InvalidOperationError |
52 | 53 |
|
|
124 | 125 | CompliantLazyFrame, |
125 | 126 | CompliantSeries, |
126 | 127 | DTypes, |
| 128 | + EagerAllowed, |
127 | 129 | FileSource, |
128 | 130 | IntoSeriesT, |
129 | 131 | MultiIndexSelector, |
@@ -2120,3 +2122,58 @@ def extend_bool( |
2120 | 2122 | Stolen from https://github.com/pola-rs/polars/blob/b8bfb07a4a37a8d449d6d1841e345817431142df/py-polars/polars/_utils/various.py#L580-L594 |
2121 | 2123 | """ |
2122 | 2124 | return (value,) * n_match if isinstance(value, bool) else tuple(value) |
| 2125 | + |
| 2126 | + |
| 2127 | +class _CanTo_List(Protocol): # noqa: N801 |
| 2128 | + def to_list(self, *args: Any, **kwds: Any) -> list[Any]: ... |
| 2129 | + |
| 2130 | + |
| 2131 | +class _CanToList(Protocol): |
| 2132 | + def tolist(self, *args: Any, **kwds: Any) -> list[Any]: ... |
| 2133 | + |
| 2134 | + |
| 2135 | +class _CanTo_PyList(Protocol): # noqa: N801 |
| 2136 | + def to_pylist(self, *args: Any, **kwds: Any) -> list[Any]: ... |
| 2137 | + |
| 2138 | + |
| 2139 | +def can_to_list(obj: Any) -> TypeIs[_CanTo_List]: |
| 2140 | + return ( |
| 2141 | + is_narwhals_series(obj) |
| 2142 | + or is_polars_series(obj) |
| 2143 | + or _hasattr_static(obj, "to_list") |
| 2144 | + ) |
| 2145 | + |
| 2146 | + |
| 2147 | +def can_tolist(obj: Any) -> TypeIs[_CanToList]: |
| 2148 | + return is_numpy_array_1d(obj) or _hasattr_static(obj, "tolist") |
| 2149 | + |
| 2150 | + |
| 2151 | +def can_to_pylist(obj: Any) -> TypeIs[_CanTo_PyList]: |
| 2152 | + return ( |
| 2153 | + (pa := get_pyarrow()) and isinstance(obj, (pa.Array, pa.ChunkedArray)) |
| 2154 | + ) or _hasattr_static(obj, "to_pylist") |
| 2155 | + |
| 2156 | + |
| 2157 | +# TODO @dangotbanned: Use in `{Expr,Series}.is_in` |
| 2158 | +# TODO @dangotbanned: Add (brief) doc |
| 2159 | +def iterable_to_sequence( |
| 2160 | + iterable: Iterable[Any], /, *, backend: EagerAllowed | None = None |
| 2161 | +) -> Sequence[Any]: |
| 2162 | + result: Sequence[Any] |
| 2163 | + if backend is not None: |
| 2164 | + from narwhals.series import Series |
| 2165 | + |
| 2166 | + result = Series.from_iterable("", iterable, backend=backend).to_list() |
| 2167 | + elif isinstance(iterable, (tuple, list)): |
| 2168 | + result = iterable |
| 2169 | + elif isinstance(iterable, (Iterator, Sequence)): |
| 2170 | + result = tuple(iterable) |
| 2171 | + elif can_to_list(iterable): |
| 2172 | + result = iterable.to_list() |
| 2173 | + elif can_tolist(iterable): |
| 2174 | + result = iterable.tolist() |
| 2175 | + elif can_to_pylist(iterable): |
| 2176 | + result = iterable.to_pylist() |
| 2177 | + else: |
| 2178 | + result = tuple(iterable) |
| 2179 | + return result |
0 commit comments