diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6b4d4b9cb..f85d72b51 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,11 +4,15 @@ Changelog v0.54.0 (unreleased) -------------------- -Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), +Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Pascal Bourgault (:user:`aulemahal`). Breaking changes ---------------- -* The minimum required version of `dask` has been increased to `2024.8.1`. `dask` versions at or above `2024.11` are not yet supported. (:issue:`1992`, :pull:`1991`). +* The minimum required version of `dask` has been increased to `2024.8.1`. (:issue:`1992`, :pull:`1991`). + +Bug fixes +^^^^^^^^^ +* Fixed pickling issue with ``xclim.sdba.Grouper`` and other classes for usage with `dask>=2024.11`. (:issue:`1992`, :pull:`1993`). Internal changes ^^^^^^^^^^^^^^^^ diff --git a/environment.yml b/environment.yml index 7a5f08ad9..88f13bce9 100644 --- a/environment.yml +++ b/environment.yml @@ -9,7 +9,7 @@ dependencies: - cf_xarray >=0.9.3 - cftime >=1.4.1 - click >=8.1 - - dask >=2024.8.1,<2024.11.0 + - dask >=2024.8.1 - filelock >=3.14.0 - jsonpickle >=3.1.0 - numba >=0.54.1 diff --git a/pyproject.toml b/pyproject.toml index c1c10f6d2..50940c858 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ "cf-xarray >=0.9.3", # cf-xarray is differently named on conda-forge "cftime >=1.4.1", "click >=8.1", - "dask[array] >=2024.8.1,<2024.11.0", + "dask[array] >=2024.8.1", "filelock >=3.14.0", "jsonpickle >=3.1.0", "numba >=0.54.1", diff --git a/xclim/sdba/base.py b/xclim/sdba/base.py index 5036058ef..03ec7d091 100644 --- a/xclim/sdba/base.py +++ b/xclim/sdba/base.py @@ -5,6 +5,7 @@ from __future__ import annotations +from collections import UserDict from collections.abc import Callable, Sequence from inspect import _empty, signature # noqa @@ -20,7 +21,7 @@ # ## Base class for the sdba module -class Parametrizable(dict): +class Parametrizable(UserDict): """Helper base class resembling a dictionary. This object is _completely_ defined by the content of its internal dictionary, accessible through item access @@ -35,24 +36,23 @@ class Parametrizable(dict): def __getstate__(self): """For (json)pickle, a Parametrizable should be defined by its internal dict only.""" - return self.parameters + return self.data def __setstate__(self, state): """For (json)pickle, a Parametrizable in only defined by its internal dict.""" - self.update(state) + # Unpickling skips the init, so we must _set_ data, we can't just update it - it's not there yet + self.data = {**state} def __getattr__(self, attr): """Get attributes.""" - try: - return self.__getitem__(attr) - except KeyError as err: - # Raise the proper error type for getattr - raise AttributeError(*err.args) from err + if attr == "data" or attr not in self.data: + return self.__getattribute__(attr) + return self.data[attr] @property def parameters(self) -> dict: """All parameters as a dictionary. Read-only.""" - return {**self} + return {**self.data} def __repr__(self) -> str: """Return a string representation."""