From b22c4296f70ea9bf59cc1c8e6c34346489046338 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:40:37 +0200 Subject: [PATCH 1/5] Verbose error handling for non-valid duckarrays (#9314) * Add helpful error for non-duckarrays * Add proof of concept * Update test_namedarray.py * Update test_namedarray.py * Update test_namedarray.py * remove test * Update test_namedarray.py --- xarray/tests/test_namedarray.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/xarray/tests/test_namedarray.py b/xarray/tests/test_namedarray.py index 7687765e659..8ccf8c541b7 100644 --- a/xarray/tests/test_namedarray.py +++ b/xarray/tests/test_namedarray.py @@ -1,6 +1,7 @@ from __future__ import annotations import copy +import sys from abc import abstractmethod from collections.abc import Mapping from typing import TYPE_CHECKING, Any, Generic, cast, overload @@ -86,7 +87,29 @@ def check_duck_array_typevar(a: duckarray[Any, _DType]) -> duckarray[Any, _DType if isinstance(b, _arrayfunction_or_api): return b else: - raise TypeError(f"a ({type(a)}) is not a valid _arrayfunction or _arrayapi") + missing_attrs = "" + actual_attrs = set(dir(b)) + for t in _arrayfunction_or_api: + if sys.version_info >= (3, 13): + # https://github.com/python/cpython/issues/104873 + from typing import get_protocol_members + + expected_attrs = get_protocol_members(t) + elif sys.version_info >= (3, 12): + expected_attrs = t.__protocol_attrs__ + else: + from typing import _get_protocol_attrs # type: ignore[attr-defined] + + expected_attrs = _get_protocol_attrs(t) + + missing_attrs_ = expected_attrs - actual_attrs + if missing_attrs_: + missing_attrs += f"{t.__name__} - {missing_attrs_}\n" + raise TypeError( + f"a ({type(a)}) is not a valid _arrayfunction or _arrayapi. " + "Missing following attrs:\n" + f"{missing_attrs}" + ) class NamedArraySubclassobjects: From 2580a9fb4dc534662a48937e5fdef5f85839b1ee Mon Sep 17 00:00:00 2001 From: Michele Claus <31700619+clausmichele@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:47:54 +0200 Subject: [PATCH 2/5] Fix pirate arrgragation (#9328) --- xarray/core/dataarray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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` From 4bae53cc9be93a6278000f5ae777b45d913d1ae0 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 11 Aug 2024 19:39:06 +0200 Subject: [PATCH 3/5] Remove ignores due to pandas-stubs (#9329) * Update test_conventions.py * more --- xarray/tests/test_backends.py | 2 +- xarray/tests/test_coding_times.py | 8 ++++---- xarray/tests/test_conventions.py | 2 +- xarray/tests/test_formatting.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 4fa8736427d..507886ca678 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -568,7 +568,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_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"), From 562015ce7063a634c2072f9c84a724fecf18aff0 Mon Sep 17 00:00:00 2001 From: Tom White Date: Sun, 11 Aug 2024 19:15:04 +0100 Subject: [PATCH 4/5] Use duck array ops for `around` and `round` (#9326) * Use duck array ops for `around` and `round` * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add type hint to `around` * Update xarray/coding/variables.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Illviljan <14371165+Illviljan@users.noreply.github.com> --- xarray/coding/variables.py | 4 ++-- xarray/core/duck_array_ops.py | 42 ++++++++--------------------------- 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/xarray/coding/variables.py b/xarray/coding/variables.py index 8a3afe650f2..c240cfe5939 100644 --- a/xarray/coding/variables.py +++ b/xarray/coding/variables.py @@ -662,8 +662,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/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): From ce5130f39d780cdce87366ee657665f4a5d3051d Mon Sep 17 00:00:00 2001 From: Diogo Teles Sant'Anna Date: Mon, 12 Aug 2024 14:38:00 -0300 Subject: [PATCH 5/5] fix: github workflow vulnerable to script injection (#9331) Signed-off-by: Diogo Teles Sant'Anna --- .github/workflows/benchmarks.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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} \