From aa0072f9f18f81b69b446ca4ce19bf9af0a4bcfa Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:23:52 +0100 Subject: [PATCH 1/9] choose the right version number --- doc/whats-new.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 6dcbdd1062b..bc83de3e757 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -6,9 +6,9 @@ What's New ========== -.. _whats-new.2025.10.2: +.. _whats-new.2025.11.0: -v2025.10.2 (unreleased) +v2025.11.0 (unreleased) ----------------------- New Features From 865282185961fec0f158a67974b0018db0520962 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:30:17 +0100 Subject: [PATCH 2/9] formatting --- doc/whats-new.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index bc83de3e757..f5fd1d85886 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -17,7 +17,7 @@ New Features - :py:func:`merge` and :py:func:`concat` now support :py:class:`DataTree` objects (:issue:`9790`, :issue:`9778`). By `Stephan Hoyer `_. -- The ``h5netcdf`` engine has support for pseudo ``NETCDF4_CLASSIC`` files, meaning variables and attributes are cast to supported types. Note that the saved files won't be recognized as genuine ``NETCDF4_CLASSIC`` files until ``h5netcdf`` adds support with version 1.7.0. (:issue:`10676`, :pull:`10686`). +- The ``h5netcdf`` engine has support for pseudo ``NETCDF4_CLASSIC`` files, meaning variables and attributes are cast to supported types. Note that the saved files won't be recognized as genuine ``NETCDF4_CLASSIC`` files until ``h5netcdf`` adds support with version 1.7.0 (:issue:`10676`, :pull:`10686`). By `David Huard `_. - Support comparing :py:class:`DataTree` objects with :py:func:`testing.assert_allclose` (:pull:`10887`). By `Justus Magin `_. @@ -33,24 +33,25 @@ Deprecations Bug Fixes ~~~~~~~~~ - Fix h5netcdf backend for format=None, use same rule as netcdf4 backend (:pull:`10859`). - By `Kai Mühlbauer `_ + By `Kai Mühlbauer `_. - ``netcdf4`` and ``pydap`` backends now use stricter URL detection to avoid incorrectly claiming remote URLs. The ``pydap`` backend now only claims URLs with explicit DAP protocol indicators (``dap2://`` or ``dap4://`` schemes, or ``/dap2/`` or ``/dap4/`` in the URL path). This prevents both backends from claiming remote Zarr stores and other non-DAP URLs without an explicit - ``engine=`` argument. (:pull:`10804`). By `Ian Hunt-Isaak `_. + ``engine=`` argument (:pull:`10804`). + By `Ian Hunt-Isaak `_. - Fix indexing with empty arrays for scipy & h5netcdf backends which now resolves to empty slices (:issue:`10867`, :pull:`10870`). By `Kai Mühlbauer `_ - Fix error handling issue in ``decode_cf_variables`` when decoding fails - the exception is now re-raised correctly, with a note added about the variable name that caused the error (:issue:`10873`, :pull:`10886`). - By `Jonas L. Bertelsen `_ + By `Jonas L. Bertelsen `_. Performance ~~~~~~~~~~~ - Speedup and reduce memory usage of :py:func:`concat`. Magnitude of improvement scales - with size of the concatenation dimension. By `Deepak Cherian `_. - :issue:`10864` :pull:`10866`. + with size of the concatenation dimension (:issue:`10864`, :pull:`10866`). + By `Deepak Cherian `_. Documentation ~~~~~~~~~~~~~ From 245f1c99a882ba21cb182c66fc0a40f00af27768 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:33:31 +0100 Subject: [PATCH 3/9] move a breaking change entry to the right section --- doc/whats-new.rst | 171 +++++++++++++++++++++++----------------------- 1 file changed, 85 insertions(+), 86 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index f5fd1d85886..7b8d97f3063 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -24,6 +24,91 @@ New Features Breaking Changes ~~~~~~~~~~~~~~~~ +- All xarray operations now preserve attributes by default (:issue:`3891`, :issue:`2582`). + Previously, operations would drop attributes unless explicitly told to preserve them via ``keep_attrs=True``. + Additionally, when attributes are preserved in binary operations, they now combine attributes from both + operands using ``drop_conflicts`` (keeping matching attributes, dropping conflicts), instead of keeping + only the left operand's attributes. + + **What changed:** + + .. code-block:: python + + # Before (xarray <2025.11.0): + data = xr.DataArray([1, 2, 3], attrs={"units": "meters", "long_name": "height"}) + result = data.mean() + result.attrs # {} - Attributes lost! + + # After (xarray ≥2025.09.1): + data = xr.DataArray([1, 2, 3], attrs={"units": "meters", "long_name": "height"}) + result = data.mean() + result.attrs # {"units": "meters", "long_name": "height"} - Attributes preserved! + + **Affected operations include:** + + *Computational operations:* + + - Reductions: ``mean()``, ``sum()``, ``std()``, ``var()``, ``min()``, ``max()``, ``median()``, ``quantile()``, etc. + - Rolling windows: ``rolling().mean()``, ``rolling().sum()``, etc. + - Groupby: ``groupby().mean()``, ``groupby().sum()``, etc. + - Resampling: ``resample().mean()``, etc. + - Weighted: ``weighted().mean()``, ``weighted().sum()``, etc. + - ``apply_ufunc()`` and NumPy universal functions + + *Binary operations:* + + - Arithmetic: ``+``, ``-``, ``*``, ``/``, ``**``, ``//``, ``%`` (combines attributes using ``drop_conflicts``) + - Comparisons: ``<``, ``>``, ``==``, ``!=``, ``<=``, ``>=`` (combines attributes using ``drop_conflicts``) + - With scalars: ``data * 2``, ``10 - data`` (preserves data's attributes) + + *Data manipulation:* + + - Missing data: ``fillna()``, ``dropna()``, ``interpolate_na()``, ``ffill()``, ``bfill()`` + - Indexing/selection: ``isel()``, ``sel()``, ``where()``, ``clip()`` + - Alignment: ``interp()``, ``reindex()``, ``align()`` + - Transformations: ``map()``, ``pipe()``, ``assign()``, ``assign_coords()`` + - Shape operations: ``expand_dims()``, ``squeeze()``, ``transpose()``, ``stack()``, ``unstack()`` + + **Binary operations - combines attributes with ``drop_conflicts``:** + + .. code-block:: python + + a = xr.DataArray([1, 2], attrs={"units": "m", "source": "sensor_a"}) + b = xr.DataArray([3, 4], attrs={"units": "m", "source": "sensor_b"}) + (a + b).attrs # {"units": "m"} - Matching values kept, conflicts dropped + (b + a).attrs # {"units": "m"} - Order doesn't matter for drop_conflicts + + **How to restore previous behavior:** + + 1. **Globally for your entire script:** + + .. code-block:: python + + import xarray as xr + + xr.set_options(keep_attrs=False) # Affects all subsequent operations + + 2. **For specific operations:** + + .. code-block:: python + + result = data.mean(dim="time", keep_attrs=False) + + 3. **For code blocks:** + + .. code-block:: python + + with xr.set_options(keep_attrs=False): + # All operations in this block drop attrs + result = data1 + data2 + + 4. **Remove attributes after operations:** + + .. code-block:: python + + result = data.mean().drop_attrs() + + By `Maximilian Roos `_. Deprecations @@ -120,92 +205,6 @@ New Features Breaking changes ~~~~~~~~~~~~~~~~ -- **All xarray operations now preserve attributes by default** (:issue:`3891`, :issue:`2582`). - Previously, operations would drop attributes unless explicitly told to preserve them via ``keep_attrs=True``. - Additionally, when attributes are preserved in binary operations, they now combine attributes from both - operands using ``drop_conflicts`` (keeping matching attributes, dropping conflicts), instead of keeping - only the left operand's attributes. - - **What changed:** - - .. code-block:: python - - # Before (xarray <2025.09.1): - data = xr.DataArray([1, 2, 3], attrs={"units": "meters", "long_name": "height"}) - result = data.mean() - result.attrs # {} - Attributes lost! - - # After (xarray ≥2025.09.1): - data = xr.DataArray([1, 2, 3], attrs={"units": "meters", "long_name": "height"}) - result = data.mean() - result.attrs # {"units": "meters", "long_name": "height"} - Attributes preserved! - - **Affected operations include:** - - *Computational operations:* - - - Reductions: ``mean()``, ``sum()``, ``std()``, ``var()``, ``min()``, ``max()``, ``median()``, ``quantile()``, etc. - - Rolling windows: ``rolling().mean()``, ``rolling().sum()``, etc. - - Groupby: ``groupby().mean()``, ``groupby().sum()``, etc. - - Resampling: ``resample().mean()``, etc. - - Weighted: ``weighted().mean()``, ``weighted().sum()``, etc. - - ``apply_ufunc()`` and NumPy universal functions - - *Binary operations:* - - - Arithmetic: ``+``, ``-``, ``*``, ``/``, ``**``, ``//``, ``%`` (combines attributes using ``drop_conflicts``) - - Comparisons: ``<``, ``>``, ``==``, ``!=``, ``<=``, ``>=`` (combines attributes using ``drop_conflicts``) - - With scalars: ``data * 2``, ``10 - data`` (preserves data's attributes) - - *Data manipulation:* - - - Missing data: ``fillna()``, ``dropna()``, ``interpolate_na()``, ``ffill()``, ``bfill()`` - - Indexing/selection: ``isel()``, ``sel()``, ``where()``, ``clip()`` - - Alignment: ``interp()``, ``reindex()``, ``align()`` - - Transformations: ``map()``, ``pipe()``, ``assign()``, ``assign_coords()`` - - Shape operations: ``expand_dims()``, ``squeeze()``, ``transpose()``, ``stack()``, ``unstack()`` - - **Binary operations - combines attributes with ``drop_conflicts``:** - - .. code-block:: python - - a = xr.DataArray([1, 2], attrs={"units": "m", "source": "sensor_a"}) - b = xr.DataArray([3, 4], attrs={"units": "m", "source": "sensor_b"}) - (a + b).attrs # {"units": "m"} - Matching values kept, conflicts dropped - (b + a).attrs # {"units": "m"} - Order doesn't matter for drop_conflicts - - **How to restore previous behavior:** - - 1. **Globally for your entire script:** - - .. code-block:: python - - import xarray as xr - - xr.set_options(keep_attrs=False) # Affects all subsequent operations - - 2. **For specific operations:** - - .. code-block:: python - - result = data.mean(dim="time", keep_attrs=False) - - 3. **For code blocks:** - - .. code-block:: python - - with xr.set_options(keep_attrs=False): - # All operations in this block drop attrs - result = data1 + data2 - - 4. **Remove attributes after operations:** - - .. code-block:: python - - result = data.mean().drop_attrs() - - By `Maximilian Roos `_. - - :py:meth:`Dataset.update` now returns ``None``, instead of the updated dataset. This completes the deprecation cycle started in version 0.17. The method still updates the dataset in-place. (:issue:`10167`) From 4c4dd726a9acc3b7329c7b1e0939755623e30fec Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:39:23 +0100 Subject: [PATCH 4/9] remove the deprecations section --- doc/whats-new.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 7b8d97f3063..0e6d7b1d3c1 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -111,10 +111,6 @@ Breaking Changes By `Maximilian Roos `_. -Deprecations -~~~~~~~~~~~~ - - Bug Fixes ~~~~~~~~~ - Fix h5netcdf backend for format=None, use same rule as netcdf4 backend (:pull:`10859`). From c0e105ec6eadad3364f212e38e6db5150b83127f Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:39:40 +0100 Subject: [PATCH 5/9] missing entry --- doc/whats-new.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 0e6d7b1d3c1..b89feb29e1a 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -126,6 +126,8 @@ Bug Fixes - Fix error handling issue in ``decode_cf_variables`` when decoding fails - the exception is now re-raised correctly, with a note added about the variable name that caused the error (:issue:`10873`, :pull:`10886`). By `Jonas L. Bertelsen `_. +- Fix ``equivalent`` for numpy scalar nan comparison (:issue:`10833`, :pull:`10838`). + By `Maximilian Roos `_. Performance ~~~~~~~~~~~ From 8d079b2bcd070831f35c89d28eb4a06913f56726 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:39:56 +0100 Subject: [PATCH 6/9] remove the empty internals section --- doc/whats-new.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index b89feb29e1a..8baa7a83bc0 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -139,10 +139,6 @@ Performance Documentation ~~~~~~~~~~~~~ - -Internal Changes -~~~~~~~~~~~~~~~~ - .. _whats-new.2025.10.1: v2025.10.1 (October 7, 2025) From 833e0fe2eb66e441cb3e58a637b904be91737580 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:43:05 +0100 Subject: [PATCH 7/9] another missing entry --- doc/whats-new.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 8baa7a83bc0..4363276c746 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -21,6 +21,8 @@ New Features By `David Huard `_. - Support comparing :py:class:`DataTree` objects with :py:func:`testing.assert_allclose` (:pull:`10887`). By `Justus Magin `_. +- Add support for ``chunks="auto"`` for cftime datasets (:issue:`9834`, :pull:`10527`). + By `Charles Turner `_. Breaking Changes ~~~~~~~~~~~~~~~~ From 9b5ef8adf96da0e7e5e60cf68a6244b428b50fea Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:46:19 +0100 Subject: [PATCH 8/9] more missing entries --- doc/whats-new.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 4363276c746..49472cf0ae0 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -130,6 +130,10 @@ Bug Fixes By `Jonas L. Bertelsen `_. - Fix ``equivalent`` for numpy scalar nan comparison (:issue:`10833`, :pull:`10838`). By `Maximilian Roos `_. +- Support non-``DataArray`` outputs in :py:meth:`Dataset.map` (:issue:`10835`, :pull:`10839`). + By `Maximilian Roos `_. +- Support ``drop_sel`` on ``MultiIndex`` objects (:issue:`10862`, :pull:`10863`). + By `Aled Owen `_. Performance ~~~~~~~~~~~ From b4e1f0cb340f5278d677667dd97509ce1e821e79 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Thu, 13 Nov 2025 15:48:56 +0100 Subject: [PATCH 9/9] remove empty line --- doc/whats-new.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 49472cf0ae0..8f7a33ecd8e 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -177,7 +177,6 @@ Bug fixes By `Stephan Hoyer `_. - .. _whats-new.2025.09.1: v2025.09.1 (September 29, 2025)