Skip to content

Commit 0eeb8cb

Browse files
authored
CLN: VariableOffsetWindowIndexer (#54379)
* CLN: VariableOffsetWindowIndexer * Add gh number
1 parent 5d27560 commit 0eeb8cb

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

doc/source/whatsnew/v2.1.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ Other enhancements
209209
- Improve error message when setting :class:`DataFrame` with wrong number of columns through :meth:`DataFrame.isetitem` (:issue:`51701`)
210210
- Improved error handling when using :meth:`DataFrame.to_json` with incompatible ``index`` and ``orient`` arguments (:issue:`52143`)
211211
- Improved error message when creating a DataFrame with empty data (0 rows), no index and an incorrect number of columns. (:issue:`52084`)
212+
- Improved error message when providing an invalid ``index`` or ``offset`` argument to :class:`pandas.api.indexers.VariableOffsetWindowIndexer` (:issue:`54379`)
212213
- Let :meth:`DataFrame.to_feather` accept a non-default :class:`Index` and non-string column names (:issue:`51787`)
213214
- Added a new parameter ``by_row`` to :meth:`Series.apply` and :meth:`DataFrame.apply`. When set to ``False`` the supplied callables will always operate on the whole Series or DataFrame (:issue:`53400`, :issue:`53601`).
214215
- :meth:`DataFrame.shift` and :meth:`Series.shift` now allow shifting by multiple periods by supplying a list of periods (:issue:`44424`)

pandas/core/indexers/objects.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55

66
import numpy as np
77

8+
from pandas._libs.tslibs import BaseOffset
89
from pandas._libs.window.indexers import calculate_variable_window_bounds
910
from pandas.util._decorators import Appender
1011

1112
from pandas.core.dtypes.common import ensure_platform_int
1213

14+
from pandas.core.indexes.datetimes import DatetimeIndex
15+
1316
from pandas.tseries.offsets import Nano
1417

1518
get_window_bounds_doc = """
@@ -183,12 +186,16 @@ def __init__(
183186
self,
184187
index_array: np.ndarray | None = None,
185188
window_size: int = 0,
186-
index=None,
187-
offset=None,
189+
index: DatetimeIndex | None = None,
190+
offset: BaseOffset | None = None,
188191
**kwargs,
189192
) -> None:
190193
super().__init__(index_array, window_size, **kwargs)
194+
if not isinstance(index, DatetimeIndex):
195+
raise ValueError("index must be a DatetimeIndex.")
191196
self.index = index
197+
if not isinstance(offset, BaseOffset):
198+
raise ValueError("offset must be a DateOffset-like object.")
192199
self.offset = offset
193200

194201
@Appender(get_window_bounds_doc)
@@ -216,6 +223,7 @@ def get_window_bounds(
216223
index_growth_sign = -1
217224
else:
218225
index_growth_sign = 1
226+
offset_diff = index_growth_sign * self.offset
219227

220228
start = np.empty(num_values, dtype="int64")
221229
start.fill(-1)
@@ -231,11 +239,12 @@ def get_window_bounds(
231239
else:
232240
end[0] = 0
233241

242+
zero = timedelta(0)
234243
# start is start of slice interval (including)
235244
# end is end of slice interval (not including)
236245
for i in range(1, num_values):
237246
end_bound = self.index[i]
238-
start_bound = self.index[i] - index_growth_sign * self.offset
247+
start_bound = end_bound - offset_diff
239248

240249
# left endpoint is closed
241250
if left_closed:
@@ -245,13 +254,15 @@ def get_window_bounds(
245254
# within the constraint
246255
start[i] = i
247256
for j in range(start[i - 1], i):
248-
if (self.index[j] - start_bound) * index_growth_sign > timedelta(0):
257+
start_diff = (self.index[j] - start_bound) * index_growth_sign
258+
if start_diff > zero:
249259
start[i] = j
250260
break
251261

252262
# end bound is previous end
253263
# or current index
254-
if (self.index[end[i - 1]] - end_bound) * index_growth_sign <= timedelta(0):
264+
end_diff = (self.index[end[i - 1]] - end_bound) * index_growth_sign
265+
if end_diff <= zero:
255266
end[i] = i + 1
256267
else:
257268
end[i] = end[i - 1]

pandas/tests/window/test_base_indexer.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,19 @@ def test_non_fixed_variable_window_indexer(closed, expected_data):
268268
tm.assert_frame_equal(result, expected)
269269

270270

271+
def test_variableoffsetwindowindexer_not_dti():
272+
# GH 54379
273+
with pytest.raises(ValueError, match="index must be a DatetimeIndex."):
274+
VariableOffsetWindowIndexer(index="foo", offset=BusinessDay(1))
275+
276+
277+
def test_variableoffsetwindowindexer_not_offset():
278+
# GH 54379
279+
idx = date_range("2020", periods=10)
280+
with pytest.raises(ValueError, match="offset must be a DateOffset-like object."):
281+
VariableOffsetWindowIndexer(index=idx, offset="foo")
282+
283+
271284
def test_fixed_forward_indexer_count(step):
272285
# GH: 35579
273286
df = DataFrame({"b": [None, None, None, 7]})

0 commit comments

Comments
 (0)