Skip to content

Commit

Permalink
feat: add extra overload for concat for when it is not known statical…
Browse files Browse the repository at this point in the history
…ly whether inputs are eager or lazy (#1783)
  • Loading branch information
MarcoGorelli authored Jan 11, 2025
1 parent 11b2f8a commit f1b9fd9
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 16 deletions.
6 changes: 1 addition & 5 deletions docs/api-completeness/index.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
# API Completeness

Narwhals has two different level of support for libraries: "full" and "interchange".

Libraries for which we have full support we intend to support the whole Narwhals API,
however this is a continuous work in progress.

In the following section it is possible to check which method is implemented for which
class and backend.

!!! info

- By design, Polars supports all the methods of the Narwhals API.
- "pandas-like" means pandas, cuDF and Modin.
- "spark-like" means PySpark, but we may extend this to also cover SQLFrame.
33 changes: 30 additions & 3 deletions narwhals/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from typing import Sequence
from typing import TypeVar
from typing import Union
from typing import overload

from narwhals._expression_parsing import extract_compliant
from narwhals._pandas_like.utils import broadcast_align_and_extract_native
Expand Down Expand Up @@ -38,7 +39,9 @@
from narwhals.dtypes import DType
from narwhals.schema import Schema
from narwhals.series import Series
from narwhals.typing import IntoDataFrameT
from narwhals.typing import IntoExpr
from narwhals.typing import IntoFrameT
from narwhals.typing import IntoSeriesT

class ArrowStreamExportable(Protocol):
Expand All @@ -47,11 +50,35 @@ def __arrow_c_stream__(
) -> object: ...


@overload
def concat(
items: Iterable[FrameT],
items: Iterable[DataFrame[IntoDataFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> FrameT:
) -> DataFrame[IntoDataFrameT]: ...


@overload
def concat(
items: Iterable[LazyFrame[IntoFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> LazyFrame[IntoFrameT]: ...


@overload
def concat(
items: Iterable[DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]: ...


def concat(
items: Iterable[DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]:
"""Concatenate multiple DataFrames, LazyFrames into a single entity.
Arguments:
Expand Down Expand Up @@ -197,7 +224,7 @@ def concat(
validate_laziness(items)
first_item = items[0]
plx = first_item.__narwhals_namespace__()
return first_item._from_compliant_dataframe( # type: ignore[return-value]
return first_item._from_compliant_dataframe(
plx.concat([df._compliant_frame for df in items], how=how),
)

Expand Down
22 changes: 15 additions & 7 deletions narwhals/stable/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3292,25 +3292,33 @@ def max_horizontal(*exprs: IntoExpr | Iterable[IntoExpr]) -> Expr:

@overload
def concat(
items: Iterable[DataFrame[Any]],
items: Iterable[DataFrame[IntoDataFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> DataFrame[Any]: ...
) -> DataFrame[IntoDataFrameT]: ...


@overload
def concat(
items: Iterable[LazyFrame[IntoFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> LazyFrame[IntoFrameT]: ...


@overload
def concat(
items: Iterable[LazyFrame[Any]],
items: Iterable[DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> LazyFrame[Any]: ...
) -> DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]: ...


def concat(
items: Iterable[DataFrame[Any] | LazyFrame[Any]],
items: Iterable[DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]],
*,
how: Literal["horizontal", "vertical", "diagonal"] = "vertical",
) -> DataFrame[Any] | LazyFrame[Any]:
) -> DataFrame[IntoDataFrameT] | LazyFrame[IntoFrameT]:
"""Concatenate multiple DataFrames, LazyFrames into a single entity.
Arguments:
Expand Down Expand Up @@ -3446,7 +3454,7 @@ def concat(
│ 4 ┆ null ┆ y │
└─────┴──────┴──────┘
"""
return _stableify(nw.concat(items, how=how)) # type: ignore[no-any-return]
return _stableify(nw.concat(items, how=how))


def concat_str(
Expand Down
2 changes: 1 addition & 1 deletion tests/frame/invalid_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_validate_laziness() -> None:
TypeError,
match=("The items to concatenate should either all be eager, or all lazy"),
):
nw.concat([nw.from_native(df, eager_only=True), nw.from_native(df).lazy()]) # type: ignore[list-item]
nw.concat([nw.from_native(df, eager_only=True), nw.from_native(df).lazy()])


@pytest.mark.slow
Expand Down

0 comments on commit f1b9fd9

Please sign in to comment.