Skip to content

Commit

Permalink
numpy 2.0 copy-keyword and trapz vs trapezoid (#8865)
Browse files Browse the repository at this point in the history
* adapt handling of copy keyword argument in coding/strings.py for numpy >= 2.0dev

* import either trapz or trapezoid depending on numpy version

* add /change whats-new.rst entry

* fix mypy, fix import order

* adapt handling of copy keyword argument in coding/strings.py for numpy >= 2.0dev
  • Loading branch information
kmuehlbauer committed Mar 22, 2024
1 parent bd9495f commit 7c3d2dd
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
9 changes: 7 additions & 2 deletions doc/whats-new.rst
Expand Up @@ -59,9 +59,14 @@ Bug fixes
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.
- do not cast `_FillValue`/`missing_value` in `CFMaskCoder` if `_Unsigned` is provided
(:issue:`8844`, :pull:`8852`).
- Adapt handling of copy keyword argument in scipy backend for numpy >= 2.0dev
(:issue:`8844`, :pull:`8851`).
- Adapt handling of copy keyword argument for numpy >= 2.0dev
(:issue:`8844`, :pull:`8851`, :pull:`8865``).
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.
- import trapz/trapezoid depending on numpy version.
(:issue:`8844`, :pull:`8865`).
By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.



Documentation
~~~~~~~~~~~~~
Expand Down
15 changes: 13 additions & 2 deletions xarray/coding/strings.py
Expand Up @@ -15,10 +15,13 @@
unpack_for_encoding,
)
from xarray.core import indexing
from xarray.core.utils import module_available
from xarray.core.variable import Variable
from xarray.namedarray.parallelcompat import get_chunked_array_type
from xarray.namedarray.pycompat import is_chunked_array

HAS_NUMPY_2_0 = module_available("numpy", minversion="2.0.0.dev0")


def create_vlen_dtype(element_type):
if element_type not in (str, bytes):
Expand Down Expand Up @@ -156,8 +159,12 @@ def bytes_to_char(arr):

def _numpy_bytes_to_char(arr):
"""Like netCDF4.stringtochar, but faster and more flexible."""
# adapt handling of copy-kwarg to numpy 2.0
# see https://github.com/numpy/numpy/issues/25916
# and https://github.com/numpy/numpy/pull/25922
copy = None if HAS_NUMPY_2_0 else False
# ensure the array is contiguous
arr = np.array(arr, copy=False, order="C", dtype=np.bytes_)
arr = np.array(arr, copy=copy, order="C", dtype=np.bytes_)
return arr.reshape(arr.shape + (1,)).view("S1")


Expand Down Expand Up @@ -199,8 +206,12 @@ def char_to_bytes(arr):

def _numpy_char_to_bytes(arr):
"""Like netCDF4.chartostring, but faster and more flexible."""
# adapt handling of copy-kwarg to numpy 2.0
# see https://github.com/numpy/numpy/issues/25916
# and https://github.com/numpy/numpy/pull/25922
copy = None if HAS_NUMPY_2_0 else False
# based on: http://stackoverflow.com/a/10984878/809705
arr = np.array(arr, copy=False, order="C")
arr = np.array(arr, copy=copy, order="C")
dtype = "S" + str(arr.shape[-1])
return arr.view(dtype).reshape(arr.shape[:-1])

Expand Down
15 changes: 11 additions & 4 deletions xarray/tests/test_dataset.py
Expand Up @@ -80,6 +80,13 @@
except ImportError:
pass

# from numpy version 2.0 trapz is deprecated and renamed to trapezoid
# remove once numpy 2.0 is the oldest supported version
try:
from numpy import trapezoid # type: ignore[attr-defined,unused-ignore]
except ImportError:
from numpy import trapz as trapezoid

sparse_array_type = array_type("sparse")

pytestmark = [
Expand Down Expand Up @@ -6999,7 +7006,7 @@ def test_integrate(dask) -> None:
actual = da.integrate("x")
# coordinate that contains x should be dropped.
expected_x = xr.DataArray(
np.trapz(da.compute(), da["x"], axis=0),
trapezoid(da.compute(), da["x"], axis=0),
dims=["y"],
coords={k: v for k, v in da.coords.items() if "x" not in v.dims},
)
Expand All @@ -7012,7 +7019,7 @@ def test_integrate(dask) -> None:
# along y
actual = da.integrate("y")
expected_y = xr.DataArray(
np.trapz(da, da["y"], axis=1),
trapezoid(da, da["y"], axis=1),
dims=["x"],
coords={k: v for k, v in da.coords.items() if "y" not in v.dims},
)
Expand Down Expand Up @@ -7093,7 +7100,7 @@ def test_cumulative_integrate(dask) -> None:
@pytest.mark.filterwarnings("ignore:Converting non-nanosecond")
@pytest.mark.parametrize("dask", [True, False])
@pytest.mark.parametrize("which_datetime", ["np", "cftime"])
def test_trapz_datetime(dask, which_datetime) -> None:
def test_trapezoid_datetime(dask, which_datetime) -> None:
rs = np.random.RandomState(42)
if which_datetime == "np":
coord = np.array(
Expand Down Expand Up @@ -7124,7 +7131,7 @@ def test_trapz_datetime(dask, which_datetime) -> None:
da = da.chunk({"time": 4})

actual = da.integrate("time", datetime_unit="D")
expected_data = np.trapz(
expected_data = trapezoid(
da.compute().data,
duck_array_ops.datetime_to_numeric(da["time"].data, datetime_unit="D"),
axis=0,
Expand Down

0 comments on commit 7c3d2dd

Please sign in to comment.