Skip to content

Commit 16b15db

Browse files
authored
add freq as CFTimeIndex property and to CFTimeIndex.__repr__ (#4597)
* add freq as property and to repr * lint * Update test_cftimeindex.py * Update test_cftimeindex.py * require cftime110 * Only show freq if more than two items * Update test_cftimeindex.py * Update cftime_offsets.py * Require cftime110 for all repr tests * Update test_cftimeindex.py * Update xarray/tests/test_cftimeindex.py * Update test_cftimeindex.py * Update xarray/tests/test_cftimeindex.py * final lint * freq in repr always and add to hidden-api * fix doctests by adding freq=None * rerun CI after timeout * api-hidden * rerun CI
1 parent bad150f commit 16b15db

File tree

5 files changed

+35
-13
lines changed

5 files changed

+35
-13
lines changed

doc/api-hidden.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@
689689
CFTimeIndex.dayofyear
690690
CFTimeIndex.dtype
691691
CFTimeIndex.empty
692+
CFTimeIndex.freq
692693
CFTimeIndex.has_duplicates
693694
CFTimeIndex.hasnans
694695
CFTimeIndex.hour

doc/whats-new.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ New Features
5555
By `Julius Busecke <https://github.com/jbusecke>`_.
5656
- Added the ``keep_attrs`` keyword to ``rolling_exp.mean()``; it now keeps attributes
5757
per default. By `Mathias Hauser <https://github.com/mathause>`_ (:pull:`4592`).
58+
- Added ``freq`` as property to :py:class:`CFTimeIndex` and into the
59+
``CFTimeIndex.repr``. (:issue:`2416`, :pull:`4597`)
60+
By `Aaron Spring <https://github.com/aaronspring>`_.
5861

5962
Bug fixes
6063
~~~~~~~~~

xarray/coding/cftime_offsets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ def cftime_range(
939939
>>> xr.cftime_range(start="2000", periods=6, freq="2MS", calendar="noleap")
940940
CFTimeIndex([2000-01-01 00:00:00, 2000-03-01 00:00:00, 2000-05-01 00:00:00,
941941
2000-07-01 00:00:00, 2000-09-01 00:00:00, 2000-11-01 00:00:00],
942-
dtype='object', length=6, calendar='noleap')
942+
dtype='object', length=6, calendar='noleap', freq='2MS')
943943
944944
As in the standard pandas function, three of the ``start``, ``end``,
945945
``periods``, or ``freq`` arguments must be specified at a given time, with

xarray/coding/cftimeindex.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ def format_attrs(index, separator=", "):
261261
"length": f"{len(index)}",
262262
"calendar": f"'{index.calendar}'",
263263
}
264+
attrs["freq"] = f"'{index.freq}'" if len(index) >= 3 else None
264265
attrs_str = [f"{k}={v}" for k, v in attrs.items()]
265266
attrs_str = f"{separator}".join(attrs_str)
266267
return attrs_str
@@ -524,10 +525,10 @@ def shift(self, n, freq):
524525
>>> index = xr.cftime_range("2000", periods=1, freq="M")
525526
>>> index
526527
CFTimeIndex([2000-01-31 00:00:00],
527-
dtype='object', length=1, calendar='gregorian')
528+
dtype='object', length=1, calendar='gregorian', freq=None)
528529
>>> index.shift(1, "M")
529530
CFTimeIndex([2000-02-29 00:00:00],
530-
dtype='object', length=1, calendar='gregorian')
531+
dtype='object', length=1, calendar='gregorian', freq=None)
531532
"""
532533
from .cftime_offsets import to_offset
533534

@@ -614,7 +615,7 @@ def to_datetimeindex(self, unsafe=False):
614615
>>> times = xr.cftime_range("2000", periods=2, calendar="gregorian")
615616
>>> times
616617
CFTimeIndex([2000-01-01 00:00:00, 2000-01-02 00:00:00],
617-
dtype='object', length=2, calendar='gregorian')
618+
dtype='object', length=2, calendar='gregorian', freq=None)
618619
>>> times.to_datetimeindex()
619620
DatetimeIndex(['2000-01-01', '2000-01-02'], dtype='datetime64[ns]', freq=None)
620621
"""
@@ -683,6 +684,13 @@ def calendar(self):
683684

684685
return infer_calendar_name(self)
685686

687+
@property
688+
def freq(self):
689+
"""The frequency used by the dates in the index."""
690+
from .frequencies import infer_freq
691+
692+
return infer_freq(self)
693+
686694
def _round_via_method(self, freq, method):
687695
"""Round dates using a specified method."""
688696
from .cftime_offsets import CFTIME_TICKS, to_offset

xarray/tests/test_cftimeindex.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,7 @@ def test_cftimeindex_calendar_property(calendar, expected):
916916
assert index.calendar == expected
917917

918918

919-
@requires_cftime
919+
@requires_cftime_1_1_0
920920
@pytest.mark.parametrize(
921921
("calendar", "expected"),
922922
[
@@ -936,7 +936,7 @@ def test_cftimeindex_calendar_repr(calendar, expected):
936936
assert "2000-01-01 00:00:00, 2000-01-02 00:00:00" in repr_str
937937

938938

939-
@requires_cftime
939+
@requires_cftime_1_1_0
940940
@pytest.mark.parametrize("periods", [2, 40])
941941
def test_cftimeindex_periods_repr(periods):
942942
"""Test that cftimeindex has periods property in repr."""
@@ -945,22 +945,32 @@ def test_cftimeindex_periods_repr(periods):
945945
assert f" length={periods}" in repr_str
946946

947947

948-
@requires_cftime
948+
@requires_cftime_1_1_0
949+
@pytest.mark.parametrize("calendar", ["noleap", "360_day", "standard"])
950+
@pytest.mark.parametrize("freq", ["D", "H"])
951+
def test_cftimeindex_freq_in_repr(freq, calendar):
952+
"""Test that cftimeindex has frequency property in repr."""
953+
index = xr.cftime_range(start="2000", periods=3, freq=freq, calendar=calendar)
954+
repr_str = index.__repr__()
955+
assert f", freq='{freq}'" in repr_str
956+
957+
958+
@requires_cftime_1_1_0
949959
@pytest.mark.parametrize(
950960
"periods,expected",
951961
[
952962
(
953963
2,
954964
"""\
955965
CFTimeIndex([2000-01-01 00:00:00, 2000-01-02 00:00:00],
956-
dtype='object', length=2, calendar='gregorian')""",
966+
dtype='object', length=2, calendar='gregorian', freq=None)""",
957967
),
958968
(
959969
4,
960970
"""\
961971
CFTimeIndex([2000-01-01 00:00:00, 2000-01-02 00:00:00, 2000-01-03 00:00:00,
962972
2000-01-04 00:00:00],
963-
dtype='object', length=4, calendar='gregorian')""",
973+
dtype='object', length=4, calendar='gregorian', freq='D')""",
964974
),
965975
(
966976
101,
@@ -974,18 +984,18 @@ def test_cftimeindex_periods_repr(periods):
974984
2000-04-04 00:00:00, 2000-04-05 00:00:00, 2000-04-06 00:00:00,
975985
2000-04-07 00:00:00, 2000-04-08 00:00:00, 2000-04-09 00:00:00,
976986
2000-04-10 00:00:00],
977-
dtype='object', length=101, calendar='gregorian')""",
987+
dtype='object', length=101, calendar='gregorian', freq='D')""",
978988
),
979989
],
980990
)
981991
def test_cftimeindex_repr_formatting(periods, expected):
982992
"""Test that cftimeindex.__repr__ is formatted similar to pd.Index.__repr__."""
983-
index = xr.cftime_range(start="2000", periods=periods)
993+
index = xr.cftime_range(start="2000", periods=periods, freq="D")
984994
expected = dedent(expected)
985995
assert expected == repr(index)
986996

987997

988-
@requires_cftime
998+
@requires_cftime_1_1_0
989999
@pytest.mark.parametrize("display_width", [40, 80, 100])
9901000
@pytest.mark.parametrize("periods", [2, 3, 4, 100, 101])
9911001
def test_cftimeindex_repr_formatting_width(periods, display_width):
@@ -1003,7 +1013,7 @@ def test_cftimeindex_repr_formatting_width(periods, display_width):
10031013
assert s[:len_intro_str] == " " * len_intro_str
10041014

10051015

1006-
@requires_cftime
1016+
@requires_cftime_1_1_0
10071017
@pytest.mark.parametrize("periods", [22, 50, 100])
10081018
def test_cftimeindex_repr_101_shorter(periods):
10091019
index_101 = xr.cftime_range(start="2000", periods=101)

0 commit comments

Comments
 (0)