From 971b1f58c86629fe56df760a2e84c8fa8f4fb1d4 Mon Sep 17 00:00:00 2001 From: Tom Nicholas <35968931+TomNicholas@users.noreply.github.com> Date: Mon, 1 Nov 2021 17:14:02 -0400 Subject: [PATCH] Update minimum dependencies for 0.20 (#5917) * conda ci requirements * update setup.cfg for 0.20 * update dependency list in whatsnew * try removing setuptools * Fix * update * Update ci/requirements/py37-min-all-deps.yml * fix test * add notes * fix pint * fix accessor * One more fix * one last fix? Co-authored-by: keewis Co-authored-by: dcherian Co-authored-by: Deepak Cherian --- ci/requirements/py37-bare-minimum.yml | 4 ++-- ci/requirements/py37-min-all-deps.yml | 32 +++++++++++++-------------- doc/whats-new.rst | 24 +++++++++++++++----- setup.cfg | 4 ++-- xarray/backends/zarr.py | 6 +---- xarray/coding/cftime_offsets.py | 10 +-------- xarray/coding/cftimeindex.py | 6 ----- xarray/coding/times.py | 11 ++------- xarray/core/accessor_dt.py | 11 +-------- xarray/core/missing.py | 13 ++--------- xarray/tests/__init__.py | 7 +----- xarray/tests/test_accessor_dt.py | 16 +------------- xarray/tests/test_backends.py | 2 -- xarray/tests/test_dask.py | 6 ++--- xarray/tests/test_dataarray.py | 19 +++------------- xarray/tests/test_dataset.py | 6 ++--- xarray/tests/test_plot.py | 5 ----- xarray/tests/test_variable.py | 6 ++--- 18 files changed, 59 insertions(+), 129 deletions(-) diff --git a/ci/requirements/py37-bare-minimum.yml b/ci/requirements/py37-bare-minimum.yml index b474f92e8a1..f9148d6dfd0 100644 --- a/ci/requirements/py37-bare-minimum.yml +++ b/ci/requirements/py37-bare-minimum.yml @@ -10,6 +10,6 @@ dependencies: - pytest-cov - pytest-env - pytest-xdist - - numpy=1.17 - - pandas=1.0 + - numpy=1.18 + - pandas=1.1 - typing_extensions=3.7 diff --git a/ci/requirements/py37-min-all-deps.yml b/ci/requirements/py37-min-all-deps.yml index f70786b72ac..2d5a0f4e8d9 100644 --- a/ci/requirements/py37-min-all-deps.yml +++ b/ci/requirements/py37-min-all-deps.yml @@ -10,29 +10,31 @@ dependencies: - python=3.7 - boto3=1.13 - bottleneck=1.3 + # cartopy 0.18 conflicts with pynio - cartopy=0.17 - cdms2=3.1 - cfgrib=0.9 - - cftime=1.1 + - cftime=1.2 - coveralls - - dask=2.24 - - distributed=2.24 + - dask=2.30 + - distributed=2.30 - h5netcdf=0.8 - h5py=2.10 + # hdf5 1.12 conflicts with h5py=2.10 - hdf5=1.10 - hypothesis - iris=2.4 - - lxml=4.5 # Optional dep of pydap - - matplotlib-base=3.2 + - lxml=4.6 # Optional dep of pydap + - matplotlib-base=3.3 - nc-time-axis=1.2 # netcdf follows a 1.major.minor[.patch] convention # (see https://github.com/Unidata/netcdf4-python/issues/1090) # bumping the netCDF4 version is currently blocked by #4491 - netcdf4=1.5.3 - - numba=0.49 - - numpy=1.17 - - pandas=1.0 - - pint=0.15 + - numba=0.51 + - numpy=1.18 + - pandas=1.1 + - pint=0.16 - pip - pseudonetcdf=3.1 - pydap=3.2 @@ -42,13 +44,11 @@ dependencies: - pytest-env - pytest-xdist - rasterio=1.1 - - scipy=1.4 - - seaborn=0.10 - # don't need to pin setuptools, now that we don't depend on it - - setuptools - - sparse=0.8 - - toolz=0.10 + - scipy=1.5 + - seaborn=0.11 + - sparse=0.11 + - toolz=0.11 - typing_extensions=3.7 - - zarr=2.4 + - zarr=2.5 - pip: - numbagg==0.1 diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 3bd04220db1..ba92d9507c1 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -49,12 +49,24 @@ Breaking changes ~~~~~~~~~~~~~~~~ - The minimum versions of some dependencies were changed: - ============ ====== ==== - Package Old New - ============ ====== ==== - dask 2.15 2.24 - distributed 2.15 2.24 - ============ ====== ==== + =============== ====== ==== + Package Old New + =============== ====== ==== + cftime 1.1 1.2 + dask 2.15 2.30 + distributed 2.15 2.30 + lxml 4.5 4.6 + matplotlib-base 3.2 3.3 + numba 0.49 0.51 + numpy 1.17 1.18 + pandas 1.0 1.1 + pint 0.15 0.16 + scipy 1.4 1.5 + seaborn 0.10 0.11 + sparse 0.8 0.11 + toolz 0.10 0.11 + zarr 2.4 2.5 + =============== ====== ==== - The ``__repr__`` of a :py:class:`xarray.Dataset`'s ``coords`` and ``data_vars`` ignore ``xarray.set_option(display_max_rows=...)`` and show the full output diff --git a/setup.cfg b/setup.cfg index 5ccd077f4f1..bd123262cf7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -76,8 +76,8 @@ zip_safe = False # https://mypy.readthedocs.io/en/latest/installed_packages.htm include_package_data = True python_requires = >=3.7 install_requires = - numpy >= 1.17 - pandas >= 1.0 + numpy >= 1.18 + pandas >= 1.1 importlib-metadata; python_version < '3.8' typing_extensions >= 3.7; python_version < '3.8' diff --git a/xarray/backends/zarr.py b/xarray/backends/zarr.py index d8548ca702f..3eb6a3caf72 100644 --- a/xarray/backends/zarr.py +++ b/xarray/backends/zarr.py @@ -1,6 +1,5 @@ import os import warnings -from distutils.version import LooseVersion import numpy as np @@ -353,10 +352,7 @@ def open_group( synchronizer=synchronizer, path=group, ) - if LooseVersion(zarr.__version__) >= "2.5.0": - open_kwargs["storage_options"] = storage_options - elif storage_options: - raise ValueError("Storage options only compatible with zarr>=2.5.0") + open_kwargs["storage_options"] = storage_options if chunk_store: open_kwargs["chunk_store"] = chunk_store diff --git a/xarray/coding/cftime_offsets.py b/xarray/coding/cftime_offsets.py index c080f19ef73..729f15bbd50 100644 --- a/xarray/coding/cftime_offsets.py +++ b/xarray/coding/cftime_offsets.py @@ -42,7 +42,6 @@ import re from datetime import timedelta -from distutils.version import LooseVersion from functools import partial from typing import ClassVar, Optional @@ -243,14 +242,7 @@ def _shift_month(date, months, day_option="start"): day = _days_in_month(reference) else: raise ValueError(day_option) - if LooseVersion(cftime.__version__) < LooseVersion("1.0.4"): - # dayofwk=-1 is required to update the dayofwk and dayofyr attributes of - # the returned date object in versions of cftime between 1.0.2 and - # 1.0.3.4. It can be removed for versions of cftime greater than - # 1.0.3.4. - return date.replace(year=year, month=month, day=day, dayofwk=-1) - else: - return date.replace(year=year, month=month, day=day) + return date.replace(year=year, month=month, day=day) def roll_qtrday(other, n, month, day_option, modby=3): diff --git a/xarray/coding/cftimeindex.py b/xarray/coding/cftimeindex.py index c0750069c23..507e245ac09 100644 --- a/xarray/coding/cftimeindex.py +++ b/xarray/coding/cftimeindex.py @@ -134,12 +134,6 @@ def _parse_iso8601_with_reso(date_type, timestr): # TODO: Consider adding support for sub-second resolution? replace[attr] = int(value) resolution = attr - if LooseVersion(cftime.__version__) < LooseVersion("1.0.4"): - # dayofwk=-1 is required to update the dayofwk and dayofyr attributes of - # the returned date object in versions of cftime between 1.0.2 and - # 1.0.3.4. It can be removed for versions of cftime greater than - # 1.0.3.4. - replace["dayofwk"] = -1 return default.replace(**replace), resolution diff --git a/xarray/coding/times.py b/xarray/coding/times.py index 2b2d25f1666..ea75219db5a 100644 --- a/xarray/coding/times.py +++ b/xarray/coding/times.py @@ -1,7 +1,6 @@ import re import warnings from datetime import datetime, timedelta -from distutils.version import LooseVersion from functools import partial import numpy as np @@ -269,19 +268,13 @@ def decode_cf_datetime(num_dates, units, calendar=None, use_cftime=None): def to_timedelta_unboxed(value, **kwargs): - if LooseVersion(pd.__version__) < "0.25.0": - result = pd.to_timedelta(value, **kwargs, box=False) - else: - result = pd.to_timedelta(value, **kwargs).to_numpy() + result = pd.to_timedelta(value, **kwargs).to_numpy() assert result.dtype == "timedelta64[ns]" return result def to_datetime_unboxed(value, **kwargs): - if LooseVersion(pd.__version__) < "0.25.0": - result = pd.to_datetime(value, **kwargs, box=False) - else: - result = pd.to_datetime(value, **kwargs).to_numpy() + result = pd.to_datetime(value, **kwargs).to_numpy() assert result.dtype == "datetime64[ns]" return result diff --git a/xarray/core/accessor_dt.py b/xarray/core/accessor_dt.py index 0965d440fc7..2cdd467bdf3 100644 --- a/xarray/core/accessor_dt.py +++ b/xarray/core/accessor_dt.py @@ -1,5 +1,4 @@ import warnings -from distutils.version import LooseVersion import numpy as np import pandas as pd @@ -336,9 +335,6 @@ def isocalendar(self): if not is_np_datetime_like(self._obj.data.dtype): raise AttributeError("'CFTimeIndex' object has no attribute 'isocalendar'") - if LooseVersion(pd.__version__) < "1.1.0": - raise AttributeError("'isocalendar' not available in pandas < 1.1.0") - values = _get_date_field(self._obj.data, "isocalendar", np.int64) obj_type = type(self._obj) @@ -383,12 +379,7 @@ def weekofyear(self): FutureWarning, ) - if LooseVersion(pd.__version__) < "1.1.0": - weekofyear = Properties._tslib_field_accessor( - "weekofyear", "The week ordinal of the year", np.int64 - ).fget(self) - else: - weekofyear = self.isocalendar().week + weekofyear = self.isocalendar().week return weekofyear diff --git a/xarray/core/missing.py b/xarray/core/missing.py index 36983a227b9..8ed9e23f1eb 100644 --- a/xarray/core/missing.py +++ b/xarray/core/missing.py @@ -1,6 +1,5 @@ import datetime as dt import warnings -from distutils.version import LooseVersion from functools import partial from numbers import Number from typing import Any, Callable, Dict, Hashable, Sequence, Union @@ -557,16 +556,8 @@ def _localize(var, indexes_coords): """ indexes = {} for dim, [x, new_x] in indexes_coords.items(): - if np.issubdtype(new_x.dtype, np.datetime64) and LooseVersion( - np.__version__ - ) < LooseVersion("1.18"): - # np.nanmin/max changed behaviour for datetime types in numpy 1.18, - # see https://github.com/pydata/xarray/pull/3924/files - minval = np.min(new_x.values) - maxval = np.max(new_x.values) - else: - minval = np.nanmin(new_x.values) - maxval = np.nanmax(new_x.values) + minval = np.nanmin(new_x.values) + maxval = np.nanmax(new_x.values) index = x.to_index() imin = index.get_loc(minval, method="nearest") imax = index.get_loc(maxval, method="nearest") diff --git a/xarray/tests/__init__.py b/xarray/tests/__init__.py index f610941914b..5aee729f15a 100644 --- a/xarray/tests/__init__.py +++ b/xarray/tests/__init__.py @@ -61,9 +61,6 @@ def LooseVersion(vstring): has_matplotlib, requires_matplotlib = _importorskip("matplotlib") -has_matplotlib_3_3_0, requires_matplotlib_3_3_0 = _importorskip( - "matplotlib", minversion="3.3.0" -) has_scipy, requires_scipy = _importorskip("scipy") has_pydap, requires_pydap = _importorskip("pydap.client") has_netCDF4, requires_netCDF4 = _importorskip("netCDF4") @@ -77,7 +74,6 @@ def LooseVersion(vstring): has_nc_time_axis, requires_nc_time_axis = _importorskip("nc_time_axis") has_rasterio, requires_rasterio = _importorskip("rasterio") has_zarr, requires_zarr = _importorskip("zarr") -has_zarr_2_5_0, requires_zarr_2_5_0 = _importorskip("zarr", minversion="2.5.0") has_fsspec, requires_fsspec = _importorskip("fsspec") has_iris, requires_iris = _importorskip("iris") has_cfgrib, requires_cfgrib = _importorskip("cfgrib") @@ -86,8 +82,7 @@ def LooseVersion(vstring): has_sparse, requires_sparse = _importorskip("sparse") has_cupy, requires_cupy = _importorskip("cupy") has_cartopy, requires_cartopy = _importorskip("cartopy") -# Need Pint 0.15 for __dask_tokenize__ tests for Quantity wrapped Dask Arrays -has_pint_0_15, requires_pint_0_15 = _importorskip("pint", minversion="0.15") +has_pint, requires_pint = _importorskip("pint") has_numexpr, requires_numexpr = _importorskip("numexpr") # some special cases diff --git a/xarray/tests/test_accessor_dt.py b/xarray/tests/test_accessor_dt.py index 135aa058439..b9473bf9e09 100644 --- a/xarray/tests/test_accessor_dt.py +++ b/xarray/tests/test_accessor_dt.py @@ -71,7 +71,7 @@ def setup(self): ) def test_field_access(self, field) -> None: - if LooseVersion(pd.__version__) >= "1.1.0" and field in ["week", "weekofyear"]: + if field in ["week", "weekofyear"]: data = self.times.isocalendar()["week"] else: data = getattr(self.times, field) @@ -98,13 +98,6 @@ def test_field_access(self, field) -> None: ) def test_isocalendar(self, field, pandas_field) -> None: - if LooseVersion(pd.__version__) < "1.1.0": - with pytest.raises( - AttributeError, match=r"'isocalendar' not available in pandas < 1.1.0" - ): - self.data.time.dt.isocalendar()[field] - return - # pandas isocalendar has dtypy UInt32Dtype, convert to Int64 expected = pd.Int64Index(getattr(self.times.isocalendar(), pandas_field)) expected = xr.DataArray( @@ -185,13 +178,6 @@ def test_dask_field_access(self, field) -> None: def test_isocalendar_dask(self, field) -> None: import dask.array as da - if LooseVersion(pd.__version__) < "1.1.0": - with pytest.raises( - AttributeError, match=r"'isocalendar' not available in pandas < 1.1.0" - ): - self.data.time.dt.isocalendar()[field] - return - expected = getattr(self.times_data.dt.isocalendar(), field) dask_times_arr = da.from_array(self.times_arr, chunks=(5, 5, 50)) diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 7657e42ff66..4e9b98b02e9 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -71,7 +71,6 @@ requires_scipy, requires_scipy_or_netCDF4, requires_zarr, - requires_zarr_2_5_0, ) from .test_coding_times import ( _ALL_CALENDARS, @@ -2400,7 +2399,6 @@ def create_zarr_target(self): @requires_fsspec -@requires_zarr_2_5_0 def test_zarr_storage_options(): pytest.importorskip("aiobotocore") ds = create_test_data() diff --git a/xarray/tests/test_dask.py b/xarray/tests/test_dask.py index 9eda6ccdf19..3b962cb2c5c 100644 --- a/xarray/tests/test_dask.py +++ b/xarray/tests/test_dask.py @@ -24,7 +24,7 @@ assert_frame_equal, assert_identical, raise_if_dask_computes, - requires_pint_0_15, + requires_pint, requires_scipy_or_netCDF4, ) from .test_backends import create_tmp_file @@ -297,7 +297,7 @@ def test_persist(self): self.assertLazyAndAllClose(u + 1, v) self.assertLazyAndAllClose(u + 1, v2) - @requires_pint_0_15(reason="Need __dask_tokenize__") + @requires_pint def test_tokenize_duck_dask_array(self): import pint @@ -748,7 +748,7 @@ def test_from_dask_variable(self): a = DataArray(self.lazy_array.variable, coords={"x": range(4)}, name="foo") self.assertLazyAndIdentical(self.lazy_array, a) - @requires_pint_0_15(reason="Need __dask_tokenize__") + @requires_pint def test_tokenize_duck_dask_array(self): import pint diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py index b1bd7576a12..53c650046e7 100644 --- a/xarray/tests/test_dataarray.py +++ b/xarray/tests/test_dataarray.py @@ -40,7 +40,7 @@ requires_iris, requires_numbagg, requires_numexpr, - requires_pint_0_15, + requires_pint, requires_scipy, requires_sparse, source_ndarray, @@ -97,10 +97,6 @@ def test_repr_multiindex(self): ) assert expected == repr(self.mda) - @pytest.mark.skipif( - LooseVersion(np.__version__) < "1.16", - reason="old versions of numpy have different printing behavior", - ) def test_repr_multiindex_long(self): mindex_long = pd.MultiIndex.from_product( [["a", "b", "c", "d"], [1, 2, 3, 4, 5, 6, 7, 8]], @@ -396,15 +392,6 @@ def test_constructor_from_self_described(self): actual = DataArray(series) assert_equal(expected[0].reset_coords("x", drop=True), actual) - if LooseVersion(pd.__version__) < "0.25.0": - 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], "a": 0, "z": ("x", [-0.5, 0.5])}, @@ -6615,7 +6602,7 @@ def test_from_dask(self): np.testing.assert_equal(da.to_numpy(), np.array([1, 2, 3])) np.testing.assert_equal(da["lat"].to_numpy(), np.array([4, 5, 6])) - @requires_pint_0_15 + @requires_pint def test_from_pint(self): from pint import Quantity @@ -6661,7 +6648,7 @@ def test_from_cupy(self): np.testing.assert_equal(da.to_numpy(), arr) @requires_dask - @requires_pint_0_15 + @requires_pint def test_from_pint_wrapping_dask(self): import dask from pint import Quantity diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 61b404275bf..cdb8382c8ee 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -47,7 +47,7 @@ requires_dask, requires_numbagg, requires_numexpr, - requires_pint_0_15, + requires_pint, requires_scipy, requires_sparse, source_ndarray, @@ -6495,7 +6495,7 @@ def test_from_dask(self): assert_identical(ds_chunked.as_numpy(), ds.compute()) - @requires_pint_0_15 + @requires_pint def test_from_pint(self): from pint import Quantity @@ -6536,7 +6536,7 @@ def test_from_cupy(self): assert_identical(ds.as_numpy(), expected) @requires_dask - @requires_pint_0_15 + @requires_pint def test_from_pint_wrapping_dask(self): import dask from pint import Quantity diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 3260b92bd71..774f90dbb04 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -29,7 +29,6 @@ requires_cartopy, requires_cftime, requires_matplotlib, - requires_matplotlib_3_3_0, requires_nc_time_axis, requires_seaborn, ) @@ -1988,19 +1987,15 @@ def test_convenient_facetgrid(self): assert "y" == ax.get_ylabel() assert "x" == ax.get_xlabel() - @requires_matplotlib_3_3_0 def test_viridis_cmap(self): return super().test_viridis_cmap() - @requires_matplotlib_3_3_0 def test_can_change_default_cmap(self): return super().test_can_change_default_cmap() - @requires_matplotlib_3_3_0 def test_colorbar_default_label(self): return super().test_colorbar_default_label() - @requires_matplotlib_3_3_0 def test_facetgrid_map_only_appends_mappables(self): return super().test_facetgrid_map_only_appends_mappables() diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index 7f3ba9123d9..9c0e45c5da9 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -35,7 +35,7 @@ raise_if_dask_computes, requires_cupy, requires_dask, - requires_pint_0_15, + requires_pint, requires_sparse, source_ndarray, ) @@ -2597,7 +2597,7 @@ def test_from_dask(self, Var): assert_identical(v_chunked.as_numpy(), v.compute()) np.testing.assert_equal(v.to_numpy(), np.array([1, 2, 3])) - @requires_pint_0_15 + @requires_pint def test_from_pint(self, Var): from pint import Quantity @@ -2632,7 +2632,7 @@ def test_from_cupy(self, Var): np.testing.assert_equal(v.to_numpy(), arr) @requires_dask - @requires_pint_0_15 + @requires_pint def test_from_pint_wrapping_dask(self, Var): import dask from pint import Quantity