diff --git a/docs/backcompat.md b/docs/backcompat.md index 807d51ed6..2090eae75 100644 --- a/docs/backcompat.md +++ b/docs/backcompat.md @@ -99,27 +99,8 @@ before making any change. ### After `stable.v1` -- Since Narwhals 1.13.0, the `strict` parameter in `from_native`, `to_native`, and `narwhalify` - has been deprecated in favour of `pass_through`. This is because several users expressed - confusion/surprise over what `strict=False` did. - ```python - # v1 syntax: - nw.from_native(df, strict=False) - - # main namespace (and, when we get there, v2) syntax: - nw.from_native(df, pass_through=True) - ``` - If you are using Narwhals>=1.13.0, then we recommend using `pass_through`, as that - works consistently across namespaces. - - In the future: - - - in the main Narwhals namespace, `strict` will be removed in favour of `pass_through` - - in `stable.v1`, we will keep both `strict` and `pass_through` - -- Since Narwhals 1.9.0, `Datetime` and `Duration` dtypes hash using both `time_unit` and - `time_zone`. - The effect of this can be seen when placing these dtypes in sets: +- `Datetime` and `Duration` dtypes hash using both `time_unit` and `time_zone`. + The effect of this can be seen when doing `dtype in {...}` checks: ```python exec="1" source="above" session="backcompat" import narwhals.stable.v1 as nw_v1 diff --git a/narwhals/dataframe.py b/narwhals/dataframe.py index bf8bb5c98..3ddaa2814 100644 --- a/narwhals/dataframe.py +++ b/narwhals/dataframe.py @@ -2874,7 +2874,7 @@ def to_native(self) -> FrameT: └─────┴─────┴─────┘ """ - return to_native(narwhals_object=self, pass_through=False) + return to_native(narwhals_object=self, strict=True) # inherited def pipe(self, function: Callable[[Any], Self], *args: Any, **kwargs: Any) -> Self: diff --git a/narwhals/functions.py b/narwhals/functions.py index 20efa7b45..b8dfffbeb 100644 --- a/narwhals/functions.py +++ b/narwhals/functions.py @@ -361,7 +361,7 @@ def _from_dict_impl( else: msg = "Calling `from_dict` without `native_namespace` is only supported if all input values are already Narwhals Series" raise TypeError(msg) - data = {key: to_native(value, pass_through=True) for key, value in data.items()} + data = {key: to_native(value, strict=False) for key, value in data.items()} implementation = Implementation.from_native_namespace(native_namespace) if implementation is Implementation.POLARS: diff --git a/narwhals/stable/v1/__init__.py b/narwhals/stable/v1/__init__.py index 20f6fee35..5bc762dda 100644 --- a/narwhals/stable/v1/__init__.py +++ b/narwhals/stable/v1/__init__.py @@ -63,7 +63,6 @@ from narwhals.utils import maybe_get_index from narwhals.utils import maybe_reset_index from narwhals.utils import maybe_set_index -from narwhals.utils import validate_strict_and_pass_though if TYPE_CHECKING: from types import ModuleType @@ -776,212 +775,12 @@ def from_native( """ -@overload -def from_native( - native_object: IntoDataFrameT | IntoSeriesT, - *, - pass_through: Literal[True], - eager_only: None = ..., - eager_or_interchange_only: Literal[True], - series_only: None = ..., - allow_series: Literal[True], -) -> DataFrame[IntoDataFrameT]: ... - - -@overload -def from_native( - native_object: IntoDataFrameT | IntoSeriesT, - *, - pass_through: Literal[True], - eager_only: Literal[True], - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: Literal[True], -) -> DataFrame[IntoDataFrameT] | Series: ... - - -@overload -def from_native( - native_object: IntoDataFrameT, - *, - pass_through: Literal[True], - eager_only: None = ..., - eager_or_interchange_only: Literal[True], - series_only: None = ..., - allow_series: None = ..., -) -> DataFrame[IntoDataFrameT]: ... - - -@overload -def from_native( - native_object: T, - *, - pass_through: Literal[True], - eager_only: None = ..., - eager_or_interchange_only: Literal[True], - series_only: None = ..., - allow_series: None = ..., -) -> T: ... - - -@overload -def from_native( - native_object: IntoDataFrameT, - *, - pass_through: Literal[True], - eager_only: Literal[True], - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: None = ..., -) -> DataFrame[IntoDataFrameT]: ... - - -@overload -def from_native( - native_object: T, - *, - pass_through: Literal[True], - eager_only: Literal[True], - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: None = ..., -) -> T: ... - - -@overload -def from_native( - native_object: IntoFrameT | IntoSeriesT, - *, - pass_through: Literal[True], - eager_only: None = ..., - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: Literal[True], -) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT] | Series: ... - - -@overload -def from_native( - native_object: IntoSeriesT, - *, - pass_through: Literal[True], - eager_only: None = ..., - eager_or_interchange_only: None = ..., - series_only: Literal[True], - allow_series: None = ..., -) -> Series: ... - - -@overload -def from_native( - native_object: IntoFrameT, - *, - pass_through: Literal[True], - eager_only: None = ..., - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: None = ..., -) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: ... - - -@overload -def from_native( - native_object: T, - *, - pass_through: Literal[True], - eager_only: None = ..., - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: None = ..., -) -> T: ... - - -@overload -def from_native( - native_object: IntoDataFrameT, - *, - pass_through: Literal[False] = ..., - eager_only: None = ..., - eager_or_interchange_only: Literal[True], - series_only: None = ..., - allow_series: None = ..., -) -> DataFrame[IntoDataFrameT]: - """ - from_native(df, pass_through=False, eager_or_interchange_only=True) - from_native(df, eager_or_interchange_only=True) - """ - - -@overload -def from_native( - native_object: IntoDataFrameT, - *, - pass_through: Literal[False] = ..., - eager_only: Literal[True], - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: None = ..., -) -> DataFrame[IntoDataFrameT]: - """ - from_native(df, pass_through=False, eager_only=True) - from_native(df, eager_only=True) - """ - - -@overload -def from_native( - native_object: IntoFrameT | IntoSeriesT, - *, - pass_through: Literal[False] = ..., - eager_only: None = ..., - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: Literal[True], -) -> DataFrame[Any] | LazyFrame[Any] | Series: - """ - from_native(df, pass_through=False, allow_series=True) - from_native(df, allow_series=True) - """ - - -@overload -def from_native( - native_object: IntoSeriesT, - *, - pass_through: Literal[False] = ..., - eager_only: None = ..., - eager_or_interchange_only: None = ..., - series_only: Literal[True], - allow_series: None = ..., -) -> Series: - """ - from_native(df, pass_through=False, series_only=True) - from_native(df, series_only=True) - """ - - -@overload -def from_native( - native_object: IntoFrameT, - *, - pass_through: Literal[False] = ..., - eager_only: None = ..., - eager_or_interchange_only: None = ..., - series_only: None = ..., - allow_series: None = ..., -) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: - """ - from_native(df, pass_through=False) - from_native(df) - """ - - # All params passed in as variables @overload def from_native( native_object: Any, *, - pass_through: bool, + strict: bool, eager_only: bool | None, eager_or_interchange_only: bool | None = None, series_only: bool | None, @@ -992,8 +791,7 @@ def from_native( def from_native( native_object: Any, *, - strict: bool | None = None, - pass_through: bool | None = None, + strict: bool = True, eager_only: bool | None = None, eager_or_interchange_only: bool | None = None, series_only: bool | None = None, @@ -1013,19 +811,8 @@ def from_native( - pandas.Series - polars.Series - anything with a `__narwhals_series__` method - strict: Determine what happens if the object isn't supported by Narwhals: - - - `True` (default): raise an error - - `False`: pass object through as-is - - **Deprecated** (v1.13.0): - Please use `pass_through` instead. Note that `strict` is still available - (and won't emit a deprecation warning) if you use `narwhals.stable.v1`, - see [perfect backwards compatibility policy](https://narwhals-dev.github.io/narwhals/backcompat/). - pass_through: Determine what happens if the object isn't supported by Narwhals: - - - `False` (default): raise an error - - `True`: pass object through as-is + strict: Whether to raise if object can't be converted (default) or + to just leave it as-is. eager_only: Whether to only allow eager objects. eager_or_interchange_only: Whether to only allow eager objects or objects which implement the Dataframe Interchange Protocol. @@ -1042,14 +829,9 @@ def from_native( return native_object if isinstance(native_object, Series) and (series_only or allow_series): return native_object - - pass_through = validate_strict_and_pass_though( - strict, pass_through, pass_through_default=False, emit_deprecation_warning=False - ) - result = _from_native_impl( native_object, - pass_through=pass_through, + strict=strict, eager_only=eager_only, eager_or_interchange_only=eager_or_interchange_only, series_only=series_only, @@ -1062,8 +844,7 @@ def from_native( def narwhalify( func: Callable[..., Any] | None = None, *, - strict: bool | None = None, - pass_through: bool | None = None, + strict: bool = False, eager_only: bool | None = False, eager_or_interchange_only: bool | None = False, series_only: bool | None = False, @@ -1124,17 +905,13 @@ def func(df): allow_series: Whether to allow series (default is only dataframe / lazyframe). """ - pass_through = validate_strict_and_pass_though( - strict, pass_through, pass_through_default=True, emit_deprecation_warning=False - ) - def decorator(func: Callable[..., Any]) -> Callable[..., Any]: @wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: args = [ from_native( arg, - pass_through=pass_through, + strict=strict, eager_only=eager_only, eager_or_interchange_only=eager_or_interchange_only, series_only=series_only, @@ -1146,7 +923,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: kwargs = { name: from_native( value, - pass_through=pass_through, + strict=strict, eager_only=eager_only, eager_or_interchange_only=eager_or_interchange_only, series_only=series_only, @@ -1167,7 +944,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: result = func(*args, **kwargs) - return to_native(result, pass_through=pass_through) + return to_native(result, strict=strict) return wrapper diff --git a/narwhals/translate.py b/narwhals/translate.py index 129fe671f..65cc44226 100644 --- a/narwhals/translate.py +++ b/narwhals/translate.py @@ -57,23 +57,22 @@ @overload def to_native( - narwhals_object: DataFrame[IntoDataFrameT], *, pass_through: Literal[False] = ... + narwhals_object: DataFrame[IntoDataFrameT], *, strict: Literal[True] = ... ) -> IntoDataFrameT: ... @overload def to_native( - narwhals_object: LazyFrame[IntoFrameT], *, pass_through: Literal[False] = ... + narwhals_object: LazyFrame[IntoFrameT], *, strict: Literal[True] = ... ) -> IntoFrameT: ... @overload -def to_native(narwhals_object: Series, *, pass_through: Literal[False] = ...) -> Any: ... +def to_native(narwhals_object: Series, *, strict: Literal[True] = ...) -> Any: ... @overload -def to_native(narwhals_object: Any, *, pass_through: bool) -> Any: ... +def to_native(narwhals_object: Any, *, strict: bool) -> Any: ... def to_native( narwhals_object: DataFrame[IntoFrameT] | LazyFrame[IntoFrameT] | Series, *, - strict: bool | None = None, - pass_through: bool | None = None, + strict: bool = True, ) -> IntoFrameT | Any: """ Convert Narwhals object to native one. @@ -87,18 +86,13 @@ def to_native( """ from narwhals.dataframe import BaseFrame from narwhals.series import Series - from narwhals.utils import validate_strict_and_pass_though - - pass_through = validate_strict_and_pass_though( - strict, pass_through, pass_through_default=False, emit_deprecation_warning=True - ) if isinstance(narwhals_object, BaseFrame): return narwhals_object._compliant_frame._native_frame if isinstance(narwhals_object, Series): return narwhals_object._compliant_series._native_series - if not pass_through: + if strict: msg = f"Expected Narwhals object, got {type(narwhals_object)}." raise TypeError(msg) return narwhals_object @@ -108,7 +102,7 @@ def to_native( def from_native( native_object: IntoDataFrameT | IntoSeriesT, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: None = ..., eager_or_interchange_only: Literal[True], series_only: None = ..., @@ -120,7 +114,7 @@ def from_native( def from_native( native_object: IntoDataFrameT | IntoSeriesT, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: Literal[True], eager_or_interchange_only: None = ..., series_only: None = ..., @@ -132,7 +126,7 @@ def from_native( def from_native( native_object: IntoDataFrameT, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: None = ..., eager_or_interchange_only: Literal[True], series_only: None = ..., @@ -144,7 +138,7 @@ def from_native( def from_native( native_object: T, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: None = ..., eager_or_interchange_only: Literal[True], series_only: None = ..., @@ -156,7 +150,7 @@ def from_native( def from_native( native_object: IntoDataFrameT, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: Literal[True], eager_or_interchange_only: None = ..., series_only: None = ..., @@ -168,7 +162,7 @@ def from_native( def from_native( native_object: T, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: Literal[True], eager_or_interchange_only: None = ..., series_only: None = ..., @@ -180,7 +174,7 @@ def from_native( def from_native( native_object: IntoFrameT | IntoSeriesT, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: None = ..., eager_or_interchange_only: None = ..., series_only: None = ..., @@ -192,7 +186,7 @@ def from_native( def from_native( native_object: IntoSeriesT, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: None = ..., eager_or_interchange_only: None = ..., series_only: Literal[True], @@ -204,7 +198,7 @@ def from_native( def from_native( native_object: IntoFrameT, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: None = ..., eager_or_interchange_only: None = ..., series_only: None = ..., @@ -216,7 +210,7 @@ def from_native( def from_native( native_object: T, *, - pass_through: Literal[True], + strict: Literal[False], eager_only: None = ..., eager_or_interchange_only: None = ..., series_only: None = ..., @@ -228,14 +222,14 @@ def from_native( def from_native( native_object: IntoDataFrameT, *, - pass_through: Literal[False] = ..., + strict: Literal[True] = ..., eager_only: None = ..., eager_or_interchange_only: Literal[True], series_only: None = ..., allow_series: None = ..., ) -> DataFrame[IntoDataFrameT]: """ - from_native(df, pass_through=False, eager_or_interchange_only=True) + from_native(df, strict=True, eager_or_interchange_only=True) from_native(df, eager_or_interchange_only=True) """ @@ -244,14 +238,14 @@ def from_native( def from_native( native_object: IntoDataFrameT, *, - pass_through: Literal[False] = ..., + strict: Literal[True] = ..., eager_only: Literal[True], eager_or_interchange_only: None = ..., series_only: None = ..., allow_series: None = ..., ) -> DataFrame[IntoDataFrameT]: """ - from_native(df, pass_through=False, eager_only=True) + from_native(df, strict=True, eager_only=True) from_native(df, eager_only=True) """ @@ -260,14 +254,14 @@ def from_native( def from_native( native_object: IntoFrameT | IntoSeriesT, *, - pass_through: Literal[False] = ..., + strict: Literal[True] = ..., eager_only: None = ..., eager_or_interchange_only: None = ..., series_only: None = ..., allow_series: Literal[True], ) -> DataFrame[Any] | LazyFrame[Any] | Series: """ - from_native(df, pass_through=False, allow_series=True) + from_native(df, strict=True, allow_series=True) from_native(df, allow_series=True) """ @@ -276,14 +270,14 @@ def from_native( def from_native( native_object: IntoSeriesT, *, - pass_through: Literal[False] = ..., + strict: Literal[True] = ..., eager_only: None = ..., eager_or_interchange_only: None = ..., series_only: Literal[True], allow_series: None = ..., ) -> Series: """ - from_native(df, pass_through=False, series_only=True) + from_native(df, strict=True, series_only=True) from_native(df, series_only=True) """ @@ -292,14 +286,14 @@ def from_native( def from_native( native_object: IntoFrameT, *, - pass_through: Literal[False] = ..., + strict: Literal[True] = ..., eager_only: None = ..., eager_or_interchange_only: None = ..., series_only: None = ..., allow_series: None = ..., ) -> DataFrame[IntoFrameT] | LazyFrame[IntoFrameT]: """ - from_native(df, pass_through=False) + from_native(df, strict=True) from_native(df) """ @@ -309,7 +303,7 @@ def from_native( def from_native( native_object: Any, *, - pass_through: bool, + strict: bool, eager_only: bool | None, eager_or_interchange_only: bool | None = None, series_only: bool | None, @@ -320,8 +314,7 @@ def from_native( def from_native( native_object: Any, *, - strict: bool | None = None, - pass_through: bool | None = None, + strict: bool = True, eager_only: bool | None = None, eager_or_interchange_only: bool | None = None, series_only: bool | None = None, @@ -341,19 +334,8 @@ def from_native( - pandas.Series - polars.Series - anything with a `__narwhals_series__` method - strict: Determine what happens if the object isn't supported by Narwhals: - - - `True` (default): raise an error - - `False`: pass object through as-is - - **Deprecated** (v1.13.0): - Please use `pass_through` instead. Note that `strict` is still available - (and won't emit a deprecation warning) if you use `narwhals.stable.v1`, - see [perfect backwards compatibility policy](https://narwhals-dev.github.io/narwhals/backcompat/). - pass_through: Determine what happens if the object isn't supported by Narwhals: - - - `False` (default): raise an error - - `True`: pass object through as-is + strict: Whether to raise if object can't be converted (default) or + to just leave it as-is. eager_only: Whether to only allow eager objects. eager_or_interchange_only: Whether to only allow eager objects or objects which implement the Dataframe Interchange Protocol. @@ -364,15 +346,10 @@ def from_native( narwhals.DataFrame or narwhals.LazyFrame or narwhals.Series """ from narwhals import dtypes - from narwhals.utils import validate_strict_and_pass_though - - pass_through = validate_strict_and_pass_though( - strict, pass_through, pass_through_default=False, emit_deprecation_warning=True - ) return _from_native_impl( native_object, - pass_through=pass_through, + strict=strict, eager_only=eager_only, eager_or_interchange_only=eager_or_interchange_only, series_only=series_only, @@ -384,7 +361,7 @@ def from_native( def _from_native_impl( # noqa: PLR0915 native_object: Any, *, - pass_through: bool = False, + strict: bool = True, eager_only: bool | None = None, eager_or_interchange_only: bool | None = None, series_only: bool | None = None, @@ -426,7 +403,7 @@ def _from_native_impl( # noqa: PLR0915 # Extensions if hasattr(native_object, "__narwhals_dataframe__"): if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with dataframe" raise TypeError(msg) return native_object @@ -436,12 +413,12 @@ def _from_native_impl( # noqa: PLR0915 ) elif hasattr(native_object, "__narwhals_lazyframe__"): if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with lazyframe" raise TypeError(msg) return native_object if eager_only or eager_or_interchange_only: - if not pass_through: + if strict: msg = "Cannot only use `eager_only` or `eager_or_interchange_only` with lazyframe" raise TypeError(msg) return native_object @@ -451,7 +428,7 @@ def _from_native_impl( # noqa: PLR0915 ) elif hasattr(native_object, "__narwhals_series__"): if not allow_series: - if not pass_through: + if strict: msg = "Please set `allow_series=True` or `series_only=True`" raise TypeError(msg) return native_object @@ -463,7 +440,7 @@ def _from_native_impl( # noqa: PLR0915 # Polars elif is_polars_dataframe(native_object): if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with polars.DataFrame" raise TypeError(msg) return native_object @@ -478,12 +455,12 @@ def _from_native_impl( # noqa: PLR0915 ) elif is_polars_lazyframe(native_object): if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with polars.LazyFrame" raise TypeError(msg) return native_object if eager_only or eager_or_interchange_only: - if not pass_through: + if strict: msg = "Cannot only use `eager_only` or `eager_or_interchange_only` with polars.LazyFrame" raise TypeError(msg) return native_object @@ -499,7 +476,7 @@ def _from_native_impl( # noqa: PLR0915 elif is_polars_series(native_object): pl = get_polars() if not allow_series: - if not pass_through: + if strict: msg = "Please set `allow_series=True` or `series_only=True`" raise TypeError(msg) return native_object @@ -515,7 +492,7 @@ def _from_native_impl( # noqa: PLR0915 # pandas elif is_pandas_dataframe(native_object): if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with dataframe" raise TypeError(msg) return native_object @@ -531,7 +508,7 @@ def _from_native_impl( # noqa: PLR0915 ) elif is_pandas_series(native_object): if not allow_series: - if not pass_through: + if strict: msg = "Please set `allow_series=True` or `series_only=True`" raise TypeError(msg) return native_object @@ -550,7 +527,7 @@ def _from_native_impl( # noqa: PLR0915 elif is_modin_dataframe(native_object): # pragma: no cover mpd = get_modin() if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with modin.DataFrame" raise TypeError(msg) return native_object @@ -566,7 +543,7 @@ def _from_native_impl( # noqa: PLR0915 elif is_modin_series(native_object): # pragma: no cover mpd = get_modin() if not allow_series: - if not pass_through: + if strict: msg = "Please set `allow_series=True` or `series_only=True`" raise TypeError(msg) return native_object @@ -584,7 +561,7 @@ def _from_native_impl( # noqa: PLR0915 elif is_cudf_dataframe(native_object): # pragma: no cover cudf = get_cudf() if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with cudf.DataFrame" raise TypeError(msg) return native_object @@ -600,7 +577,7 @@ def _from_native_impl( # noqa: PLR0915 elif is_cudf_series(native_object): # pragma: no cover cudf = get_cudf() if not allow_series: - if not pass_through: + if strict: msg = "Please set `allow_series=True` or `series_only=True`" raise TypeError(msg) return native_object @@ -618,7 +595,7 @@ def _from_native_impl( # noqa: PLR0915 elif is_pyarrow_table(native_object): pa = get_pyarrow() if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with arrow table" raise TypeError(msg) return native_object @@ -633,7 +610,7 @@ def _from_native_impl( # noqa: PLR0915 elif is_pyarrow_chunked_array(native_object): pa = get_pyarrow() if not allow_series: - if not pass_through: + if strict: msg = "Please set `allow_series=True` or `series_only=True`" raise TypeError(msg) return native_object @@ -650,12 +627,12 @@ def _from_native_impl( # noqa: PLR0915 # Dask elif is_dask_dataframe(native_object): if series_only: - if not pass_through: + if strict: msg = "Cannot only use `series_only` with dask DataFrame" raise TypeError(msg) return native_object if eager_only or eager_or_interchange_only: - if not pass_through: + if strict: msg = "Cannot only use `eager_only` or `eager_or_interchange_only` with dask DataFrame" raise TypeError(msg) return native_object @@ -674,7 +651,7 @@ def _from_native_impl( # noqa: PLR0915 # DuckDB elif is_duckdb_relation(native_object): if eager_only or series_only: # pragma: no cover - if not pass_through: + if strict: msg = ( "Cannot only use `series_only=True` or `eager_only=False` " "with DuckDB Relation" @@ -690,7 +667,7 @@ def _from_native_impl( # noqa: PLR0915 # Ibis elif is_ibis_table(native_object): # pragma: no cover if eager_only or series_only: - if not pass_through: + if strict: msg = ( "Cannot only use `series_only=True` or `eager_only=False` " "with Ibis table" @@ -705,7 +682,7 @@ def _from_native_impl( # noqa: PLR0915 # Interchange protocol elif hasattr(native_object, "__dataframe__"): if eager_only or series_only: - if not pass_through: + if strict: msg = ( "Cannot only use `series_only=True` or `eager_only=False` " "with object which only implements __dataframe__" @@ -717,7 +694,7 @@ def _from_native_impl( # noqa: PLR0915 level="interchange", ) - elif not pass_through: + elif strict: msg = f"Expected pandas-like dataframe, Polars dataframe, or Polars lazyframe, got: {type(native_object)}" raise TypeError(msg) return native_object @@ -744,8 +721,7 @@ def get_native_namespace(obj: Any) -> Any: def narwhalify( func: Callable[..., Any] | None = None, *, - strict: bool | None = None, - pass_through: bool | None = None, + strict: bool = False, eager_only: bool | None = False, eager_or_interchange_only: bool | None = False, series_only: bool | None = False, @@ -805,11 +781,6 @@ def func(df): series_only: Whether to only allow series. allow_series: Whether to allow series (default is only dataframe / lazyframe). """ - from narwhals.utils import validate_strict_and_pass_though - - pass_through = validate_strict_and_pass_though( - strict, pass_through, pass_through_default=True, emit_deprecation_warning=True - ) def decorator(func: Callable[..., Any]) -> Callable[..., Any]: @wraps(func) @@ -817,7 +788,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: args = [ from_native( arg, - pass_through=pass_through, + strict=strict, eager_only=eager_only, eager_or_interchange_only=eager_or_interchange_only, series_only=series_only, @@ -829,7 +800,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: kwargs = { name: from_native( value, - pass_through=pass_through, + strict=strict, eager_only=eager_only, eager_or_interchange_only=eager_or_interchange_only, series_only=series_only, @@ -850,7 +821,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: result = func(*args, **kwargs) - return to_native(result, pass_through=pass_through) + return to_native(result, strict=strict) return wrapper diff --git a/narwhals/utils.py b/narwhals/utils.py index 496dee42b..66c2badee 100644 --- a/narwhals/utils.py +++ b/narwhals/utils.py @@ -549,83 +549,3 @@ def parse_columns_to_drop( def is_sequence_but_not_str(sequence: Any) -> TypeGuard[Sequence[Any]]: return isinstance(sequence, Sequence) and not isinstance(sequence, str) - - -def find_stacklevel() -> int: - """ - Find the first place in the stack that is not inside narwhals. - - Taken from: - https://github.com/pandas-dev/pandas/blob/ab89c53f48df67709a533b6a95ce3d911871a0a8/pandas/util/_exceptions.py#L30-L51 - """ - import inspect - from pathlib import Path - - import narwhals as nw - - pkg_dir = str(Path(nw.__file__).parent) - - # https://stackoverflow.com/questions/17407119/python-inspect-stack-is-slow - frame = inspect.currentframe() - n = 0 - try: - while frame: - fname = inspect.getfile(frame) - if fname.startswith(pkg_dir) or ( - (qualname := getattr(frame.f_code, "co_qualname", None)) - # ignore @singledispatch wrappers - and qualname.startswith("singledispatch.") - ): - frame = frame.f_back - n += 1 - else: # pragma: no cover - break - else: # pragma: no cover - pass - finally: - # https://docs.python.org/3/library/inspect.html - # > Though the cycle detector will catch these, destruction of the frames - # > (and local variables) can be made deterministic by removing the cycle - # > in a finally clause. - del frame - return n - - -def issue_deprecation_warning(message: str, _version: str) -> None: - """ - Issue a deprecation warning. - - Parameters - ---------- - message - The message associated with the warning. - version - Narwhals version when the warning was introduced. Just used for internal - bookkeeping. - """ - warn(message=message, category=DeprecationWarning, stacklevel=find_stacklevel()) - - -def validate_strict_and_pass_though( - strict: bool | None, - pass_through: bool | None, - *, - pass_through_default: bool, - emit_deprecation_warning: bool, -) -> bool: - if strict is None and pass_through is None: - pass_through = pass_through_default - elif strict is not None and pass_through is None: - if emit_deprecation_warning: - msg = ( - "`strict` in `from_native` is deprecated, please use `pass_through` instead.\n\n" - "Note: `strict` will remain available in `narwhals.stable.v1`." - ) - issue_deprecation_warning(msg, _version="1.13.0") - pass_through = not strict - elif strict is None and pass_through is not None: - pass - else: - msg = "Cannot pass both `strict` and `pass_through`" - raise ValueError(msg) - return pass_through diff --git a/tests/translate/from_native_test.py b/tests/translate/from_native_test.py index 05c922503..e1fc4a59b 100644 --- a/tests/translate/from_native_test.py +++ b/tests/translate/from_native_test.py @@ -226,15 +226,9 @@ def test_from_native_strict_false_typing() -> None: nw.from_native(df, strict=False, eager_only=True) nw.from_native(df, strict=False, eager_or_interchange_only=True) - with pytest.deprecated_call(match="please use `pass_through` instead"): - unstable_nw.from_native(df, strict=False) # type: ignore[call-overload] - unstable_nw.from_native(df, strict=False, eager_only=True) # type: ignore[call-overload] - unstable_nw.from_native(df, strict=False, eager_or_interchange_only=True) # type: ignore[call-overload] - - -def test_from_native_strict_false_invalid() -> None: - with pytest.raises(ValueError, match="Cannot pass both `strict`"): - nw.from_native({"a": [1, 2, 3]}, strict=True, pass_through=False) # type: ignore[call-overload] + unstable_nw.from_native(df, strict=False) + unstable_nw.from_native(df, strict=False, eager_only=True) + unstable_nw.from_native(df, strict=False, eager_or_interchange_only=True) def test_from_mock_interchange_protocol_non_strict() -> None: diff --git a/tests/translate/narwhalify_test.py b/tests/translate/narwhalify_test.py index 4dc346543..5c700a191 100644 --- a/tests/translate/narwhalify_test.py +++ b/tests/translate/narwhalify_test.py @@ -61,23 +61,21 @@ def func( def test_narwhalify_method_invalid() -> None: - with pytest.deprecated_call(match="please use `pass_through` instead"): - - class Foo: - @nw.narwhalify(strict=True, eager_only=True) - def func(self) -> Foo: # pragma: no cover - return self + class Foo: + @nw.narwhalify(strict=True, eager_only=True) + def func(self) -> Foo: # pragma: no cover + return self - @nw.narwhalify(strict=True, eager_only=True) - def fun2(self, df: Any) -> Any: # pragma: no cover - return df + @nw.narwhalify(strict=True, eager_only=True) + def fun2(self, df: Any) -> Any: # pragma: no cover + return df - with pytest.raises(TypeError): - Foo().func() + with pytest.raises(TypeError): + Foo().func() def test_narwhalify_invalid() -> None: - @nw.narwhalify(pass_through=False) + @nw.narwhalify(strict=True) def func() -> None: # pragma: no cover return None diff --git a/tests/translate/to_native_test.py b/tests/translate/to_native_test.py index e832e73eb..3d116a459 100644 --- a/tests/translate/to_native_test.py +++ b/tests/translate/to_native_test.py @@ -13,27 +13,27 @@ @pytest.mark.parametrize( - ("method", "pass_through", "context"), + ("method", "strict", "context"), [ - ("head", False, does_not_raise()), ("head", True, does_not_raise()), - ("to_numpy", True, does_not_raise()), + ("head", False, does_not_raise()), + ("to_numpy", False, does_not_raise()), ( "to_numpy", - False, + True, pytest.raises(TypeError, match="Expected Narwhals object, got"), ), ], ) def test_to_native( - constructor_eager: ConstructorEager, method: str, *, pass_through: bool, context: Any + constructor_eager: ConstructorEager, method: str, strict: Any, context: Any ) -> None: df = nw.from_native(constructor_eager({"a": [1, 2, 3]})) with context: - nw.to_native(getattr(df, method)(), pass_through=pass_through) + nw.to_native(getattr(df, method)(), strict=strict) s = df["a"] with context: - nw.to_native(getattr(s, method)(), pass_through=pass_through) + nw.to_native(getattr(s, method)(), strict=strict)