11# Copyright 2024 Marimo. All rights reserved.
22from __future__ import annotations
33
4- from typing import Any , Generic , TypeVar
4+ from typing import TYPE_CHECKING , TypeVar
55
6- from narwhals .dependencies import is_narwhals_dataframe
7-
8- from marimo ._dependencies .dependencies import DependencyManager
96from marimo ._plugins .ui ._impl .dataframes .transforms .handlers import (
10- IbisTransformHandler ,
11- PandasTransformHandler ,
12- PolarsTransformHandler ,
7+ NarwhalsTransformHandler ,
138)
149from marimo ._plugins .ui ._impl .dataframes .transforms .types import (
10+ DataFrameType ,
1511 Transform ,
1612 Transformations ,
1713 TransformHandler ,
1814 TransformType ,
1915)
2016from marimo ._utils .assert_never import assert_never
17+ from marimo ._utils .narwhals_utils import can_narwhalify , is_narwhals_lazyframe
2118
2219T = TypeVar ("T" )
2320
2421
22+ if TYPE_CHECKING :
23+ import narwhals .stable .v2 as nw
24+ from narwhals .typing import IntoLazyFrame
25+
26+
2527def _handle (df : T , handler : TransformHandler [T ], transform : Transform ) -> T :
2628 if transform .type is TransformType .COLUMN_CONVERSION :
2729 return handler .handle_column_conversion (df , transform )
@@ -50,6 +52,33 @@ def _handle(df: T, handler: TransformHandler[T], transform: Transform) -> T:
5052 assert_never (transform .type )
5153
5254
55+ def apply_transforms_to_df (
56+ df : DataFrameType , transform : Transform
57+ ) -> DataFrameType :
58+ """Apply a transform to a dataframe using NarwhalsTransformHandler."""
59+ if not can_narwhalify (df ):
60+ raise ValueError (
61+ f"Unsupported dataframe type. Must be Pandas, Polars, Ibis, Pyarrow, or DuckDB. Got: { type (df )} "
62+ )
63+
64+ import narwhals .stable .v2 as nw
65+
66+ nw_df = nw .from_native (df )
67+ was_lazy = is_narwhals_lazyframe (nw_df )
68+ nw_df = nw_df .lazy ()
69+
70+ result_nw = _apply_transforms (
71+ nw_df ,
72+ NarwhalsTransformHandler (),
73+ Transformations (transforms = [transform ]),
74+ )
75+
76+ if was_lazy :
77+ return result_nw .to_native ()
78+
79+ return result_nw .collect ().to_native () # type: ignore[no-any-return]
80+
81+
5382def _apply_transforms (
5483 df : T , handler : TransformHandler [T ], transforms : Transformations
5584) -> T :
@@ -61,54 +90,39 @@ def _apply_transforms(
6190
6291
6392def get_handler_for_dataframe (
64- df : Any ,
65- ) -> TransformHandler [ Any ] :
93+ df : DataFrameType ,
94+ ) -> NarwhalsTransformHandler :
6695 """
6796 Gets the handler for the given dataframe.
6897
6998 raises ValueError if the dataframe type is not supported.
7099 """
71- if DependencyManager .pandas .imported ():
72- import pandas as pd
73-
74- if isinstance (df , pd .DataFrame ):
75- return PandasTransformHandler ()
76- if DependencyManager .polars .imported ():
77- import polars as pl
78-
79- if isinstance (df , pl .DataFrame ):
80- return PolarsTransformHandler ()
100+ if not can_narwhalify (df ):
101+ raise ValueError (
102+ f"Unsupported dataframe type. Must be Pandas, Polars, Ibis, Pyarrow, or DuckDB. Got: { type (df )} "
103+ )
81104
82- if DependencyManager .ibis .imported ():
83- import ibis # type: ignore
84-
85- if isinstance (df , ibis .Table ):
86- return IbisTransformHandler ()
87-
88- if DependencyManager .narwhals .imported ():
89- if is_narwhals_dataframe (df ):
90- return get_handler_for_dataframe (df .to_native ())
91-
92- raise ValueError (
93- "Unsupported dataframe type. Must be Pandas or Polars."
94- f" Got: { type (df )} "
95- )
105+ return NarwhalsTransformHandler ()
96106
97107
98- class TransformsContainer ( Generic [ T ]) :
108+ class TransformsContainer :
99109 """
100110 Keeps internal state of the last transformation applied to the dataframe.
101111 So that we can incrementally apply transformations.
102112 """
103113
104- def __init__ (self , df : T , handler : TransformHandler [T ]) -> None :
114+ def __init__ (
115+ self ,
116+ df : nw .LazyFrame [IntoLazyFrame ],
117+ handler : NarwhalsTransformHandler ,
118+ ) -> None :
105119 self ._original_df = df
106120 # The dataframe for the given transform.
107121 self ._snapshot_df = df
108122 self ._handler = handler
109123 self ._transforms : list [Transform ] = []
110124
111- def apply (self , transform : Transformations ) -> T :
125+ def apply (self , transform : Transformations ) -> nw . LazyFrame [ IntoLazyFrame ] :
112126 """
113127 Applies the given transformations to the dataframe.
114128 """
0 commit comments