6
6
import numpy as np
7
7
import pandas as pd
8
8
import pytest
9
- from packaging .version import Version
10
9
11
10
import xarray as xr
12
- from xarray .coding .cftime_offsets import _new_to_legacy_freq
11
+ from xarray .coding .cftime_offsets import (
12
+ CFTIME_TICKS ,
13
+ Day ,
14
+ _new_to_legacy_freq ,
15
+ to_offset ,
16
+ )
13
17
from xarray .coding .cftimeindex import CFTimeIndex
14
18
from xarray .core .resample_cftime import CFTimeGrouper
19
+ from xarray .tests import has_pandas_3
15
20
16
21
cftime = pytest .importorskip ("cftime" )
17
22
54
59
]
55
60
56
61
62
+ def has_tick_resample_freq (freqs ):
63
+ resample_freq , _ = freqs
64
+ resample_freq_as_offset = to_offset (resample_freq )
65
+ return isinstance (resample_freq_as_offset , CFTIME_TICKS )
66
+
67
+
68
+ def has_non_tick_resample_freq (freqs ):
69
+ return not has_tick_resample_freq (freqs )
70
+
71
+
72
+ FREQS_WITH_TICK_RESAMPLE_FREQ = list (filter (has_tick_resample_freq , FREQS ))
73
+ FREQS_WITH_NON_TICK_RESAMPLE_FREQ = list (filter (has_non_tick_resample_freq , FREQS ))
74
+
75
+
57
76
def compare_against_pandas (
58
77
da_datetimeindex ,
59
78
da_cftimeindex ,
@@ -110,22 +129,14 @@ def da(index) -> xr.DataArray:
110
129
)
111
130
112
131
113
- @pytest .mark .parametrize ("freqs" , FREQS , ids = lambda x : "{}->{}" .format (* x ))
132
+ @pytest .mark .parametrize (
133
+ "freqs" , FREQS_WITH_TICK_RESAMPLE_FREQ , ids = lambda x : "{}->{}" .format (* x )
134
+ )
114
135
@pytest .mark .parametrize ("closed" , [None , "left" , "right" ])
115
136
@pytest .mark .parametrize ("label" , [None , "left" , "right" ])
116
137
@pytest .mark .parametrize ("offset" , [None , "5s" ], ids = lambda x : f"{ x } " )
117
- def test_resample (freqs , closed , label , offset ) -> None :
138
+ def test_resample_with_tick_resample_freq (freqs , closed , label , offset ) -> None :
118
139
initial_freq , resample_freq = freqs
119
- if (
120
- resample_freq == "4001D"
121
- and closed == "right"
122
- and Version (pd .__version__ ) < Version ("2.2" )
123
- ):
124
- pytest .skip (
125
- "Pandas fixed a bug in this test case in version 2.2, which we "
126
- "ported to xarray, so this test no longer produces the same "
127
- "result as pandas for earlier pandas versions."
128
- )
129
140
start = "2000-01-01T12:07:01"
130
141
origin = "start"
131
142
@@ -149,6 +160,43 @@ def test_resample(freqs, closed, label, offset) -> None:
149
160
)
150
161
151
162
163
+ @pytest .mark .parametrize (
164
+ "freqs" , FREQS_WITH_NON_TICK_RESAMPLE_FREQ , ids = lambda x : "{}->{}" .format (* x )
165
+ )
166
+ @pytest .mark .parametrize ("closed" , [None , "left" , "right" ])
167
+ @pytest .mark .parametrize ("label" , [None , "left" , "right" ])
168
+ def test_resample_with_non_tick_resample_freq (freqs , closed , label ) -> None :
169
+ initial_freq , resample_freq = freqs
170
+ resample_freq_as_offset = to_offset (resample_freq )
171
+ if isinstance (resample_freq_as_offset , Day ) and not has_pandas_3 :
172
+ pytest .skip ("Only valid for pandas >= 3.0" )
173
+ start = "2000-01-01T12:07:01"
174
+
175
+ # Set offset and origin to their default values since they have no effect
176
+ # on resampling data with a non-tick resample frequency.
177
+ offset = None
178
+ origin = "start_day"
179
+
180
+ datetime_index = pd .date_range (
181
+ start = start , periods = 5 , freq = _new_to_legacy_freq (initial_freq )
182
+ )
183
+ cftime_index = xr .date_range (
184
+ start = start , periods = 5 , freq = initial_freq , use_cftime = True
185
+ )
186
+ da_datetimeindex = da (datetime_index )
187
+ da_cftimeindex = da (cftime_index )
188
+
189
+ compare_against_pandas (
190
+ da_datetimeindex ,
191
+ da_cftimeindex ,
192
+ resample_freq ,
193
+ closed = closed ,
194
+ label = label ,
195
+ offset = offset ,
196
+ origin = origin ,
197
+ )
198
+
199
+
152
200
@pytest .mark .parametrize (
153
201
("freq" , "expected" ),
154
202
[
@@ -225,19 +273,28 @@ def test_origin(closed, origin) -> None:
225
273
226
274
@pytest .mark .parametrize ("offset" , ["foo" , "5MS" , 10 ])
227
275
def test_invalid_offset_error (offset : str | int ) -> None :
228
- cftime_index = xr .date_range ("2000" , periods = 5 , use_cftime = True )
276
+ cftime_index = xr .date_range ("2000" , periods = 5 , freq = "h" , use_cftime = True )
229
277
da_cftime = da (cftime_index )
230
278
with pytest .raises (ValueError , match = "offset must be" ):
231
- da_cftime .resample (time = "2D " , offset = offset ) # type: ignore[arg-type]
279
+ da_cftime .resample (time = "2h " , offset = offset ) # type: ignore[arg-type]
232
280
233
281
234
282
def test_timedelta_offset () -> None :
235
283
timedelta = datetime .timedelta (seconds = 5 )
236
284
string = "5s"
237
285
238
- cftime_index = xr .date_range ("2000" , periods = 5 , use_cftime = True )
286
+ cftime_index = xr .date_range ("2000" , periods = 5 , freq = "h" , use_cftime = True )
239
287
da_cftime = da (cftime_index )
240
288
241
- timedelta_result = da_cftime .resample (time = "2D " , offset = timedelta ).mean ()
242
- string_result = da_cftime .resample (time = "2D " , offset = string ).mean ()
289
+ timedelta_result = da_cftime .resample (time = "2h " , offset = timedelta ).mean ()
290
+ string_result = da_cftime .resample (time = "2h " , offset = string ).mean ()
243
291
xr .testing .assert_identical (timedelta_result , string_result )
292
+
293
+
294
+ @pytest .mark .parametrize (("option" , "value" ), [("offset" , "5s" ), ("origin" , "start" )])
295
+ def test_non_tick_option_warning (option , value ) -> None :
296
+ cftime_index = xr .date_range ("2000" , periods = 5 , use_cftime = True )
297
+ da_cftime = da (cftime_index )
298
+ kwargs = {option : value }
299
+ with pytest .warns (RuntimeWarning , match = option ):
300
+ da_cftime .resample (time = "ME" , ** kwargs )
0 commit comments