Skip to content

Commit 9fbb360

Browse files
authored
Compatibility with Dask 2025.4 (#6451)
* Use dask.compute() instead of compute() method - dask/dask#11844. * Remove out-dated test_landsea_unpacking_uses_dask. * What's New entry.
1 parent 8962e3b commit 9fbb360

File tree

5 files changed

+18
-46
lines changed

5 files changed

+18
-46
lines changed

docs/src/whatsnew/3.12.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ v3.12.1 (30 Apr 2025)
198198
versions of dask fix the bug casuing the pin. Introduced a minimum pin (2025.1.0)
199199
to avoid this bug. (:pull:`6342`)
200200

201+
#. `@trexfeathers`_ refactored Iris loading and saving to make it compatible
202+
with Dask version ``2025.4.0`` and above. (:pull:`6451`)
203+
201204

202205
📚 Documentation
203206
================

lib/iris/fileformats/netcdf/saver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,7 @@ def _create_generic_cf_array_var(
17421742
if len(element_dims) == 1:
17431743
data_first = data[0]
17441744
if is_lazy_data(data_first):
1745-
data_first = data_first.compute()
1745+
data_first = dask.compute(data_first)
17461746
data = list("%- *s" % (string_dimension_depth, data_first))
17471747
else:
17481748
orig_shape = data.shape
@@ -2380,7 +2380,7 @@ def complete(self) -> None:
23802380
raise ValueError(msg)
23812381

23822382
# Complete the saves now
2383-
self.delayed_completion().compute()
2383+
dask.compute(self.delayed_completion())
23842384

23852385

23862386
def save(

lib/iris/tests/integration/netcdf/test_delayed_save.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from cf_units import Unit
1010
import dask.array as da
1111
import dask.config
12-
from dask.delayed import Delayed
1312
import distributed
1413
import numpy as np
1514
import pytest
@@ -20,6 +19,13 @@
2019
from iris.tests.stock import realistic_4d
2120

2221

22+
def are_dask_collections(obj):
23+
result = dask.is_dask_collection(obj)
24+
if not result and hasattr(obj, "__len__"):
25+
result = all([dask.is_dask_collection(item) for item in obj])
26+
return result
27+
28+
2329
class Test__lazy_stream_data:
2430
# Ensure all saves are done with split-atttribute saving,
2531
# -- because some of these tests are sensitive to unexpected warnings.
@@ -130,7 +136,7 @@ def test_realfile_loadsave_equivalence(self, save_is_delayed, output_path):
130136
result = iris.save(original_cubes, output_path, compute=not save_is_delayed)
131137
if save_is_delayed:
132138
# In this case, must also "complete" the save.
133-
result.compute()
139+
dask.compute(result)
134140
reloaded_cubes = iris.load(output_path)
135141
reloaded_cubes = sorted(reloaded_cubes, key=lambda cube: cube.name())
136142
assert reloaded_cubes == original_cubes
@@ -188,7 +194,7 @@ def test_scheduler_types(self, output_path, scheduler_type, save_is_delayed):
188194
if not save_is_delayed:
189195
assert result is None
190196
else:
191-
assert isinstance(result, Delayed)
197+
assert are_dask_collections(result)
192198

193199
def test_time_of_writing(self, save_is_delayed, output_path, scheduler_type):
194200
# Check when lazy data is *actually* written :
@@ -251,7 +257,7 @@ def fetch_masks():
251257

252258
if save_is_delayed:
253259
# Complete the write.
254-
result.compute()
260+
dask.compute(result)
255261

256262
# Re-fetch the lazy arrays. The data should now **not be masked**.
257263
data_mask, coord_mask, ancil_mask, cm_mask = fetch_masks()
@@ -267,4 +273,4 @@ def test_no_delayed_writes(self, output_path):
267273
cube = self.make_testcube(include_lazy_content=False)
268274
warnings.simplefilter("error")
269275
result = iris.save(cube, output_path, compute=False)
270-
assert isinstance(result, Delayed)
276+
assert are_dask_collections(result)

lib/iris/tests/integration/netcdf/test_general.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from unittest import mock
1717
import warnings
1818

19+
import dask
1920
import numpy as np
2021
import numpy.ma as ma
2122
import pytest
@@ -456,7 +457,7 @@ def test_basic_save(self):
456457
ds.close()
457458

458459
# Complete the delayed saves.
459-
result.compute()
460+
dask.compute(result)
460461

461462
# Check that data now *is* written.
462463
ds = nc.Dataset(filepath_indirect)

lib/iris/tests/unit/fileformats/pp/test__interpret_field.py

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
import numpy as np
1515

16-
import iris
1716
import iris.fileformats.pp as pp
1817

1918

@@ -91,43 +90,6 @@ def test_deferred_fix_lbrow_lbnpt(self):
9190
self.assertEqual(f1.lbrow, 3)
9291
self.assertEqual(f1.lbnpt, 4)
9392

94-
@tests.skip_data
95-
def test_landsea_unpacking_uses_dask(self):
96-
# Ensure that the graph of the (lazy) landsea-masked data contains an
97-
# explicit reference to a (lazy) landsea-mask field.
98-
# Otherwise its compute() will need to invoke another compute().
99-
# See https://github.com/SciTools/iris/issues/3237
100-
101-
# This is too complex to explore in a mock-ist way, so let's load a
102-
# tiny bit of real data ...
103-
testfile_path = tests.get_data_path(
104-
["FF", "landsea_masked", "testdata_mini_lsm.ff"]
105-
)
106-
landsea_mask, soil_temp = iris.load_cubes(
107-
testfile_path, ("land_binary_mask", "soil_temperature")
108-
)
109-
110-
# Now check that the soil-temp dask graph correctly references the
111-
# landsea mask, in its dask graph.
112-
lazy_mask_array = landsea_mask.core_data()
113-
lazy_soildata_array = soil_temp.core_data()
114-
115-
# Work out the main dask key for the mask data, as used by 'compute()'.
116-
mask_toplev_key = (lazy_mask_array.name,) + (0,) * lazy_mask_array.ndim
117-
# Get the 'main' calculation entry.
118-
mask_toplev_item = lazy_mask_array.dask[mask_toplev_key]
119-
# This should be a task (a simple fetch).
120-
self.assertTrue(callable(mask_toplev_item))
121-
# Get the key (name) of the array that it fetches.
122-
mask_data_name = mask_toplev_item.args[0].key
123-
124-
# Check that the item this refers to is a PPDataProxy.
125-
self.assertIsInstance(lazy_mask_array.dask[mask_data_name], pp.PPDataProxy)
126-
127-
# Check that the soil-temp graph references the *same* lazy element,
128-
# showing that the mask+data calculation is handled by dask.
129-
self.assertIn(mask_data_name, lazy_soildata_array.dask.keys())
130-
13193

13294
if __name__ == "__main__":
13395
tests.main()

0 commit comments

Comments
 (0)