Skip to content

Commit 279bbc8

Browse files
authored
Merge pull request #846 from davidhassell/numpy-v2-from-cfa-in-cfdm
Move to numpy version 2
2 parents e3bc06c + feb7404 commit 279bbc8

File tree

11 files changed

+133
-148
lines changed

11 files changed

+133
-148
lines changed

Changelog.rst

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@ version 3.17.0
33

44
**2025-??-??**
55

6+
* Set a new minimum version of `numpy`: ``2.0.0``
7+
(https://github.com/NCAS-CMS/cf-python/issues/843)
68
* Replace dataset aggregation functionality (CFA) with that imported
79
from `cfdm` (https://github.com/NCAS-CMS/cf-python/issues/841)
810
* New keyword parameter to `cf.Field.compute_vertical_coordinates`:
911
``key`` (https://github.com/NCAS-CMS/cf-python/issues/802)
10-
* Changed dependency: ``1.12.0.0<=cfdm<1.12.1.0``
11-
* Changed dependency: ``h5py>=3.12.0``
12+
* Changed dependency: ``Python>=3.9.0``
13+
* Changed dependency: ``numpy>=2.0.0``
14+
* Changed dependency: ``cfdm>=1.12.0.0, <1.12.1.0``
15+
* Changed optional dependency: ``esmpy>=8.7.0``
16+
* Removed dependency (now incorporated into ``cfdm``): ``h5py``
17+
* Removed dependency (now incorporated into ``cfdm``): ``h5netcdf``
18+
* Removed dependency (now incorporated into ``cfdm``): ``s3fs``
1219

1320
----
1421

@@ -287,8 +294,8 @@ version 3.15.0
287294
* Handled the renaming of the ESMF Python interface from `ESMF` to
288295
`esmpy` at version 8.4.0. Both module names are accepted for now.
289296
* Changed dependency: ``1.10.1.0<=cfdm<1.10.2.0``
290-
* Changed (optional) dependency: ``8.0.0<=esmpy``
291-
* Changed (optional) dependency: ``1.10.0<=scipy``
297+
* Changed optional dependency: ``8.0.0<=esmpy``
298+
* Changed optional dependency: ``1.10.0<=scipy``
292299

293300
----
294301

cf/__init__.py

Lines changed: 94 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
8181
"""
8282

83-
__Conventions__ = "CF-1.11"
8483
__date__ = "2025-01-28"
8584
__version__ = "3.16.3"
8685

@@ -95,154 +94,143 @@
9594
"packaging",
9695
"scipy",
9796
)
98-
9997
x = ", ".join(_requires)
10098
_error0 = f"cf v{__version__} requires the modules {x}. "
10199

100+
import importlib.util
101+
from platform import python_version
102+
103+
_found_esmpy = bool(importlib.util.find_spec("esmpy"))
104+
102105
try:
103-
import cfdm
106+
import packaging
107+
from packaging.version import Version
104108
except ImportError as error1:
105109
raise ImportError(_error0 + str(error1))
110+
else:
111+
_minimum_vn = "20.0"
112+
if Version(packaging.__version__) < Version(_minimum_vn):
113+
raise RuntimeError(
114+
f"Bad packaging version: cf requires packaging>={_minimum_vn}. "
115+
f"Got {packaging.__version__} at {packaging.__file__}"
116+
)
106117

107-
__cf_version__ = cfdm.core.__cf_version__
108-
109-
from packaging.version import Version
110-
import importlib.util
111-
import platform
112-
113-
# ESMF renamed its Python module to `esmpy` at ESMF version 8.4.0. Allow
114-
# either for now for backwards compatibility.
115-
_found_esmpy = bool(
116-
importlib.util.find_spec("esmpy") or importlib.util.find_spec("ESMF")
117-
)
118+
try:
119+
import cfdm
120+
except ImportError as error1:
121+
raise ImportError(_error0 + str(error1))
122+
else:
123+
# Check the version of cfdm
124+
_minimum_vn = "1.12.0.0"
125+
_maximum_vn = "1.12.1.0"
126+
_cfdm_version = Version(cfdm.__version__)
127+
if (
128+
_cfdm_version < Version(_minimum_vn) or
129+
_cfdm_version >= Version(_maximum_vn)
130+
):
131+
raise RuntimeError(
132+
"Bad cfdm version: cf requires "
133+
f"{_minimum_vn}<=cfdm<{_maximum_vn}. "
134+
f"Got {cfdm.__version__} at {cfdm.__file__}"
135+
)
136+
137+
__cf_version__ = cfdm.__cf_version__
138+
__Conventions__ = f"CF-{__cf_version__}"
118139

119140
try:
120141
import netCDF4
121142
except ImportError as error1:
122143
raise ImportError(_error0 + str(error1))
144+
else:
145+
_minimum_vn = "1.7.2"
146+
if Version(netCDF4.__version__) < Version(_minimum_vn):
147+
raise RuntimeError(
148+
f"Bad netCDF4 version: cf requires netCDF4>={_minimum_vn}. "
149+
f"Got {netCDF4.__version__} at {netCDF4.__file__}"
150+
)
123151

124152
try:
125153
import numpy as np
126154
except ImportError as error1:
127155
raise ImportError(_error0 + str(error1))
156+
else:
157+
_minimum_vn = "2.0.0"
158+
if Version(np.__version__) < Version(_minimum_vn):
159+
raise ValueError(
160+
f"Bad numpy version: cf requires numpy>={_minimum_vn} "
161+
f"Got {np.__version__} at {np.__file__}"
162+
)
128163

129164
try:
130165
import cftime
131166
except ImportError as error1:
132167
raise ImportError(_error0 + str(error1))
168+
else:
169+
_minimum_vn = "1.6.4"
170+
if Version(cftime.__version__) < Version(_minimum_vn):
171+
raise RuntimeError(
172+
f"Bad cftime version: cf requires cftime>={_minimum_vn}. "
173+
f"Got {cftime.__version__} at {cftime.__file__}"
174+
)
133175

134176
try:
135177
import cfunits
136178
except ImportError as error1:
137179
raise ImportError(_error0 + str(error1))
180+
else:
181+
_minimum_vn = "3.3.7"
182+
if Version(cfunits.__version__) < Version(_minimum_vn):
183+
raise RuntimeError(
184+
f"Bad cfunits version: cf requires cfunits>={_minimum_vn}. "
185+
f"Got {cfunits.__version__} at {cfunits.__file__}"
186+
)
138187

139188
try:
140189
import psutil
141190
except ImportError as error1:
142191
raise ImportError(_error0 + str(error1))
192+
else:
193+
_minimum_vn = "0.6.0"
194+
if Version(psutil.__version__) < Version(_minimum_vn):
195+
raise RuntimeError(
196+
f"Bad psutil version: cf requires psutil>={_minimum_vn}. "
197+
f"Got {psutil.__version__} at {psutil.__file__}"
198+
)
143199

144200
try:
145201
import dask
146202
except ImportError as error1:
147203
raise ImportError(_error0 + str(error1))
148-
149-
try:
150-
import packaging
151-
except ImportError as error1:
152-
raise ImportError(_error0 + str(error1))
204+
else:
205+
_minimum_vn = "2024.6.1"
206+
_maximum_vn = "2024.7.1"
207+
if (
208+
Version(dask.__version__) < Version(_minimum_vn) or
209+
Version(dask.__version__) > Version(_maximum_vn)
210+
):
211+
raise ValueError(
212+
"Bad dask version: cf requires "
213+
f"{_minimum_vn}<=dask<={_maximum_vn}. "
214+
f"Got {dask.__version__} at {dask.__file__}"
215+
)
153216

154217
try:
155218
import scipy
156219
except ImportError as error1:
157220
raise ImportError(_error0 + str(error1))
158-
159-
# Check the version of packaging
160-
_minimum_vn = "20.0"
161-
if Version(packaging.__version__) < Version(_minimum_vn):
162-
raise RuntimeError(
163-
f"Bad packaging version: cf requires packaging>={_minimum_vn}. "
164-
f"Got {packaging.__version__} at {packaging.__file__}"
165-
)
166-
167-
# Check the version of psutil
168-
_minimum_vn = "0.6.0"
169-
if Version(psutil.__version__) < Version(_minimum_vn):
170-
raise RuntimeError(
171-
f"Bad psutil version: cf requires psutil>={_minimum_vn}. "
172-
f"Got {psutil.__version__} at {psutil.__file__}"
173-
)
174-
175-
# Check the version of netCDF4
176-
_minimum_vn = "1.6.5"
177-
if Version(netCDF4.__version__) < Version(_minimum_vn):
178-
raise RuntimeError(
179-
f"Bad netCDF4 version: cf requires netCDF4>={_minimum_vn}. "
180-
f"Got {netCDF4.__version__} at {netCDF4.__file__}"
181-
)
182-
183-
# Check the version of cftime
184-
_minimum_vn = "1.6.2"
185-
if Version(cftime.__version__) < Version(_minimum_vn):
186-
raise RuntimeError(
187-
f"Bad cftime version: cf requires cftime>={_minimum_vn}. "
188-
f"Got {cftime.__version__} at {cftime.__file__}"
189-
)
190-
191-
# Check the version of numpy
192-
_minimum_vn = "1.22"
193-
_maximum_vn = "2.0"
194-
if not Version(_minimum_vn) <= Version(np.__version__) < Version(_maximum_vn):
195-
raise ValueError(
196-
"Bad numpy version: cf requires _minimum_vn}<=numpy<{_maximum_vn}. "
197-
f"Got {np.__version__} at {np.__file__}"
198-
)
199-
200-
# Check the version of cfunits
201-
_minimum_vn = "3.3.7"
202-
if Version(cfunits.__version__) < Version(_minimum_vn):
203-
raise RuntimeError(
204-
f"Bad cfunits version: cf requires cfunits>={_minimum_vn}. "
205-
f"Got {cfunits.__version__} at {cfunits.__file__}"
206-
)
207-
208-
# Check the version of cfdm
209-
_minimum_vn = "1.12.0.0"
210-
_maximum_vn = "1.12.1.0"
211-
_cfdm_version = Version(cfdm.__version__)
212-
if not Version(_minimum_vn) <= _cfdm_version < Version(_maximum_vn):
213-
raise RuntimeError(
214-
f"Bad cfdm version: cf requires {_minimum_vn}<=cfdm<{_maximum_vn}. "
215-
f"Got {cfdm.__version__} at {cfdm.__file__}"
216-
)
217-
218-
# Check the version of dask
219-
220-
_minimum_vn = "2024.6.1"
221-
_maximum_vn = "2024.7.1"
222-
if (
223-
not Version(_minimum_vn)
224-
<= Version(dask.__version__)
225-
<= Version(_maximum_vn)
226-
):
221+
else:
222+
_minimum_vn = "1.10.0"
223+
if Version(scipy.__version__) < Version(_minimum_vn):
224+
raise RuntimeError(
225+
f"Bad scipy version: cf requires scipy>={_minimum_vn}. "
226+
f"Got {scipy.__version__} at {scipy.__file__}"
227+
)
228+
229+
_minimum_vn = "3.9.0"
230+
if Version(python_version()) < Version(_minimum_vn):
227231
raise ValueError(
228-
"Bad dask version: cf requires {_minimum_vn}<=dask<={_maximum_vn}. "
229-
f"Got {dask.__version__} at {dask.__file__}"
230-
)
231-
232-
# Check the version of Python
233-
_minimum_vn = "3.8.0"
234-
if Version(platform.python_version()) < Version(_minimum_vn):
235-
raise ValueError(
236-
f"Bad python version: cf requires python version {_minimum_vn} "
237-
f"or later. Got {platform.python_version()}"
238-
)
239-
240-
# Check the version of scipy
241-
_minimum_vn = "1.10.0"
242-
if Version(scipy.__version__) < Version(_minimum_vn):
243-
raise RuntimeError(
244-
f"Bad scipy version: cf requires scipy>={_minimum_vn}. "
245-
f"Got {scipy.__version__} at {scipy.__file__}"
232+
f"Bad python version: cf requires python>={_minimum_vn}. "
233+
f"Got {python_version()}"
246234
)
247235

248236
del _minimum_vn, _maximum_vn

cf/data/collapse/dask_collapse.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -858,9 +858,17 @@ def cf_sample_size_chunk(x, dtype="i8", computing_meta=False, **kwargs):
858858
return x
859859

860860
x = cfdm_to_memory(x)
861-
862861
if np.ma.isMA(x):
863-
N = chunk.sum(np.ones_like(x, dtype=dtype), **kwargs)
862+
# Note: We're not using `np.ones_like` here (like we used to)
863+
# because numpy currently (numpy==2.2.3) has a bug that
864+
# produces a RuntimeWarning: "numpy/ma/core.py:502:
865+
# RuntimeWarning: invalid value encountered in cast
866+
# fill_value = np.asarray(fill_value,
867+
# dtype=ndtype)". See
868+
# https://github.com/numpy/numpy/issues/28255 for more
869+
# details.
870+
x = np.ma.array(np.ones((x.shape), dtype=x.dtype), mask=x.mask)
871+
N = chunk.sum(x, **kwargs)
864872
else:
865873
if dtype:
866874
kwargs["dtype"] = dtype

cf/functions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2755,6 +2755,7 @@ def dirname(path, normalise=False, uri=None, isdir=False, sep=False):
27552755
dirname.__doc__ = cfdm.dirname.__doc__.replace("cfdm.", "cf.")
27562756

27572757
from functools import partial
2758+
27582759
dirname2 = partial(cfdm.dirname)
27592760
dirname2.__doc__ = cfdm.dirname.__doc__.replace("cfdm.", "cf.")
27602761

cf/mixin/fielddomain.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -692,8 +692,7 @@ def _point_not_in_cell(nodes_x, nodes_y, point):
692692
if ind is not None:
693693
mask_component_shape = []
694694
masked_subspace_size = 1
695-
# TODONUMPY2: https://numpy.org/devdocs/numpy_2_0_migration_guide.html#adapting-to-changes-in-the-copy-keyword
696-
ind = np.array(ind, copy=False)
695+
ind = np.array(ind)
697696

698697
for i, (axis, start, stop) in enumerate(
699698
zip(canonical_axes, ind.min(axis=1), ind.max(axis=1))

cf/mixin/propertiesdata.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,6 @@ class PropertiesData(Properties):
4949

5050
_special_properties = ("units", "calendar")
5151

52-
def __array__(self, *dtype):
53-
"""Returns a numpy array representation of the data."""
54-
data = self.get_data(None)
55-
if data is not None:
56-
return data.__array__(*dtype)
57-
58-
raise ValueError(f"{self.__class__.__name__} has no data")
59-
6052
def __contains__(self, value):
6153
"""Called to implement membership test operators.
6254

cf/regrid/regrid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2186,7 +2186,7 @@ def create_esmpy_mesh(grid, mask=None):
21862186
# esmpy.
21872187
min_id = node_ids.min()
21882188
if min_id < 1:
2189-
node_ids += min_id + 1
2189+
node_ids = node_ids + min_id + 1
21902190

21912191
# Add nodes. This must be done before `add_elements`.
21922192
esmpy_mesh.add_nodes(

cf/test/test_Data.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2621,7 +2621,7 @@ def test_Data_percentile_median(self):
26212621
a1 = np.nanpercentile(filled, q, keepdims=keepdims)
26222622
mask = np.isnan(a1)
26232623
if mask.any():
2624-
a1 = np.ma.masked_where(mask, a1, copy=False)
2624+
a1 = np.ma.masked_where(mask, a1)
26252625

26262626
b1 = d.percentile(q, squeeze=not keepdims)
26272627
self.assertEqual(b1.shape, a1.shape)
@@ -3613,6 +3613,7 @@ def test_Data_sample_size(self):
36133613
b = np.ma.asanyarray(b)
36143614

36153615
e = d.sample_size(axes=axis, squeeze=True)
3616+
36163617
e = np.ma.array(e.array)
36173618

36183619
self.assertTrue((e.mask == b.mask).all())

0 commit comments

Comments
 (0)