Skip to content

Commit

Permalink
Remove outdated code related to compatibility with netcdftime (#3450)
Browse files Browse the repository at this point in the history
* Remove code leftover from the netcdftime -> cftime transition

* Add a what's new note

* black formatting

* Add more detail to what's new note

* More minor edits to what's new note
  • Loading branch information
spencerkclark authored and dcherian committed Oct 29, 2019
1 parent 74ca69a commit cb5eef1
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 199 deletions.
5 changes: 5 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ Breaking changes
~~~~~~~~~~~~~~~~

- Minimum cftime version is now 1.0.3. By `Deepak Cherian <https://github.com/dcherian>`_.
- All leftover support for dates from non-standard calendars through netcdftime, the
module included in versions of netCDF4 prior to 1.4 that eventually became the
cftime package, has been removed in favor of relying solely on the standalone
cftime package (:pull:`3450`). By `Spencer Clark
<https://github.com/spencerkclark>`_.

New Features
~~~~~~~~~~~~
Expand Down
43 changes: 5 additions & 38 deletions xarray/coding/times.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,34 +39,6 @@
)


def _import_cftime():
"""
helper function handle the transition to netcdftime/cftime
as a stand-alone package
"""
try:
import cftime
except ImportError:
# in netCDF4 the num2date/date2num function are top-level api
try:
import netCDF4 as cftime
except ImportError:
raise ImportError("Failed to import cftime")
return cftime


def _require_standalone_cftime():
"""Raises an ImportError if the standalone cftime is not found"""
try:
import cftime # noqa: F401
except ImportError:
raise ImportError(
"Decoding times with non-standard calendars "
"or outside the pandas.Timestamp-valid range "
"requires the standalone cftime package."
)


def _netcdf_to_numpy_timeunit(units):
units = units.lower()
if not units.endswith("s"):
Expand Down Expand Up @@ -119,16 +91,11 @@ def _decode_cf_datetime_dtype(data, units, calendar, use_cftime):


def _decode_datetime_with_cftime(num_dates, units, calendar):
cftime = _import_cftime()
import cftime

if cftime.__name__ == "cftime":
return np.asarray(
cftime.num2date(num_dates, units, calendar, only_use_cftime_datetimes=True)
)
else:
# Must be using num2date from an old version of netCDF4 which
# does not have the only_use_cftime_datetimes option.
return np.asarray(cftime.num2date(num_dates, units, calendar))
return np.asarray(
cftime.num2date(num_dates, units, calendar, only_use_cftime_datetimes=True)
)


def _decode_datetime_with_pandas(flat_num_dates, units, calendar):
Expand Down Expand Up @@ -354,7 +321,7 @@ def _encode_datetime_with_cftime(dates, units, calendar):
This method is more flexible than xarray's parsing using datetime64[ns]
arrays but also slower because it loops over each element.
"""
cftime = _import_cftime()
import cftime

if np.issubdtype(dates.dtype, np.datetime64):
# numpy's broken datetime conversion only works for us precision
Expand Down
4 changes: 0 additions & 4 deletions xarray/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,6 @@ def LooseVersion(vstring):
requires_scipy_or_netCDF4 = pytest.mark.skipif(
not has_scipy_or_netCDF4, reason="requires scipy or netCDF4"
)
has_cftime_or_netCDF4 = has_cftime or has_netCDF4
requires_cftime_or_netCDF4 = pytest.mark.skipif(
not has_cftime_or_netCDF4, reason="requires cftime or netCDF4"
)
try:
import_seaborn()
has_seaborn = True
Expand Down
30 changes: 8 additions & 22 deletions xarray/tests/test_accessor_dt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
from . import (
assert_array_equal,
assert_equal,
has_cftime,
has_cftime_or_netCDF4,
has_dask,
raises_regex,
requires_cftime,
requires_dask,
)

Expand Down Expand Up @@ -199,7 +197,7 @@ def times_3d(times):
)


@pytest.mark.skipif(not has_cftime, reason="cftime not installed")
@requires_cftime
@pytest.mark.parametrize(
"field", ["year", "month", "day", "hour", "dayofyear", "dayofweek"]
)
Expand All @@ -217,7 +215,7 @@ def test_field_access(data, field):
assert_equal(result, expected)


@pytest.mark.skipif(not has_cftime, reason="cftime not installed")
@requires_cftime
def test_cftime_strftime_access(data):
""" compare cftime formatting against datetime formatting """
date_format = "%Y%m%d%H"
Expand All @@ -232,8 +230,8 @@ def test_cftime_strftime_access(data):
assert_equal(result, expected)


@pytest.mark.skipif(not has_dask, reason="dask not installed")
@pytest.mark.skipif(not has_cftime, reason="cftime not installed")
@requires_cftime
@requires_dask
@pytest.mark.parametrize(
"field", ["year", "month", "day", "hour", "dayofyear", "dayofweek"]
)
Expand All @@ -254,8 +252,8 @@ def test_dask_field_access_1d(data, field):
assert_equal(result.compute(), expected)


@pytest.mark.skipif(not has_dask, reason="dask not installed")
@pytest.mark.skipif(not has_cftime, reason="cftime not installed")
@requires_cftime
@requires_dask
@pytest.mark.parametrize(
"field", ["year", "month", "day", "hour", "dayofyear", "dayofweek"]
)
Expand Down Expand Up @@ -286,7 +284,7 @@ def cftime_date_type(calendar):
return _all_cftime_date_types()[calendar]


@pytest.mark.skipif(not has_cftime, reason="cftime not installed")
@requires_cftime
def test_seasons(cftime_date_type):
dates = np.array([cftime_date_type(2000, month, 15) for month in range(1, 13)])
dates = xr.DataArray(dates)
Expand All @@ -307,15 +305,3 @@ def test_seasons(cftime_date_type):
seasons = xr.DataArray(seasons)

assert_array_equal(seasons.values, dates.dt.season.values)


@pytest.mark.skipif(not has_cftime_or_netCDF4, reason="cftime or netCDF4 not installed")
def test_dt_accessor_error_netCDF4(cftime_date_type):
da = xr.DataArray(
[cftime_date_type(1, 1, 1), cftime_date_type(2, 1, 1)], dims=["time"]
)
if not has_cftime:
with pytest.raises(TypeError):
da.dt.month
else:
da.dt.month
10 changes: 3 additions & 7 deletions xarray/tests/test_cftimeindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)
from xarray.tests import assert_array_equal, assert_identical

from . import has_cftime, has_cftime_or_netCDF4, raises_regex, requires_cftime
from . import raises_regex, requires_cftime
from .test_coding_times import (
_ALL_CALENDARS,
_NON_STANDARD_CALENDARS,
Expand Down Expand Up @@ -653,7 +653,7 @@ def test_indexing_in_dataframe_iloc(df, index):
assert result.equals(expected)


@pytest.mark.skipif(not has_cftime_or_netCDF4, reason="cftime not installed")
@requires_cftime
def test_concat_cftimeindex(date_type):
da1 = xr.DataArray(
[1.0, 2.0], coords=[[date_type(1, 1, 1), date_type(1, 2, 1)]], dims=["time"]
Expand All @@ -663,11 +663,7 @@ def test_concat_cftimeindex(date_type):
)
da = xr.concat([da1, da2], dim="time")

if has_cftime:
assert isinstance(da.indexes["time"], CFTimeIndex)
else:
assert isinstance(da.indexes["time"], pd.Index)
assert not isinstance(da.indexes["time"], CFTimeIndex)
assert isinstance(da.indexes["time"], CFTimeIndex)


@requires_cftime
Expand Down
Loading

0 comments on commit cb5eef1

Please sign in to comment.