Skip to content

Commit bfecc48

Browse files
authored
REF: simplify wrapping in apply_index (#34555)
* REF: return ndarray from apply_index * Remove unnecessary to_perioddelta, _timestamp
1 parent 88db451 commit bfecc48

File tree

4 files changed

+16
-24
lines changed

4 files changed

+16
-24
lines changed

pandas/_libs/tslibs/offsets.pyx

+9-17
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ from pandas._libs.tslibs.ccalendar cimport DAY_NANOS, get_days_in_month, dayofwe
4040
from pandas._libs.tslibs.conversion cimport (
4141
convert_datetime_to_tsobject,
4242
localize_pydatetime,
43+
normalize_i8_timestamps,
4344
)
4445
from pandas._libs.tslibs.nattype cimport NPY_NAT, c_NaT as NaT
4546
from pandas._libs.tslibs.np_datetime cimport (
@@ -79,21 +80,14 @@ cdef bint _is_normalized(datetime dt):
7980
def apply_index_wraps(func):
8081
# Note: normally we would use `@functools.wraps(func)`, but this does
8182
# not play nicely with cython class methods
82-
def wrapper(self, other):
83-
84-
is_index = not util.is_array(other._data)
85-
86-
# operate on DatetimeArray
87-
arr = other._data if is_index else other
88-
89-
result = func(self, arr)
83+
def wrapper(self, other) -> np.ndarray:
84+
# other is a DatetimeArray
9085

91-
if is_index:
92-
# Wrap DatetimeArray result back to DatetimeIndex
93-
result = type(other)._simple_new(result, name=other.name)
86+
result = func(self, other)
87+
result = np.asarray(result)
9488

9589
if self.normalize:
96-
result = result.to_period('D').to_timestamp()
90+
result = normalize_i8_timestamps(result.view("i8"), None)
9791
return result
9892

9993
# do @functools.wraps(func) manually since it doesn't work on cdef funcs
@@ -1889,7 +1883,7 @@ cdef class YearOffset(SingleConstructorOffset):
18891883
shifted = shift_quarters(
18901884
dtindex.asi8, self.n, self.month, self._day_opt, modby=12
18911885
)
1892-
return type(dtindex)._simple_new(shifted, dtype=dtindex.dtype)
1886+
return shifted
18931887

18941888

18951889
cdef class BYearEnd(YearOffset):
@@ -2033,7 +2027,7 @@ cdef class QuarterOffset(SingleConstructorOffset):
20332027
shifted = shift_quarters(
20342028
dtindex.asi8, self.n, self.startingMonth, self._day_opt
20352029
)
2036-
return type(dtindex)._simple_new(shifted, dtype=dtindex.dtype)
2030+
return shifted
20372031

20382032

20392033
cdef class BQuarterEnd(QuarterOffset):
@@ -2139,7 +2133,7 @@ cdef class MonthOffset(SingleConstructorOffset):
21392133
@apply_index_wraps
21402134
def apply_index(self, dtindex):
21412135
shifted = shift_months(dtindex.asi8, self.n, self._day_opt)
2142-
return type(dtindex)._simple_new(shifted, dtype=dtindex.dtype)
2136+
return shifted
21432137

21442138
cpdef __setstate__(self, state):
21452139
state.pop("_use_relativedelta", False)
@@ -2503,8 +2497,6 @@ cdef class Week(SingleConstructorOffset):
25032497
@apply_index_wraps
25042498
def apply_index(self, dtindex):
25052499
if self.weekday is None:
2506-
# integer addition on PeriodIndex is deprecated,
2507-
# so we use _time_shift directly
25082500
td = timedelta(days=7 * self.n)
25092501
td64 = np.timedelta64(td, "ns")
25102502
return dtindex + td64

pandas/core/arrays/datetimes.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,9 @@ def _add_offset(self, offset):
685685
values = self.tz_localize(None)
686686
else:
687687
values = self
688-
result = offset.apply_index(values).tz_localize(self.tz)
688+
result = offset.apply_index(values)
689+
result = DatetimeArray._simple_new(result)
690+
result = result.tz_localize(self.tz)
689691

690692
except NotImplementedError:
691693
warnings.warn(

pandas/tests/tseries/offsets/test_offsets.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -3524,7 +3524,7 @@ def test_offset_whole_year(self):
35243524
with tm.assert_produces_warning(None):
35253525
# GH#22535 check that we don't get a FutureWarning from adding
35263526
# an integer array to PeriodIndex
3527-
result = SemiMonthEnd().apply_index(s)
3527+
result = SemiMonthEnd() + s
35283528

35293529
exp = DatetimeIndex(dates[1:])
35303530
tm.assert_index_equal(result, exp)
@@ -3672,7 +3672,7 @@ def test_apply_index(self, case):
36723672
with tm.assert_produces_warning(None):
36733673
# GH#22535 check that we don't get a FutureWarning from adding
36743674
# an integer array to PeriodIndex
3675-
result = offset.apply_index(s)
3675+
result = offset + s
36763676

36773677
exp = DatetimeIndex(cases.values())
36783678
tm.assert_index_equal(result, exp)
@@ -3783,7 +3783,7 @@ def test_offset_whole_year(self):
37833783
with tm.assert_produces_warning(None):
37843784
# GH#22535 check that we don't get a FutureWarning from adding
37853785
# an integer array to PeriodIndex
3786-
result = SemiMonthBegin().apply_index(s)
3786+
result = SemiMonthBegin() + s
37873787

37883788
exp = DatetimeIndex(dates[1:])
37893789
tm.assert_index_equal(result, exp)
@@ -3936,7 +3936,7 @@ def test_apply_index(self, case):
39363936
with tm.assert_produces_warning(None):
39373937
# GH#22535 check that we don't get a FutureWarning from adding
39383938
# an integer array to PeriodIndex
3939-
result = offset.apply_index(s)
3939+
result = offset + s
39403940

39413941
exp = DatetimeIndex(cases.values())
39423942
tm.assert_index_equal(result, exp)

pandas/tests/tseries/offsets/test_yqm_offsets.py

-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ def test_apply_index(cls, n):
6565

6666
res = rng + offset
6767
assert res.freq is None # not retained
68-
res_v2 = offset.apply_index(rng)
69-
assert (res == res_v2).all()
7068
assert res[0] == rng[0] + offset
7169
assert res[-1] == rng[-1] + offset
7270
res2 = ser + offset

0 commit comments

Comments
 (0)