Skip to content

Commit

Permalink
Test suite: explicitly ignore irrelevant warnings (pydata#2162)
Browse files Browse the repository at this point in the history
* Test suite: explicitly ignore irrelevant warnings

Also includes a fix for Dataset.update()

* Cleaner implementation of Dataset.__setitem__

* more lint

* Fix dask version check

* Fix warning in Dataset.update() and clean-up logic

* Fix whats new

* More whats new

* DeprecationWarning -> FutureWarning for old resample API
  • Loading branch information
shoyer authored May 29, 2018
1 parent 5ddfee6 commit 9c80059
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 67 deletions.
9 changes: 7 additions & 2 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,15 @@ Enhancements
Bug fixes
~~~~~~~~~

- Fixed a bug where `to_netcdf(..., unlimited_dims='bar'` yielded NetCDF files
with spurious 0-length dimensions (i.e. `b`, `a`, and `r`) (:issue:`2134`).
- Fixed a bug where ``to_netcdf(..., unlimited_dims='bar')`` yielded NetCDF
files with spurious 0-length dimensions (i.e. ``b``, ``a``, and ``r``)
(:issue:`2134`).
By `Joe Hamman <https://github.com/jhamman>`_.

- Removed spurious warnings with ``Dataset.update(Dataset)`` (:issue:`2161`)
and ``array.equals(array)`` when ``array`` contains ``NaT`` (:issue:`2162`).
By `Stephan Hoyer <https://github.com/shoyer>`_.

- Aggregations with :py:meth:`Dataset.reduce` (including ``mean``, ``sum``,
etc) no longer drop unrelated coordinates (:issue:`1470`). Also fixed a
bug where non-scalar data-variables that did not include the aggregation
Expand Down
2 changes: 1 addition & 1 deletion xarray/conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def maybe_encode_nonstring_dtype(var, name=None):
warnings.warn('saving variable %s with floating '
'point data as an integer dtype without '
'any _FillValue to use for NaNs' % name,
SerializationWarning, stacklevel=3)
SerializationWarning, stacklevel=10)
data = duck_array_ops.around(data)[...]
data = data.astype(dtype=dtype)
var = Variable(dims, data, attrs, encoding)
Expand Down
2 changes: 1 addition & 1 deletion xarray/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ def _resample_immediately(self, freq, dim, how, skipna,
"how=\"{how}\", instead consider using "
".resample({dim}=\"{freq}\").{how}('{dim}') ".format(
dim=dim, freq=freq, how=how),
DeprecationWarning, stacklevel=3)
FutureWarning, stacklevel=3)

if isinstance(dim, basestring):
dim = self[dim]
Expand Down
20 changes: 13 additions & 7 deletions xarray/core/duck_array_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,13 @@ def array_equiv(arr1, arr2):
if arr1.shape != arr2.shape:
return False

flag_array = (arr1 == arr2)
flag_array |= (isnull(arr1) & isnull(arr2))
with warnings.catch_warnings():
warnings.filterwarnings('ignore', "In the future, 'NAT == x'")

return bool(flag_array.all())
flag_array = (arr1 == arr2)
flag_array |= (isnull(arr1) & isnull(arr2))

return bool(flag_array.all())


def array_notnull_equiv(arr1, arr2):
Expand All @@ -159,11 +162,14 @@ def array_notnull_equiv(arr1, arr2):
if arr1.shape != arr2.shape:
return False

flag_array = (arr1 == arr2)
flag_array |= isnull(arr1)
flag_array |= isnull(arr2)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', "In the future, 'NAT == x'")

flag_array = (arr1 == arr2)
flag_array |= isnull(arr1)
flag_array |= isnull(arr2)

return bool(flag_array.all())
return bool(flag_array.all())


def count(data, axis=None):
Expand Down
23 changes: 13 additions & 10 deletions xarray/core/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,21 +547,24 @@ def dataset_merge_method(dataset, other, overwrite_vars, compat, join):


def dataset_update_method(dataset, other):
"""Guts of the Dataset.update method
"""Guts of the Dataset.update method.
This drops a duplicated coordinates from `other` (GH:2068)
This drops a duplicated coordinates from `other` if `other` is not an
`xarray.Dataset`, e.g., if it's a dict with DataArray values (GH2068,
GH2180).
"""
from .dataset import Dataset
from .dataarray import DataArray

other = other.copy()
for k, obj in other.items():
if isinstance(obj, (Dataset, DataArray)):
# drop duplicated coordinates
coord_names = [c for c in obj.coords
if c not in obj.dims and c in dataset.coords]
if coord_names:
other[k] = obj.drop(coord_names)
if not isinstance(other, Dataset):
other = OrderedDict(other)
for key, value in other.items():
if isinstance(value, DataArray):
# drop conflicting coordinates
coord_names = [c for c in value.coords
if c not in value.dims and c in dataset.coords]
if coord_names:
other[key] = value.drop(coord_names)

return merge_core([dataset, other], priority_arg=1,
indexes=dataset.indexes)
10 changes: 8 additions & 2 deletions xarray/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ def _importorskip(modname, minversion=None):
has_pathlib, requires_pathlib = _importorskip('pathlib2')
if has_dask:
import dask
dask.set_options(get=dask.get)
if LooseVersion(dask.__version__) < '0.18':
dask.set_options(get=dask.get)
else:
dask.config.set(scheduler='sync')
try:
import_seaborn()
has_seaborn = True
Expand Down Expand Up @@ -191,7 +194,10 @@ def source_ndarray(array):
"""Given an ndarray, return the base object which holds its memory, or the
object itself.
"""
base = getattr(array, 'base', np.asarray(array).base)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'DatetimeIndex.base')
warnings.filterwarnings('ignore', 'TimedeltaIndex.base')
base = getattr(array, 'base', np.asarray(array).base)
if base is None:
base = array
return base
42 changes: 25 additions & 17 deletions xarray/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,21 +363,26 @@ def test_roundtrip_cftime_datetime_data_enable_cftimeindex(self):
expected_decoded_t0 = np.array([date_type(1, 1, 1)])
expected_calendar = times[0].calendar

with xr.set_options(enable_cftimeindex=True):
with self.roundtrip(expected, save_kwargs=kwds) as actual:
abs_diff = abs(actual.t.values - expected_decoded_t)
assert (abs_diff <= np.timedelta64(1, 's')).all()
assert (actual.t.encoding['units'] ==
'days since 0001-01-01 00:00:00.000000')
assert (actual.t.encoding['calendar'] ==
expected_calendar)

abs_diff = abs(actual.t0.values - expected_decoded_t0)
assert (abs_diff <= np.timedelta64(1, 's')).all()
assert (actual.t0.encoding['units'] ==
'days since 0001-01-01')
assert (actual.t.encoding['calendar'] ==
expected_calendar)
with warnings.catch_warnings():
if expected_calendar in {'proleptic_gregorian', 'gregorian'}:
warnings.filterwarnings(
'ignore', 'Unable to decode time axis')

with xr.set_options(enable_cftimeindex=True):
with self.roundtrip(expected, save_kwargs=kwds) as actual:
abs_diff = abs(actual.t.values - expected_decoded_t)
assert (abs_diff <= np.timedelta64(1, 's')).all()
assert (actual.t.encoding['units'] ==
'days since 0001-01-01 00:00:00.000000')
assert (actual.t.encoding['calendar'] ==
expected_calendar)

abs_diff = abs(actual.t0.values - expected_decoded_t0)
assert (abs_diff <= np.timedelta64(1, 's')).all()
assert (actual.t0.encoding['units'] ==
'days since 0001-01-01')
assert (actual.t.encoding['calendar'] ==
expected_calendar)

def test_roundtrip_timedelta_data(self):
time_deltas = pd.to_timedelta(['1h', '2h', 'NaT'])
Expand Down Expand Up @@ -767,8 +772,11 @@ def test_default_fill_value(self):
# Test default encoding for int:
ds = Dataset({'x': ('y', np.arange(10.0))})
kwargs = dict(encoding={'x': {'dtype': 'int16'}})
with self.roundtrip(ds, save_kwargs=kwargs) as actual:
self.assertTrue('_FillValue' not in actual.x.encoding)
with warnings.catch_warnings():
warnings.filterwarnings(
'ignore', '.*floating point data as an integer')
with self.roundtrip(ds, save_kwargs=kwargs) as actual:
self.assertTrue('_FillValue' not in actual.x.encoding)
self.assertEqual(ds.x.encoding, {})

# Test default encoding for implicit int:
Expand Down
4 changes: 3 additions & 1 deletion xarray/tests/test_coding_times.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ def test_decode_cf_datetime_overflow():
expected = (datetime(1677, 12, 31), datetime(2262, 4, 12))

for i, day in enumerate(days):
result = coding.times.decode_cf_datetime(day, units)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'Unable to decode time axis')
result = coding.times.decode_cf_datetime(day, units)
assert result == expected[i]


Expand Down
4 changes: 3 additions & 1 deletion xarray/tests/test_conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ def test_decode_cf_datetime_transition_to_invalid(self):
ds = Dataset(coords={'time': [0, 266 * 365]})
units = 'days since 2000-01-01 00:00:00'
ds.time.attrs = dict(units=units)
ds_decoded = conventions.decode_cf(ds)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'unable to decode time')
ds_decoded = conventions.decode_cf(ds)

expected = [datetime(2000, 1, 1, 0, 0),
datetime(2265, 10, 28, 0, 0)]
Expand Down
3 changes: 1 addition & 2 deletions xarray/tests/test_dask.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,7 @@ def counting_get(*args, **kwargs):
count[0] += 1
return dask.get(*args, **kwargs)

with dask.set_options(get=counting_get):
ds.load()
ds.load(get=counting_get)
assert count[0] == 1

def test_stack(self):
Expand Down
30 changes: 19 additions & 11 deletions xarray/tests/test_dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from copy import deepcopy
from distutils.version import LooseVersion
from textwrap import dedent
import warnings

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -321,11 +322,14 @@ def test_constructor_from_self_described(self):
actual = DataArray(series)
assert_equal(expected[0].reset_coords('x', drop=True), actual)

panel = pd.Panel({0: frame})
actual = DataArray(panel)
expected = DataArray([data], expected.coords, ['dim_0', 'x', 'y'])
expected['dim_0'] = [0]
assert_identical(expected, actual)
if hasattr(pd, 'Panel'):
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'\W*Panel is deprecated')
panel = pd.Panel({0: frame})
actual = DataArray(panel)
expected = DataArray([data], expected.coords, ['dim_0', 'x', 'y'])
expected['dim_0'] = [0]
assert_identical(expected, actual)

expected = DataArray(data,
coords={'x': ['a', 'b'], 'y': [-1, -2],
Expand Down Expand Up @@ -2320,7 +2324,7 @@ def test_resample_old_vs_new_api(self):
array = DataArray(np.ones(10), [('time', times)])

# Simple mean
with pytest.warns(DeprecationWarning):
with pytest.warns(FutureWarning):
old_mean = array.resample('1D', 'time', how='mean')
new_mean = array.resample(time='1D').mean()
assert_identical(old_mean, new_mean)
Expand All @@ -2329,7 +2333,7 @@ def test_resample_old_vs_new_api(self):
attr_array = array.copy()
attr_array.attrs['meta'] = 'data'

with pytest.warns(DeprecationWarning):
with pytest.warns(FutureWarning):
old_mean = attr_array.resample('1D', dim='time', how='mean',
keep_attrs=True)
new_mean = attr_array.resample(time='1D').mean(keep_attrs=True)
Expand All @@ -2340,7 +2344,7 @@ def test_resample_old_vs_new_api(self):
nan_array = array.copy()
nan_array[1] = np.nan

with pytest.warns(DeprecationWarning):
with pytest.warns(FutureWarning):
old_mean = nan_array.resample('1D', 'time', how='mean',
skipna=False)
new_mean = nan_array.resample(time='1D').mean(skipna=False)
Expand All @@ -2354,12 +2358,12 @@ def test_resample_old_vs_new_api(self):
# Discard attributes on the call using the new api to match
# convention from old api
new_api = getattr(resampler, method)(keep_attrs=False)
with pytest.warns(DeprecationWarning):
with pytest.warns(FutureWarning):
old_api = array.resample('1D', dim='time', how=method)
assert_identical(new_api, old_api)
for method in [np.mean, np.sum, np.max, np.min]:
new_api = resampler.reduce(method)
with pytest.warns(DeprecationWarning):
with pytest.warns(FutureWarning):
old_api = array.resample('1D', dim='time', how=method)
assert_identical(new_api, old_api)

Expand Down Expand Up @@ -2713,9 +2717,13 @@ def test_to_pandas(self):

# roundtrips
for shape in [(3,), (3, 4), (3, 4, 5)]:
if len(shape) > 2 and not hasattr(pd, 'Panel'):
continue
dims = list('abc')[:len(shape)]
da = DataArray(np.random.randn(*shape), dims=dims)
roundtripped = DataArray(da.to_pandas()).drop(dims)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'\W*Panel is deprecated')
roundtripped = DataArray(da.to_pandas()).drop(dims)
assert_identical(da, roundtripped)

with raises_regex(ValueError, 'cannot convert'):
Expand Down
43 changes: 33 additions & 10 deletions xarray/tests/test_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from distutils.version import LooseVersion
from io import StringIO
from textwrap import dedent
import warnings

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -338,14 +339,20 @@ def test_constructor_pandas_single(self):
das = [
DataArray(np.random.rand(4), dims=['a']), # series
DataArray(np.random.rand(4, 3), dims=['a', 'b']), # df
DataArray(np.random.rand(4, 3, 2), dims=['a', 'b', 'c']), # panel
]

for a in das:
pandas_obj = a.to_pandas()
ds_based_on_pandas = Dataset(pandas_obj)
for dim in ds_based_on_pandas.data_vars:
assert_array_equal(ds_based_on_pandas[dim], pandas_obj[dim])
if hasattr(pd, 'Panel'):
das.append(
DataArray(np.random.rand(4, 3, 2), dims=['a', 'b', 'c']))

with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'\W*Panel is deprecated')
for a in das:
pandas_obj = a.to_pandas()
ds_based_on_pandas = Dataset(pandas_obj)
for dim in ds_based_on_pandas.data_vars:
assert_array_equal(
ds_based_on_pandas[dim], pandas_obj[dim])

def test_constructor_compat(self):
data = OrderedDict([('x', DataArray(0, coords={'y': 1})),
Expand Down Expand Up @@ -2139,6 +2146,22 @@ def test_update(self):
actual.update(other)
assert_identical(expected, actual)

def test_update_overwrite_coords(self):
data = Dataset({'a': ('x', [1, 2])}, {'b': 3})
data.update(Dataset(coords={'b': 4}))
expected = Dataset({'a': ('x', [1, 2])}, {'b': 4})
assert_identical(data, expected)

data = Dataset({'a': ('x', [1, 2])}, {'b': 3})
data.update(Dataset({'c': 5}, coords={'b': 4}))
expected = Dataset({'a': ('x', [1, 2]), 'c': 5}, {'b': 4})
assert_identical(data, expected)

data = Dataset({'a': ('x', [1, 2])}, {'b': 3})
data.update({'c': DataArray(5, coords={'b': 4})})
expected = Dataset({'a': ('x', [1, 2]), 'c': 5}, {'b': 3})
assert_identical(data, expected)

def test_update_auto_align(self):
ds = Dataset({'x': ('t', [3, 4])}, {'t': [0, 1]})

Expand Down Expand Up @@ -2343,14 +2366,14 @@ def test_setitem_with_coords(self):
actual = ds.copy()
actual['var3'] = other
assert_identical(expected, actual)
assert 'numbers' in other # should not change other
assert 'numbers' in other.coords # should not change other

# with alignment
other = ds['var3'].isel(dim3=slice(1, -1))
other['numbers'] = ('dim3', np.arange(8))
actual = ds.copy()
actual['var3'] = other
assert 'numbers' in other # should not change other
assert 'numbers' in other.coords # should not change other
expected = ds.copy()
expected['var3'] = ds['var3'].isel(dim3=slice(1, -1))
assert_identical(expected, actual)
Expand All @@ -2362,7 +2385,7 @@ def test_setitem_with_coords(self):
actual = ds.copy()
actual['var3'] = other
assert 'position' in actual
assert 'position' in other
assert 'position' in other.coords

# assigning a coordinate-only dataarray
actual = ds.copy()
Expand Down Expand Up @@ -2774,7 +2797,7 @@ def test_resample_old_vs_new_api(self):
# Discard attributes on the call using the new api to match
# convention from old api
new_api = getattr(resampler, method)(keep_attrs=False)
with pytest.warns(DeprecationWarning):
with pytest.warns(FutureWarning):
old_api = ds.resample('1D', dim='time', how=method)
assert_identical(new_api, old_api)

Expand Down
Loading

0 comments on commit 9c80059

Please sign in to comment.