NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #247 most downloaded on PyPI
Extremely lightweight compatibility layer between dataframe libraries
Last release 26 days ago
08 Sep 2026
Ships fairly regularly
a new release about every 3 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
4 versions withdrawn
withdrawn after publishing
3 years old
243 releases · first in 2024
fix: Deprecate cat.get_categories and stop relying on Polars' removed method
simple_select (#3875)is_finite, sqrt, kurtosis and skew (#3874)strip_chars with empty characters no longer strips whitespace (#3925)dtype.categories for pl.Enum in get_categories (#3924)concat with the stable frame classes (#3908)shift preserves length when n exceeds the series length (#3920)cat.get_categories and stop relying on Polars' removed method (#3902)hist (#3907)is_in and __contains__ tests (#3901)str.slice(..., length=0) returns empty string on pandas and dask (#3891){cast,bool,str} calls (#3905)test_unique_expr for duckdb 1.6+ (#3899)closed=True in some TypedDicts (#3800)Thank you to all our contributors for making this release possible!
@FBruzzesi, @heyilingran, @MarcoGorelli, @ptimizeroracle, @winklemad, @github-actions[bot], @dangotbanned, @EdAbati and ptimizeroracle
One column per month.
perf: remove redundant work in eager when/then, schema resolution, selectors, and module lookups
str.strip_chars_{start,end} (#3843)maintain_order argument to {Expr, Series}.list.unique (#3697)PluginName NewType so plugin backends can type check (#3794)Expr.list.median for ibis backend (#3791)concat (#3866)with_row_index(order_by=...) (#3863)Categorical columns by value in the pyarrow backend (#3862)is_in was not preserving nulls where possible (#3859)pyrefly: ignores (#3848)pyproject.toml, as dependencies are pinned in uv.lock anyway (#3847)*Namespace methods (#3793)expression_args instead of **expressifiable_args (#3766)cat.get_categories tests for expr and series (#3814)Thank you to all our contributors for making this release possible!
@aleks-drozy, @CangyuanLi, @EdAbati, @FBruzzesi, @ghostiee-11, @MarcoGorelli, @maxzw, @Shaan-alpha, @vidigoat and @github-actions[bot]
feat: Widen IntoSchema to accept IntoDType values and (name, dtype) pair sequences
IntoSchema to accept IntoDType values and (name, dtype) pair sequences (#3756)is_into_* (#3754)altair downstream test (#3767)fill_null for Dask with expressions (#3758)assert_equal_data for objects where __eq__ returns non-bool (#3760)CONTRIBUTING.md and PR field (#3701)assert_equal_data (#3772)Thank you to all our contributors for making this release possible! @CangyuanLi, @EdAbati, @FBruzzesi, @MarcoGorelli, @PraveenKumarSridhar, @camriddell, @dangotbanned, @dependabot[bot], @github-actions[bot], @renovate[bot], dependabot[bot], github-actions[bot] and renovate[bot]
fix: address polars deprecation of how='horizontal' in concat
selectors.enum (#3729)Float16 datatype (#3725)orient="row" in pl.from_numpy (#3732)sample arguments validation, bump pyright and numpy deps (#3724)Expr subclass through when/then/otherwise chains (#3708)corr null handling and expose corr/cov in stable.v1 (#3687)lightgbm downstream test (#3699)how='horizontal' in concat (#3731)scikit-learn to downstream tests (#3609)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @cosmicBboy, @dependabot[bot], @e10v, @gaoflow, @renovate[bot], dependabot[bot] and renovate[bot]
fix: preserve fireducks functionality
is_close for Decimal dtype and join(how={"semi", "anti"}) on null's (#3660)Thank you to all our contributors for making this release possible! @FBruzzesi and @MarcoGorelli
test: Port Array recursion tests from polars
Array recursion tests from polars (#3651)is_into_lazyframe, export missing functionalities, fix SQLFrame bug (#3613)is_into_lazyframe, export missing functionalities, fix SQLFrame bug (#3613).over was mutating expressions in some cases (#3638)allow-redefinition for mypy (#3650)src/ layout (#3631)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli and @dangotbanned
chore: Prepare for future pandas inplace deprecation
float('nan') as value in join for duckdb (#3555)" (#3627)downstream_tests_slow (#3629)# pragma: no cover for binary_string_sum_fallback (#3614)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli and @pedro-villanueva-bcom
test: The Asia/Katmandu timezone is deprecated
Expr.quantile for spark-like backends (#3568)over with partition_by and order_by with scrambed groups for pandas (#3603)float('nan') as value in join for duckdb (#3555)Expr.over(order_by=...) (#3549)issubclass check in native_to_narwhals_dtype in _polars (#3594)get_categories to avoid polars categorical flakiness (#3592)no_default sentinel (#3587)strict in to_native v1 overloads (#3586){Expr,Series}.str.to_time (#3538)quantile in group-by context (#3583)scorecard github action (#3573)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell, @dependabot[bot], @ofajardo, @pedro-villanueva-bcom, @pre-commit-ci[bot], dependabot[bot] and pre-commit-ci[bot]
feat: enable when/then chaining
struct function (#3522)nw.struct follow-up (#3551)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli and @schloerke
feat: Support other Expr/Series in str.contains for polars and SQL-like backends
str.contains for polars and SQL-like backends (#3473)nw.corr (#3460)from_native (#3515)make typing to re-use uv machinery (#3531)weekday with day_of_week for pandas-like and dask (#3527)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli, @benrutter, @camriddell, @dependabot[bot] and dependabot[bot]
chore: silence deprecationwarning we cannot do anything about
concat_str for pandas backed by pyarrow large-string (#3499)message attribute annotations (#3514)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli and @jorenham
tests: Remove xfail for SQLFrame Expr.skew
Expr.skew (#3507)Expr.replace_strict for SQLFrame backend (#3490)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dependabot[bot], @manzt, @pre-commit-ci[bot], dependabot[bot] and pre-commit-ci[bot]
fix: Address DuckDB 1.5 fetch_arrow_table deprecation
Series in Series.scatter (#3444)Decimal dtypes in {Series, Expr}.is_close (#3480)offset_by was raising unnecessarily for sql-like (#3478)fetch_arrow_table deprecation (#3464)mkdocs.yml warning (#3454)ruff==0.15.0 (#3449)--system with $UV_SYSTEM_PYTHON (#3455)utils.check_docstrings Ruff usage (#3461)tpch/generate_data.py (#3421)utils.check_docstrings Ruff usage (#3461)--clear in uv venv for 0.10.0 (#3462)"polars==1.37.1" for tpch queries (#3467)test_concat_diagonal_invalid again (#3451)"polars==1.37.1" for tpch queries (#3453)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli, @dangotbanned, @pre-commit-ci[bot] and pre-commit-ci[bot]
ci: Unpin polars==1.34.0 in --group typing
polars==1.34.0 in --group typing (#3434)duckdb==1.4.4 in --group typing (#3433)pd.ArrowDtype -> nw.DType (#3413)separator argument in read_csv/scan_csv (#2989)lit (#3424)narwhals.sql (#3254)order_by in first / last (#3372)Decimal DType (#3377)concat(..., how="diagonal") for ibis (#3404)list.{sort, sum} for sqlframe (#3400)str.pad_{start,end} (#3395){Expr,Series}.cos (#3392)testing.assert_frame_equal (#3220)lit_test (#3438)list.mean (#3397)sqlglot<28.6.0 in --group typing (#3432)tpch typing (#3420)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell, @dangotbanned, @liamholmes31, and @raisadz
test: unxfail sqlframe tests for list functions
list.median (#3387){Expr,Series}.sin (#3365)list.sort (#3356)hierarchicalforecast installation (#3362)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @liamholmes31, @raisadz
feat: add list aggregate methods
{Expr,Series}.any_value (#3315)slice(None) in series getitem (#3342)ArrowSeries.fill_null(strategy=..., limit=...) and None at the "edge" (#3335)is_ordered_categorical doctest (#3348)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dependabot[bot], @hoxbro, @raisadz, @ym-pett and dependabot[bot]
feat: Enable ArrowExpr.over with null's in multiple columns
ArrowExpr.over with null's in multiple columns (#3316)@overloads in nw.from_native (#3125)df[:, boolean_selector] (#3330)ArrowDataFrame.row (#3334)nw.__getattr__ (#3333)test_over_cum_reverse for pandas[nullable] v3.0+ (#3326)show_version typo, add PR top level description section (#3324)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @m-richards and @raisadz
enh: Make public narwhals.compliant.py
narwhals.compliant.py (#3302)when/then … (#3312)narwhals.compliant.py (#3302)Thank you to all our contributors for making this release possible! @MarcoGorelli
feat: Add Expr.replace_strict support for lazy backends if default is provided
Expr.replace_strict support for lazy backends if default is provided (#3282)not_implemented and "could not translate" errors for plugins (#3297)default in {Expr,Series}.replace_strict (#3276)with_row_index was returning incorrect results when used with order_by for pandas, pyarrow, and polars (#3292)is_finite consistent for Polars < 1.18 (#3288)default in {Expr,Series}.replace_strict (#3276)cat.get_categories (flaky) (#3283)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell and @liamholmes31
test: un-xfail is_finite for sqlframe
is_finite for sqlframe (#3268)coalesce was raising with multi-output expression (#3278)Thank you to all our contributors for making this release possible! @MarcoGorelli, @dangotbanned, @dependabot[bot] and dependabot[bot]
fix: allow for None dtype in from_dict
None dtype in from_dict (#3252).is_finite (#3258)None dtype in from_dict (#3252)pandas.Series.to_frame for unnamed series in internal usage (#3251)DTypeClass to improve DType.__repr__ and simplify __slots__ (#3213)typos-cli in pre-commit (#3260)find_spec('dask') and find_spec('dask.dataframe') (#3253)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @hoxbro and @ym-pett
perf: Rewrite with_row_index so it's faster for pandas/pyarrow and doesn't use rank
with_row_index so it's faster for pandas/pyarrow and doesn't use rank (#3239)over expressions more freely, make expressions printable, rewrite internals (travelling pr 🌴 ) (#3152)nw.nth expansion with nw.col during group_by (#3243)str.to_titlecase with polars v1.35.0 behavior (#3238)over expressions more freely, make expressions printable, rewrite internals (travelling pr 🌴 ) (#3152)concat_str (#3240)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli and @ym-pett
feat: Add support for {Expr,Series}.{ceil,floor}
{Expr,Series}.{ceil,floor} (#3198)assert_series_equal (#2983)nw.Unknown) (#3223)_native.py (#3086)_native.py (#3086)DTypes (#3205)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @m-richards and @sfc-gh-eferguson
perf: Add __slots__ to all DTypes
__slots__ to all DTypes (#3194)concat_str performance (#3193)Iterator > tuple > list, use native pyarrow.repeat, simplify nw.concat_str for DuckDB backend (#3190){Expr,Series}.str.to_titlecase (#3116)concat_str performance (#3193)BaseFrame.filter with list[bool] in predicates (#3183)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @pre-commit-ci[bot] and pre-commit-ci[bot]
feat: Adds {Expr,Series}.{first,last}
nw.format (#3169){Expr,Series}.{first,last} (#2528)polars.UInt128 (#3138)prefix argument to generate_temporary_column_name (#3147){nw,DataFrame}.from_dicts (#3148)Implementation.UNKNOWN._backend_version() safe (#3133)CompliantNamespace.is_native (#3130)Implementation.UNKNOWN._backend_version() safe (#3133)EagerDataFrame intermittent [False Negative] (#3142)--upgrade flag to uv sync --dev (#3175)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @akmalsoliev, @dangotbanned, @dependabot[bot], @felixgwilliams and dependabot[bot]
fix: Align division by zero behavior across all backends
skew with over (#3161)n_unique with over across all backends (#3159)pl.UInt128 (#3144)@requires.backend_version in namespaces (#3127)version_test failing on old venv (#3134)pickle_test using Sequence (#3135)maybe_convert_dtypes (#3141)CompliantFrame._with_native (#3140)isinstance_or_issubclass overloads (#3139)v0.13.0 and fix related issues in tests/ (#3126)modern polars tests (#3087)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned and @skritsotalakis
fix: Handle duckdb breaking change in arrow
os.PathLike[str] in {read,scan}_* functions (#3112)keep={'first', 'last'} in {DataFrame,LazyFrame}.unique (#3118)arrow (#3119)CompliantNamespace.from_native (#3114)Thank you to all our contributors for making this release possible! @MarcoGorelli, @dangotbanned and @ym-pett
enh: support diagonal concatenation for duckdb
Thank you to all our contributors for making this release possible!
feat: Raise on mismatched *Frame joins
*Frame joins (#3055)Schema.from_{native,<backend>} (#2957).str.replace[_all] (#2886).lazy(backend=...) (#3032)Lazyframe.unique was raising when column name was "group" (#3070)Compliant* APIs (#3045)CompliantFrame protocol (#3056)with_callable in fill_nan (#3052)ExprKind.NARY (#3050)None in object_native_to_narwhals_dtype (#3038)CompliantDataFrame.collect (#3041)dask_expr.Series.mask (#3039)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell and @dangotbanned
feat: Add {Expr,Series}.fill_nan
{Expr,Series}.fill_nan (#3030)mode(..., keep="any") (#3019)DataFrame.top_k and LazyFrame.top_k (#2977)IntoBackend alias (#2971)returns_scalar argument in map_batches (#2998)Series.from_iterable (#2933)DataFrame, LazyFrame (#2944)map_batches parsing result type (#3008)v2 constructor overrides (#3006)duckdb nightly from cov (#3015)GroupBy with mixed length exprs as keys (#3004)clip with modin[pyarrow] and cudf backends (#2986)IntoBackend alias (#2971)DType methods, properties in API Reference (#2999)ruff config (#3009)zip with zip_strict (#3003)eager_backend fixture (#3005)read_scan_test, spark session (#3024)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell, @dangotbanned, @kklein and @raisadz
fix(tests): correct polars version in modern polars ewm_mean_test
explode output by sorting on multiple columns (#2988)DType.base_type (#2969)list.get(index: int) (#2949)DType.base_type (#2969){Expr,Series}.is_close (#2962)map_batches test for now (#2996)read_parquet (#2980)lit (#2972)CompliantColumn (#2967)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @ofajardo and @skritsotalakis
fix: agg(nw.all().len()) was unnecessarily raising
agg(nw.all().len()) was unnecessarily raising (#2974)Thank you to all our contributors for making this release possible! @EdAbati and @MarcoGorelli
test: polars categorical physical order deprecation and (temporarely) xfail datetime selectors
IntoSchema alias (#2945)list.contains (#2942)list.unique() (#2940)is_boolean method to DType. (#2935)Series.from_numpy (#2893)nw.Object to pandas-like (#2953)modin, pandas dtypes (#2958)importlib for polars version (#2952)from_arrow import for modin (#2919)modin[pyarrow] to use more dtypes (#2950)IntoSchema alias (#2945)SQLExpr (#2920).list.unique (#2946)Expr.str namespace for sql frontends (#2941)unique test (#2937)RET505, A005, ISC001, PD003) (#2923)Compliant*Frame methods (#2934)Polars*Namespace(s) (#2897)Namespace.from_native_object (#2914)"polars==1.32.2" for typing (#2968)sqlframe on test_unique_expr (#2956)pandas[pyarrow] series slice on nightly (#2954)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli, @dangotbanned, @kklein, @pre-commit-ci[bot], @raisadz, @skritsotalakis, @ym-pett and pre-commit-ci[bot]
feat: Warn, instead of raising, in is_*_dataframe / is_*_series functions
is_*_dataframe / is_*_series functions (#2906)Thank you to all our contributors for making this release possible! @MarcoGorelli
enh: Start narwhals.stable.v2 and enforce deprecations
narwhals.stable.v2 and enforce deprecations (#2814).name expressions, aligning with Polars' new aliasing behaviour (#2898).name expressions, aligning with Polars' new aliasing behaviour (#2898)DataFrame.from_numpy (#2887)DataFrame.from_arrow (#2891)DataFrame.from_dict (#2885)get_column typing for stable.v1 (#2892).clip should not treat 0 and None as same (#2889)3.8 compat from Schema (#2894)Series.hist (#2839)clip and some aggregations from duckdb/spark-like/ibis (#2883)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @skritsotalakis and @ym-pett
feat: Deprecate Expr.arg_min and Expr.arg_max from the main namespace
pyright step (#2870)Expr.arg_min and Expr.arg_max from the main namespace (#2873)sink parquet for lazy backends (#2867)from_dict (#2874)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli, @dangotbanned, @raisadz and @ym-pett
tests: Fix CuDF test failures and xpass
offset_by test (#2857)assign for Series.rank in pandas, fix Series.rank for nameless pandas Series (#2846)all and any in group by context (#2856)LazyFrame.schema (#2849)scatter was raising unnecessarily for pyarrow (#2864)Distribution for show_versions (#2809)assign for Series.rank in pandas, fix Series.rank for nameless pandas Series (#2846)uwdata/mosaic to users in README.md (#2848)narwhals._sql (#2853)DTypes from narwhals.stable.v1.typing (#2843)with_columns, filter and select tests (#2844)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli, @dangotbanned, @peter-gy and @raisadz
fix: Fixup logic for new pandas str type
pytest_addoption (#2837)ColumnNotFound for duckdb and pyspark (#2493)calculate_timestamp_datetime and calculate_timestamp_date (#2838)combine_metadata (#2836)EagerExpr._reuse_series_namespace to support expressifiable kwargs (#2834)Path instead of open in utils (#2833)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli, @camriddell and @dangotbanned
enh: support offset_by for cudf
offset_by for cudf (#2823)coalesce for all backends (#2647)formulaic to ecosystem list (#2827)utils.Version from API Reference (#2824)_apply_exprs_function internal (#2829)reset_index(inplace=True) out of _select_results (#2828)PandasLikeGroupBy (#2680)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli, @camriddell, @dangotbanned, @matthewwardrop, @pre-commit-ci[bot] and pre-commit-ci[bot]
refactor: Cache, reuse Implementation._backend_version
Implementation._backend_version (#2764)Expr.dt.offset_by() (#2733)over(order_by=...) for rank (#2746)Datetime for PySpark (#2780)quantile and ewm_mean in over context (#2774)DataFrame().lazy("ibis") (#2771)"utf-8" encoding for windows (#2770)descending and nulls_last for duckdb window_expression (#2791)named: Literal[False] was missing in DataFrame.iter_rows (#2778)Implementation._backend_version (#2764)_compliant exports (#2773)_reuse_series to EagerExpr whenever possible (#2765)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @dependabot[bot], @raisadz and dependabot[bot]
feat: Add Expr|Series.str.to_date
Expr|Series.str.to_date (#2747)ignore_nulls to any_horizontal and all_horizontal (#2719)order_by option in with_row_index method (#2683)str.to_datetime (#2740)fill_null doesn't silently downcast for pandas per-3.0 (#2724)NotImplementedError for cuDF (#2760)Self whenever possible (#2730)import_array_module util function (#2757)LazyExprNamespace (#2756)is_dtype_numpy_nullable (#2744)PandasLikeDataFrame|DaskLazyFrame.join method (#2511)check_column_names_are_unique util (#2749)_constants module (#2737)LazyExpr._from_elementwise_horizontal_op (#2718)_pandas_like.utils (#2714)_typing_compat.assert_never (#2717)_utils signatures (#2712)isinstance_or_issubclass overloads (#2731)window_expression for DuckDB (#2729)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned and @jrw34
fix, perf: avoid np.repeat for broadcasting
Expr.str.zfill (#2598)*GroupBy variance issue (#2694)generate_temporary_column_name result always starts with character (#2699)cuDF 25.08.00a (#2700)Thank you to all our contributors for making this release possible! @EdAbati, @MarcoGorelli, @camriddell, @dangotbanned, @rwhitten577 and @williambdean
perf: Avoid Python range whenever possible
narwhals.stable.v1.dependencies was importing narwhals.dependencies (#2696)PolarsBaseFrame parent class (#2689)Thank you to all our contributors for making this release possible! @FBruzzesi and @MarcoGorelli
depr: Deprecate nw.get_level from main namespace
too_slow on test_rolling_var_hypothesis_polars (#2674)nw.get_level from main namespace (#2681)nw.dependencies.is_*_dataframe and nw.dependencies.is_*_series (#1444)Expr.kurtosis and Series.kurtosis (#2676)Expr.sqrt and Series.sqrt (#2668)Implementation.to_native_namespace (#2620)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned and @raisadz
feat(typing): Add IntoDType alias
IntoDType alias (#2654)Expr.exp and Series.exp (#2667)replace_all typo in replace_strict docstring (#2661)EagerWhen._if_then_else (#2662)Thank you to all our contributors for making this release possible! @MarcoGorelli, @camriddell, @dangotbanned and @raisadz
enh: pushdown over in elementwise operations for spark-like and duckdb
pandas.error.MergeError (#2655)Thank you to all our contributors for making this release possible! @MarcoGorelli and @dangotbanned
api: remove support for dataframe interchange protocol from main namespace (but keep supported in narwhals.stable.v1
narwhals.stable.v1 (#2637)over params for shift and diff (#2646)Series constructor (#2628)_impl top-level functions (#2640)_duckdb runtime type checks to narwhals-level (#2632)stable.v1.from_native (#2629)concat in stable.v1 (#2630)is_ordered_categorical (#2618)Namespace.from_backend fallback overload (#2622)to_dict test for v1 (#2616)_has_default_index comment (#2615)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell, @dangotbanned, @pre-commit-ci[bot] and pre-commit-ci[bot]
enh: reflect connection time zone in Datetime for pyspark, support convert_time_zone and replace_time_zone
to_string method to SparkLikeExprDateTimeNamespace (#1842)Datetime for DuckDB, support convert_time_zone and replace_time_zone (#2590)pass_through=True, eager_only=True interaction (#2606)get_native_namespace (#2608)truncate for timezone-aware timestamps for DuckDB (#2577)check_columns_exist where possible (#2495)WindowInputs code (#2600)tool.ruff.lint.typing-modules (#2610)broadcast for spark-like and ibis (#2595)pre-commit, update CONTRIBUTING (#2587)_typing_compat module (#2578)skip-magic-trailing-comma for ruff format (#2582)_input to expr in _spark_like, _ibis, and _dask (#2581)_input to expr in _duckdb (#2580)Expression instead of duckdb.Expression for typing (#2579)Thank you to all our contributors for making this release possible! @Dhanunjaya-Elluri, @EdAbati, @FBruzzesi, @MarcoGorelli and @dangotbanned
perf: Set pandas attributes inplace when it is safe to do so
rank so that it works with over() for lazy backends (#2533)IbisExpr.dt.truncate (#2567)Series|Expr.log method (#2549)collect_with_kwargs for polars nightly (#2527)call_kwargs to scalar_kwargs (#2555)_is_naive_format helper function into utils.py (#2568)CompliantExpr.from_column_indices (#2561)scalar_kwargs in EagerExpr (#2560)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned and @raisadz
fix: collect_schema was failing for DuckDB in narwhals.stable.v1 with Enum type
collect_schema was failing for DuckDB in narwhals.stable.v1 with Enum type (#2551)FrameT more precise (#2542)IbisLazyFrame support (#2000)left_on / right_on tighter at compliant level (#2548)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli and @rwhitten577
chore: Bump version manually only in pyproject.toml
new_version.strip() in bump_version.py, otherwise the tag will be invalid (#2535)new_version.strip() in bump_version.py, otherwise the tag will be invalid (#2535)not_implemented some more (#2539)SparkLike window (#2505)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned and @mgorny
fix: Catch ImportError when checking for PySparkConnect
ImportError when checking for PySparkConnect (#2518)Thank you to all our contributors for making this release possible! @MarcoGorelli and @akmalsoliev
patch: Fix is_pyspark_connect_dataframe
is_pyspark_connect_dataframe (#2512)from_native(...).to_native() returns original object (#2508)pyspark truncate in ci (#2507)polars optional in truncate_test (#2501)LazyExpr.alias (#2506)to_py_scalar (#2503)join|join_asof) predicate lengths match (#2504)PandasLikeDataFrame.pivot (#2494)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @mgorny, @pre-commit-ci[bot], @rwhitten577 and pre-commit-ci[bot]
patch: Filter is_sparse DeprecationWarning in test suite
stable in narwhals/__init__.py, instead require import narwhals.stable (#2480)importlib.util.find_spec (#2391)_DelayedCategories -> _DeferredIterable (#2421)dt.truncate (#2465)is_sparse DeprecationWarning in test suite (#2476)_translate docs (#2455)join_asof (#2457)pyarrow-stubs==19.2 (#2458)ruff complexity rules (#2460)_with_callable for narwhals expr namespaces (#2477)Implementation._alias in favor of non-auto values (#2432)_translate docs (#2455)Compliant*.to_narwhals (#2461)_DelayedCategories -> _DeferredIterable (#2421)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @dangotbanned, @dependabot[bot], @e10v, @raisadz and dependabot[bot]
test: Simplify test_lazy_backend
test_lazy_backend (#2445)_arrow.typing aliases (#2448)is_sized_multi_index_selector (#2449)Thank you to all our contributors for making this release possible! @EdAbati, @MarcoGorelli and @dangotbanned
perf: Add pa.Table rename fastpath for >=17
pa.Table rename fastpath for >=17 (#2433)fill_null(strategy=...).over(order_by=...) for pandas-like (#2443)fill_null for DuckDB and SparkLike (#2413)group_by keys (#2325)__getitem__ annotations (#2436)dask imports (#2437)utils, tpch warnings (#2426)pa.Table rename fastpath for >=17 (#2433)Version.dtypes, remove import_dtypes_module (#2431)Version.namespace, remove import_namespace (#2425)setuptool<78 in CI (#2441)Thank you to all our contributors for making this release possible! @EdAbati, @FBruzzesi, @MarcoGorelli and @dangotbanned
perf: Delay converting categories to tuple for Enum
columns property for lazyframe's (#2407)DataFrame.__getitem__ consistency (#2393)Namespace class (#2324)nw.Enum accept categories, map pandas ordered categorical to Enum (only in main namespace, not stable.v1) (#2192)polars python type aliases (#2362)np.generic in is_numpy_scalar (#2395)TypeVar(s) used in (Data|Lazy)Frame (#2356)dependency-groups (#2392)columns property for lazyframe's (#2407).id and .children properties (#2406)Namespace class (#2324)self: Self annotations (#2399)pytest.skip for dt tests which can never pass (#2398)type from is_list_of return (#2397)@requires for backend method constraints (#2371)__getitem__ less internally (#2390)(Arrow|PandasLike)Namespace.concat (#2381)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell, @dangotbanned and @mollydesjardin
Fix: Align Series.hist with new Polars behaviour
Series.hist with new Polars behaviour (#2374)concat(..., how="horizontal") for LazyFrame (#2341)__getitem__ and filter (#2384)DuckDBExpr.rank (#2319)concat(..., how="horizontal") for LazyFrame (#2341)over statements, nested aggregations, filtrations on aggregations, document expression metadata better (#2351)polars literal aliases (#2352)DuckDBLazyFrame.rename using python API (#2382)Series.hist with new Polars behaviour (#2374)nw.len().over was unnecessarily raising for pandas-like (#2372)over statements, nested aggregations, filtrations on aggregations, document expression metadata better (#2351)polars literal aliases (#2352)PandasLikeNamespace.concat (#2368)Thank you to all our contributors for making this release possible! @FBruzzesi, @MarcoGorelli, @camriddell, @dangotbanned and @marvinl803
[pre-commit.ci] pre-commit autoupdate
typing_extensions.TypeVar(default) exists (#2361)cast_for_truediv (#2355)Thank you to all our contributors for making this release possible! @FBruzzesi, @dangotbanned, @mnxoid, @pre-commit-ci[bot] and pre-commit-ci[bot]
test: unify tests in group_by_test.py
group_by_test.py (#2195)[assignment] with extract_args_kwargs (#2329)unique(keep='none') for pyspark/sqlframe (#2338)TypeVar used in Series (#2347)Constructor, ConstructorEager aliases (#2349)concat signature (#2339)on nor index were passed (#2335)[assignment] with extract_args_kwargs (#2329)DTypes typing (#2330)separate_signature: true (#2353)_compliant.typing aliases in more places (#2336)pyarrow-stubs==19.1 (#2350)_compliant.typing aliases in more places (#2336)Compliant*.from_native (#2315)selectors away from Protocol38 (#2326)Polars(Expr|Series) compliant (#2328)group_by_test.py (#2332)PandasLikeDataFrame.with_columns (#2327)Thank you to all our contributors for making this release possible! @MarcoGorelli, @dangotbanned and @luke396
Your coding agent can read these notes before it upgrades. Set up the MCP server →