Skip to content

Commit 8950993

Browse files
max-sixtykeewis
andauthored
Silencing numpy warnings (#4369)
* WIP on silencing numpy warnings * Remove testing expected warning * Remove ignore warnings in tests; add xfail test for corner case * _ * @keewis feedback * Formatting * Update xarray/tests/test_dataset.py Co-authored-by: keewis <[email protected]> * Update xarray/core/dataarray.py * whatsnew * Add note to xfailing test * _ * Pacify pylance linter * Add more tests for no errors * Convert to docstring Co-authored-by: keewis <[email protected]>
1 parent d3d93d7 commit 8950993

9 files changed

+70
-29
lines changed

doc/whats-new.rst

+2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ Internal Changes
105105
By `Maximilian Roos <https://github.com/max-sixty>`_
106106
- Only load resource files when running inside a Jupyter Notebook
107107
(:issue:`4294`) By `Guido Imperiale <https://github.com/crusaderky>`_
108+
- Silenced most ``numpy`` warnings such as ``Mean of empty slice``. (:pull:`4369`)
109+
By `Maximilian Roos <https://github.com/max-sixty>`_
108110
- Enable type checking for :py:func:`concat` (:issue:`4238`)
109111
By `Mathias Hauser <https://github.com/mathause>`_.
110112
- Updated plot functions for matplotlib version 3.3 and silenced warnings in the

xarray/core/dataarray.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import datetime
22
import functools
3+
import warnings
34
from numbers import Number
45
from typing import (
56
TYPE_CHECKING,
@@ -1583,9 +1584,7 @@ def swap_dims(self, dims_dict: Mapping[Hashable, Hashable]) -> "DataArray":
15831584
--------
15841585
15851586
>>> arr = xr.DataArray(
1586-
... data=[0, 1],
1587-
... dims="x",
1588-
... coords={"x": ["a", "b"], "y": ("x", [0, 1])},
1587+
... data=[0, 1], dims="x", coords={"x": ["a", "b"], "y": ("x", [0, 1])},
15891588
... )
15901589
>>> arr
15911590
<xarray.DataArray (x: 2)>
@@ -2709,8 +2708,13 @@ def __rmatmul__(self, other):
27092708
def _unary_op(f: Callable[..., Any]) -> Callable[..., "DataArray"]:
27102709
@functools.wraps(f)
27112710
def func(self, *args, **kwargs):
2712-
with np.errstate(all="ignore"):
2713-
return self.__array_wrap__(f(self.variable.data, *args, **kwargs))
2711+
with warnings.catch_warnings():
2712+
warnings.filterwarnings("ignore", r"All-NaN (slice|axis) encountered")
2713+
warnings.filterwarnings(
2714+
"ignore", r"Mean of empty slice", category=RuntimeWarning
2715+
)
2716+
with np.errstate(all="ignore"):
2717+
return self.__array_wrap__(f(self.variable.data, *args, **kwargs))
27142718

27152719
return func
27162720

@@ -3424,9 +3428,7 @@ def map_blocks(
34243428
to the function being applied in ``xr.map_blocks()``:
34253429
34263430
>>> array.map_blocks(
3427-
... calculate_anomaly,
3428-
... kwargs={"groupby_type": "time.year"},
3429-
... template=array,
3431+
... calculate_anomaly, kwargs={"groupby_type": "time.year"}, template=array,
34303432
... ) # doctest: +ELLIPSIS
34313433
<xarray.DataArray (time: 24)>
34323434
dask.array<calculate_anomaly-...-<this, shape=(24,), dtype=float64, chunksize=(24,), chunktype=numpy.ndarray>

xarray/core/nanops.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import warnings
2+
13
import numpy as np
24

35
from . import dtypes, nputils, utils
@@ -133,10 +135,14 @@ def nanmean(a, axis=None, dtype=None, out=None):
133135
if a.dtype.kind == "O":
134136
return _nanmean_ddof_object(0, a, axis=axis, dtype=dtype)
135137

136-
if isinstance(a, dask_array_type):
137-
return dask_array.nanmean(a, axis=axis, dtype=dtype)
138+
with warnings.catch_warnings():
139+
warnings.filterwarnings(
140+
"ignore", r"Mean of empty slice", category=RuntimeWarning
141+
)
142+
if isinstance(a, dask_array_type):
143+
return dask_array.nanmean(a, axis=axis, dtype=dtype)
138144

139-
return np.nanmean(a, axis=axis, dtype=dtype)
145+
return np.nanmean(a, axis=axis, dtype=dtype)
140146

141147

142148
def nanmedian(a, axis=None, out=None):

xarray/core/variable.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -1635,10 +1635,14 @@ def reduce(
16351635

16361636
input_data = self.data if allow_lazy else self.values
16371637

1638-
if axis is not None:
1639-
data = func(input_data, axis=axis, **kwargs)
1640-
else:
1641-
data = func(input_data, **kwargs)
1638+
with warnings.catch_warnings():
1639+
warnings.filterwarnings(
1640+
"ignore", r"Mean of empty slice", category=RuntimeWarning
1641+
)
1642+
if axis is not None:
1643+
data = func(input_data, axis=axis, **kwargs)
1644+
else:
1645+
data = func(input_data, **kwargs)
16421646

16431647
if getattr(data, "shape", ()) == self.shape:
16441648
dims = self.dims

xarray/tests/test_dataarray.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -6186,24 +6186,21 @@ def test_isin(da):
61866186
assert_equal(result, expected)
61876187

61886188

6189+
@pytest.mark.filterwarnings("error:Mean of empty slice")
61896190
@pytest.mark.parametrize("da", (1, 2), indirect=True)
61906191
def test_rolling_iter(da):
61916192

61926193
rolling_obj = da.rolling(time=7)
6193-
with warnings.catch_warnings():
6194-
warnings.filterwarnings("ignore", "Mean of empty slice")
6195-
rolling_obj_mean = rolling_obj.mean()
6194+
rolling_obj_mean = rolling_obj.mean()
61966195

61976196
assert len(rolling_obj.window_labels) == len(da["time"])
61986197
assert_identical(rolling_obj.window_labels, da["time"])
61996198

62006199
for i, (label, window_da) in enumerate(rolling_obj):
62016200
assert label == da["time"].isel(time=i)
62026201

6203-
with warnings.catch_warnings():
6204-
warnings.filterwarnings("ignore", "Mean of empty slice")
6205-
actual = rolling_obj_mean.isel(time=i)
6206-
expected = window_da.mean("time")
6202+
actual = rolling_obj_mean.isel(time=i)
6203+
expected = window_da.mean("time")
62076204

62086205
# TODO add assert_allclose_with_nan, which compares nan position
62096206
# as well as the closeness of the values.
@@ -6489,6 +6486,11 @@ def test_raise_no_warning_for_nan_in_binary_ops():
64896486
assert len(record) == 0
64906487

64916488

6489+
@pytest.mark.filterwarnings("error")
6490+
def test_no_warning_for_all_nan():
6491+
_ = xr.DataArray([np.NaN, np.NaN]).mean()
6492+
6493+
64926494
def test_name_in_masking():
64936495
name = "RingoStarr"
64946496
da = xr.DataArray(range(10), coords=[("x", range(10))], name=name)

xarray/tests/test_dataset.py

+28
Original file line numberDiff line numberDiff line change
@@ -6027,6 +6027,8 @@ def test_rolling_wrapped_bottleneck(ds, name, center, min_periods, key):
60276027
expected = getattr(bn, func_name)(
60286028
ds[key].values, window=7, axis=0, min_count=min_periods
60296029
)
6030+
else:
6031+
raise ValueError
60306032
assert_array_equal(actual[key].values, expected)
60316033

60326034
# Test center
@@ -6191,6 +6193,32 @@ def test_raise_no_warning_for_nan_in_binary_ops():
61916193
assert len(record) == 0
61926194

61936195

6196+
@pytest.mark.filterwarnings("error")
6197+
@pytest.mark.parametrize("ds", (2,), indirect=True)
6198+
def test_raise_no_warning_assert_close(ds):
6199+
assert_allclose(ds, ds)
6200+
6201+
6202+
@pytest.mark.xfail(reason="See https://github.com/pydata/xarray/pull/4369 or docstring")
6203+
@pytest.mark.filterwarnings("error")
6204+
@pytest.mark.parametrize("ds", (2,), indirect=True)
6205+
@pytest.mark.parametrize("name", ("mean", "max"))
6206+
def test_raise_no_warning_dask_rolling_assert_close(ds, name):
6207+
"""
6208+
This is a puzzle — I can't easily find the source of the warning. It
6209+
requires `assert_allclose` to be run, for the `ds` param to be 2, and is
6210+
different for `mean` and `max`. `sum` raises no warning.
6211+
"""
6212+
6213+
ds = ds.chunk({"x": 4})
6214+
6215+
rolling_obj = ds.rolling(time=4, x=3)
6216+
6217+
actual = getattr(rolling_obj, name)()
6218+
expected = getattr(getattr(ds.rolling(time=4), name)().rolling(x=3), name)()
6219+
assert_allclose(actual, expected)
6220+
6221+
61946222
@pytest.mark.parametrize("dask", [True, False])
61956223
@pytest.mark.parametrize("edge_order", [1, 2])
61966224
def test_differentiate(dask, edge_order):

xarray/tests/test_duck_array_ops.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,9 @@ def test_concatenate_type_promotion(self):
120120
result = concatenate([[1], ["b"]])
121121
assert_array_equal(result, np.array([1, "b"], dtype=object))
122122

123+
@pytest.mark.filterwarnings("error")
123124
def test_all_nan_arrays(self):
124-
with warnings.catch_warnings():
125-
warnings.filterwarnings("ignore", "All-NaN slice")
126-
warnings.filterwarnings("ignore", "Mean of empty slice")
127-
assert np.isnan(mean([np.nan, np.nan]))
125+
assert np.isnan(mean([np.nan, np.nan]))
128126

129127

130128
def test_cumsum_1d():

xarray/tests/test_groupby.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -447,8 +447,7 @@ def test_groupby_drops_nans():
447447

448448
# reduction operation along a different dimension
449449
actual = grouped.mean("time")
450-
with pytest.warns(RuntimeWarning): # mean of empty slice
451-
expected = ds.mean("time").where(ds.id.notnull())
450+
expected = ds.mean("time").where(ds.id.notnull())
452451
assert_identical(actual, expected)
453452

454453
# NaN in non-dimensional coordinate

xarray/tests/test_weighted.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def test_weighted_sum_nan(weights, expected, skipna):
119119
assert_equal(expected, result)
120120

121121

122-
@pytest.mark.filterwarnings("ignore:Mean of empty slice")
122+
@pytest.mark.filterwarnings("error")
123123
@pytest.mark.parametrize("da", ([1.0, 2], [1, np.nan], [np.nan, np.nan]))
124124
@pytest.mark.parametrize("skipna", (True, False))
125125
@pytest.mark.parametrize("factor", [1, 2, 3.14])

0 commit comments

Comments
 (0)