diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 886bcfbd548..72d748ecb74 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -5,6 +5,9 @@ on: types: [opened, reopened, synchronize, labeled] workflow_dispatch: +env: + PR_HEAD_LABEL: ${{ github.event.pull_request.head.label }} + jobs: benchmark: if: ${{ contains( github.event.pull_request.labels.*.name, 'run-benchmark') && github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' }} @@ -49,7 +52,7 @@ jobs: # ID this runner asv machine --yes echo "Baseline: ${{ github.event.pull_request.base.sha }} (${{ github.event.pull_request.base.label }})" - echo "Contender: ${GITHUB_SHA} (${{ github.event.pull_request.head.label }})" + echo "Contender: ${GITHUB_SHA} ($PR_HEAD_LABEL)" # Run benchmarks for current commit against base ASV_OPTIONS="--split --show-stderr --factor $ASV_FACTOR" asv continuous $ASV_OPTIONS ${{ github.event.pull_request.base.sha }} ${GITHUB_SHA} \ diff --git a/ci/requirements/environment.yml b/ci/requirements/environment.yml index ef02a3e7f23..40ef4a7fc74 100644 --- a/ci/requirements/environment.yml +++ b/ci/requirements/environment.yml @@ -26,7 +26,7 @@ dependencies: - numba - numbagg - numexpr - - numpy + - numpy>=2 - opt_einsum - packaging - pandas diff --git a/xarray/coding/variables.py b/xarray/coding/variables.py index 55c12029dbf..a7cc28466e3 100644 --- a/xarray/coding/variables.py +++ b/xarray/coding/variables.py @@ -685,8 +685,8 @@ def encode(self, variable: Variable, name: T_Name = None) -> Variable: SerializationWarning, stacklevel=10, ) - data = np.around(data) - data = data.astype(dtype=dtype) + data = duck_array_ops.round(data) + data = duck_array_ops.astype(data, dtype=dtype) return Variable(dims, data, attrs, encoding, fastpath=True) else: return variable diff --git a/xarray/core/computation.py b/xarray/core/computation.py index 5d21d0836b9..bb7122e82de 100644 --- a/xarray/core/computation.py +++ b/xarray/core/computation.py @@ -23,7 +23,7 @@ from xarray.core.merge import merge_attrs, merge_coordinates_without_align from xarray.core.options import OPTIONS, _get_keep_attrs from xarray.core.types import Dims, T_DataArray -from xarray.core.utils import is_dict_like, is_duck_dask_array, is_scalar, parse_dims +from xarray.core.utils import is_dict_like, is_scalar, parse_dims from xarray.core.variable import Variable from xarray.namedarray.parallelcompat import get_chunked_array_type from xarray.namedarray.pycompat import is_chunked_array @@ -1693,11 +1693,11 @@ def cross( if a.sizes[dim] < b.sizes[dim]: a = a.pad({dim: (0, 1)}, constant_values=0) # TODO: Should pad or apply_ufunc handle correct chunking? - a = a.chunk({dim: -1}) if is_duck_dask_array(a.data) else a + a = a.chunk({dim: -1}) if is_chunked_array(a.data) else a else: b = b.pad({dim: (0, 1)}, constant_values=0) # TODO: Should pad or apply_ufunc handle correct chunking? - b = b.chunk({dim: -1}) if is_duck_dask_array(b.data) else b + b = b.chunk({dim: -1}) if is_chunked_array(b.data) else b else: raise ValueError( f"{dim!r} on {'a' if a.sizes[dim] == 1 else 'b'} is incompatible:" diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index 79fd0412d40..0818f488b7e 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -7223,7 +7223,7 @@ def coarsen( User guide describing :py:func:`~xarray.DataArray.coarsen` :ref:`compute.coarsen` - User guide on block arrgragation :py:func:`~xarray.DataArray.coarsen` + User guide on block aggregation :py:func:`~xarray.DataArray.coarsen` :doc:`xarray-tutorial:fundamentals/03.3_windowed` Tutorial on windowed computation using :py:func:`~xarray.DataArray.coarsen` diff --git a/xarray/core/duck_array_ops.py b/xarray/core/duck_array_ops.py index 8993c136ba6..4e6b066591f 100644 --- a/xarray/core/duck_array_ops.py +++ b/xarray/core/duck_array_ops.py @@ -12,13 +12,14 @@ import warnings from functools import partial from importlib import import_module +from typing import Callable import numpy as np import pandas as pd from numpy import all as array_all # noqa from numpy import any as array_any # noqa +from numpy import concatenate as _concatenate from numpy import ( # noqa - around, # noqa full_like, gradient, isclose, @@ -29,7 +30,6 @@ transpose, unravel_index, ) -from numpy import concatenate as _concatenate from numpy.lib.stride_tricks import sliding_window_view # noqa from packaging.version import Version from pandas.api.types import is_extension_array_dtype @@ -122,37 +122,13 @@ def fail_on_dask_array_input(values, msg=None, func_name=None): # Requires special-casing because pandas won't automatically dispatch to dask.isnull via NEP-18 pandas_isnull = _dask_or_eager_func("isnull", eager_module=pd, dask_module="dask.array") -# np.around has failing doctests, overwrite it so they pass: -# https://github.com/numpy/numpy/issues/19759 -around.__doc__ = str.replace( - around.__doc__ or "", - "array([0., 2.])", - "array([0., 2.])", -) -around.__doc__ = str.replace( - around.__doc__ or "", - "array([0., 2.])", - "array([0., 2.])", -) -around.__doc__ = str.replace( - around.__doc__ or "", - "array([0.4, 1.6])", - "array([0.4, 1.6])", -) -around.__doc__ = str.replace( - around.__doc__ or "", - "array([0., 2., 2., 4., 4.])", - "array([0., 2., 2., 4., 4.])", -) -around.__doc__ = str.replace( - around.__doc__ or "", - ( - ' .. [2] "How Futile are Mindless Assessments of\n' - ' Roundoff in Floating-Point Computation?", William Kahan,\n' - " https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf\n" - ), - "", -) + +def round(array): + xp = get_array_namespace(array) + return xp.round(array) + + +around: Callable = round def isnull(data): diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index fa9fd4b5bc5..d321cb3d7a7 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -595,7 +595,7 @@ def test_roundtrip_cftime_datetime_data(self) -> None: assert actual.t.encoding["calendar"] == expected_calendar def test_roundtrip_timedelta_data(self) -> None: - time_deltas = pd.to_timedelta(["1h", "2h", "NaT"]) # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 + time_deltas = pd.to_timedelta(["1h", "2h", "NaT"]) expected = Dataset({"td": ("td", time_deltas), "td0": time_deltas[0]}) with self.roundtrip(expected) as actual: assert_identical(expected, actual) diff --git a/xarray/tests/test_coding_times.py b/xarray/tests/test_coding_times.py index 9d048a2230c..d52ec28090c 100644 --- a/xarray/tests/test_coding_times.py +++ b/xarray/tests/test_coding_times.py @@ -628,10 +628,10 @@ def test_cf_timedelta_2d() -> None: @pytest.mark.parametrize( ["deltas", "expected"], [ - (pd.to_timedelta(["1 day", "2 days"]), "days"), # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 - (pd.to_timedelta(["1h", "1 day 1 hour"]), "hours"), # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 - (pd.to_timedelta(["1m", "2m", np.nan]), "minutes"), # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 - (pd.to_timedelta(["1m3s", "1m4s"]), "seconds"), # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 + (pd.to_timedelta(["1 day", "2 days"]), "days"), + (pd.to_timedelta(["1h", "1 day 1 hour"]), "hours"), + (pd.to_timedelta(["1m", "2m", np.nan]), "minutes"), + (pd.to_timedelta(["1m3s", "1m4s"]), "seconds"), ], ) def test_infer_timedelta_units(deltas, expected) -> None: diff --git a/xarray/tests/test_computation.py b/xarray/tests/test_computation.py index 8b480b02472..e974b8b1ac8 100644 --- a/xarray/tests/test_computation.py +++ b/xarray/tests/test_computation.py @@ -2547,7 +2547,8 @@ def test_polyfit_polyval_integration( "cartesian", 1, ], - [ # Test 1 sized arrays with coords: + # Test 1 sized arrays with coords: + pytest.param( xr.DataArray( np.array([1]), dims=["cartesian"], @@ -2562,8 +2563,10 @@ def test_polyfit_polyval_integration( np.array([4, 5, 6]), "cartesian", -1, - ], - [ # Test filling in between with coords: + marks=(pytest.mark.xfail(),), + ), + # Test filling in between with coords: + pytest.param( xr.DataArray( [1, 2], dims=["cartesian"], @@ -2578,7 +2581,8 @@ def test_polyfit_polyval_integration( np.array([4, 5, 6]), "cartesian", -1, - ], + marks=(pytest.mark.xfail(),), + ), ], ) def test_cross(a, b, ae, be, dim: str, axis: int, use_dask: bool) -> None: diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py index ea518b6d677..d7291d6abee 100644 --- a/xarray/tests/test_conventions.py +++ b/xarray/tests/test_conventions.py @@ -119,7 +119,7 @@ def test_incompatible_attributes(self) -> None: Variable( ["t"], pd.date_range("2000-01-01", periods=3), {"units": "foobar"} ), - Variable(["t"], pd.to_timedelta(["1 day"]), {"units": "foobar"}), # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 + Variable(["t"], pd.to_timedelta(["1 day"]), {"units": "foobar"}), Variable(["t"], [0, 1, 2], {"add_offset": 0}, {"add_offset": 2}), Variable(["t"], [0, 1, 2], {"_FillValue": 0}, {"_FillValue": 2}), ] diff --git a/xarray/tests/test_formatting.py b/xarray/tests/test_formatting.py index 0bd8abc3a70..9d0eb81bace 100644 --- a/xarray/tests/test_formatting.py +++ b/xarray/tests/test_formatting.py @@ -118,9 +118,9 @@ def test_format_items(self) -> None: np.arange(4) * np.timedelta64(500, "ms"), "00:00:00 00:00:00.500000 00:00:01 00:00:01.500000", ), - (pd.to_timedelta(["NaT", "0s", "1s", "NaT"]), "NaT 00:00:00 00:00:01 NaT"), # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 + (pd.to_timedelta(["NaT", "0s", "1s", "NaT"]), "NaT 00:00:00 00:00:01 NaT"), ( - pd.to_timedelta(["1 day 1 hour", "1 day", "0 hours"]), # type: ignore[arg-type] #https://github.com/pandas-dev/pandas-stubs/issues/956 + pd.to_timedelta(["1 day 1 hour", "1 day", "0 hours"]), "1 days 01:00:00 1 days 00:00:00 0 days 00:00:00", ), ([1, 2, 3], "1 2 3"),