pydata / pydata/xarray

cftime_range fails for base cftime.datetime object

Open
#4,336 11 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

topic-cftime topic-documentation topic-error reporting
Dominant language
Python
Stars
4.2k
Forks
1.4k
Avg merge
2d 15h
Merged PRs (30d)
14

Description

What happened:

xarray.cftime_range does not accept dates that use base classcftime.datetime objects.

What you expected to happen:

I expected xarray.cftime_range to raise an exception that this is an unsupported cftime.datetime type and for the documentation to reflect this.

Minimal Complete Verifiable Example:

import cftime
import xarray
date = cftime.datetime(10,1,1)
xarray.cftime_range(date, periods=3, freq='Y')

Anything else we need to know?:

Returns this error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-29-d090ea15e436> in <module>
      2 import xarray
      3 date = cftime.datetime(10,1,1)
----> 4 xarray.cftime_range(date, periods=3, freq='Y')

/g/data3/hh5/public/apps/miniconda3/envs/analysis3-20.07/lib/python3.7/site-packages/xarray/coding/cftime_offsets.py in cftime_range(start, end, periods, freq, normalize, name, closed, calendar)
    973     else:
    974         offset = to_offset(freq)
--> 975         dates = np.array(list(_generate_range(start, end, periods, offset)))
    976 
    977     left_closed = False

/g/data3/hh5/public/apps/miniconda3/envs/analysis3-20.07/lib/python3.7/site-packages/xarray/coding/cftime_offsets.py in _generate_range(start, end, periods, offset)
    744     """
    745     if start:
--> 746         start = offset.rollforward(start)
    747 
    748     if end:

/g/data3/hh5/public/apps/miniconda3/envs/analysis3-20.07/lib/python3.7/site-packages/xarray/coding/cftime_offsets.py in rollforward(self, date)
    526     def rollforward(self, date):
    527         """Roll date forward to nearest end of year"""
--> 528         if self.onOffset(date):
    529             return date
    530         else:

/g/data3/hh5/public/apps/miniconda3/envs/analysis3-20.07/lib/python3.7/site-packages/xarray/coding/cftime_offsets.py in onOffset(self, date)
    522         """Check if the given date is in the set of possible dates created
    523         using a length-one version of this offset class."""
--> 524         return date.day == _days_in_month(date) and date.month == self.month
    525 
    526     def rollforward(self, date):

/g/data3/hh5/public/apps/miniconda3/envs/analysis3-20.07/lib/python3.7/site-packages/xarray/coding/cftime_offsets.py in _days_in_month(date)
    195     else:
    196         reference = type(date)(date.year, date.month + 1, 1)
--> 197     return (reference - timedelta(days=1)).day
    198 
    199 

TypeError: unsupported operand type(s) for -: 'cftime._cftime.datetime' and 'datetime.timedelta'

Works if a datetime object with a calendar is used:

import cftime
import xarray
date = cftime.DatetimeGregorian(10,1,1)
xarray.cftime_range(date, periods=3, freq='Y')

Returns:

CFTimeIndex([0010-12-31 00:00:00, 0011-12-31 00:00:00, 0012-12-31 00:00:00], dtype='object')

as expected.

The error occurs here

https://github.com/pydata/xarray/blob/master/xarray/coding/cftime_offsets.py#L197

because this operation is not defined for the base class

https://github.com/Unidata/cftime/blob/master/cftime/_cftime.pyx#L1054

The relevant tests all seem to use datetime strings which are by default standard calendar:

https://github.com/pydata/xarray/blob/master/xarray/coding/cftime_offsets.py#L788

Environment:

Output of xr.show_versions()

INSTALLED VERSIONS

commit: None
python: 3.7.8 | packaged by conda-forge | (default, Jul 31 2020, 02:25:08)
[GCC 7.5.0]
python-bits: 64
OS: Linux
OS-release: 2.6.32-754.18.2.el6.x86_64
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: en_AU.utf8
LANG: en_AU.UTF-8
LOCALE: en_AU.UTF-8
libhdf5: 1.10.5
libnetcdf: 4.7.4

xarray: 0.16.0
pandas: 1.1.0
numpy: 1.19.1
scipy: 1.5.2
netCDF4: 1.5.3
pydap: installed
h5netcdf: 0.8.1
h5py: 2.10.0
Nio: 1.5.5
zarr: 2.4.0
cftime: 1.0.3.4
nc_time_axis: 1.2.0
PseudoNetCDF: None
rasterio: 1.1.5
cfgrib: 0.9.8.4
iris: 2.4.0
bottleneck: 1.3.2
dask: 2.22.0
distributed: 2.22.0
matplotlib: 3.3.0
cartopy: 0.18.0
seaborn: 0.10.1
numbagg: None
pint: 0.14
setuptools: 49.2.0.post20200712
pip: 20.1.1
conda: installed
pytest: 6.0.1
IPython: 7.17.0
sphinx: 3.2.0

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with xarray/coding/cftime_offsets.py around _days_in_month at line 197 and reproduce the cftime.datetime example from the issue. Review the related tests around line 788, then ensure the unsupported base cftime.datetime case has the documented exception behavior and corresponding documentation coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.