Skip to content

Commit d5a07a1

Browse files
authored
REF: implement _with_freq, use _from_sequence less (#32849)
1 parent 73cf1b4 commit d5a07a1

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

pandas/core/arrays/datetimelike.py

+30-2
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,34 @@ def floor(self, freq, ambiguous="raise", nonexistent="raise"):
396396
def ceil(self, freq, ambiguous="raise", nonexistent="raise"):
397397
return self._round(freq, RoundTo.PLUS_INFTY, ambiguous, nonexistent)
398398

399+
def _with_freq(self, freq):
400+
"""
401+
Helper to set our freq in-place, returning self to allow method chaining.
402+
403+
Parameters
404+
----------
405+
freq : DateOffset, None, or "infer"
406+
407+
Returns
408+
-------
409+
self
410+
"""
411+
# GH#29843
412+
if freq is None:
413+
# Always valid
414+
pass
415+
elif len(self) == 0 and isinstance(freq, DateOffset):
416+
# Always valid. In the TimedeltaArray case, we assume this
417+
# is a Tick offset.
418+
pass
419+
else:
420+
# As an internal method, we can ensure this assertion always holds
421+
assert freq == "infer"
422+
freq = frequencies.to_offset(self.inferred_freq)
423+
424+
self._freq = freq
425+
return self
426+
399427

400428
class DatetimeLikeArrayMixin(ExtensionOpsMixin, AttributesMixin, ExtensionArray):
401429
"""
@@ -1157,7 +1185,7 @@ def _add_timedeltalike_scalar(self, other):
11571185
if new_freq is not None:
11581186
# fastpath that doesnt require inference
11591187
return type(self)(new_values, dtype=self.dtype, freq=new_freq)
1160-
return type(self)._from_sequence(new_values, dtype=self.dtype, freq="infer")
1188+
return type(self)(new_values, dtype=self.dtype)._with_freq("infer")
11611189

11621190
def _add_timedelta_arraylike(self, other):
11631191
"""
@@ -1187,7 +1215,7 @@ def _add_timedelta_arraylike(self, other):
11871215
mask = (self._isnan) | (other._isnan)
11881216
new_values[mask] = iNaT
11891217

1190-
return type(self)._from_sequence(new_values, dtype=self.dtype, freq="infer")
1218+
return type(self)(new_values, dtype=self.dtype)._with_freq("infer")
11911219

11921220
def _add_nat(self):
11931221
"""

pandas/core/arrays/datetimes.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ def _add_offset(self, offset):
697697
# GH#30336 _from_sequence won't be able to infer self.tz
698698
return type(self)._from_sequence(result).tz_localize(self.tz)
699699

700-
return type(self)._from_sequence(result, freq="infer")
700+
return type(self)._from_sequence(result)._with_freq("infer")
701701

702702
def _sub_datetimelike_scalar(self, other):
703703
# subtract a datetime from myself, yielding a ndarray[timedelta64[ns]]
@@ -1031,7 +1031,7 @@ def normalize(self):
10311031
new_values[not_null] = new_values[not_null] - adjustment
10321032
else:
10331033
new_values = conversion.normalize_i8_timestamps(self.asi8, self.tz)
1034-
return type(self)._from_sequence(new_values, freq="infer").tz_localize(self.tz)
1034+
return type(self)(new_values)._with_freq("infer").tz_localize(self.tz)
10351035

10361036
def to_period(self, freq=None):
10371037
"""

pandas/core/arrays/period.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def _from_sequence(
185185
validate_dtype_freq(scalars.dtype, freq)
186186
if copy:
187187
scalars = scalars.copy()
188+
assert isinstance(scalars, PeriodArray) # for mypy
188189
return scalars
189190

190191
periods = np.asarray(scalars, dtype=object)
@@ -452,7 +453,7 @@ def to_timestamp(self, freq=None, how="start"):
452453
new_data = self.asfreq(freq, how=how)
453454

454455
new_data = libperiod.periodarr_to_dt64arr(new_data.asi8, base)
455-
return DatetimeArray._from_sequence(new_data, freq="infer")
456+
return DatetimeArray(new_data)._with_freq("infer")
456457

457458
# --------------------------------------------------------------------
458459

pandas/core/indexes/datetimelike.py

+2-14
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from pandas.core.ops import get_op_result_name
4444
from pandas.core.tools.timedeltas import to_timedelta
4545

46-
from pandas.tseries.frequencies import DateOffset, to_offset
46+
from pandas.tseries.frequencies import DateOffset
4747

4848
_index_doc_kwargs = dict(ibase._index_doc_kwargs)
4949

@@ -623,19 +623,7 @@ def _set_freq(self, freq):
623623
freq : DateOffset, None, or "infer"
624624
"""
625625
# GH#29843
626-
if freq is None:
627-
# Always valid
628-
pass
629-
elif len(self) == 0 and isinstance(freq, DateOffset):
630-
# Always valid. In the TimedeltaIndex case, we assume this
631-
# is a Tick offset.
632-
pass
633-
else:
634-
# As an internal method, we can ensure this assertion always holds
635-
assert freq == "infer"
636-
freq = to_offset(self.inferred_freq)
637-
638-
self._data._freq = freq
626+
self._data._with_freq(freq)
639627

640628
def _shallow_copy(self, values=None, name: Label = lib.no_default):
641629
name = self.name if name is lib.no_default else name

0 commit comments

Comments
 (0)