Skip to content

Commit c1a81fe

Browse files
jorisvandenbosscheTomAugspurger
authored andcommitted
API: TimedeltaArray freq validation without _from_sequence (#24723)
* TimedeltaArray freq validation without _from_sequence
1 parent 7c4efe0 commit c1a81fe

File tree

2 files changed

+51
-18
lines changed

2 files changed

+51
-18
lines changed

pandas/core/arrays/timedeltas.py

+50-17
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
from pandas.util._decorators import Appender
1616

1717
from pandas.core.dtypes.common import (
18-
_NS_DTYPE, _TD_DTYPE, ensure_int64, is_datetime64_dtype, is_dtype_equal,
19-
is_float_dtype, is_integer_dtype, is_list_like, is_object_dtype, is_scalar,
18+
_NS_DTYPE, _TD_DTYPE, ensure_int64, is_datetime64_dtype, is_float_dtype,
19+
is_integer_dtype, is_list_like, is_object_dtype, is_scalar,
2020
is_string_dtype, is_timedelta64_dtype, is_timedelta64_ns_dtype,
2121
pandas_dtype)
2222
from pandas.core.dtypes.dtypes import DatetimeTZDtype
@@ -134,28 +134,61 @@ def dtype(self):
134134
_attributes = ["freq"]
135135

136136
def __init__(self, values, dtype=_TD_DTYPE, freq=None, copy=False):
137-
if not hasattr(values, "dtype"):
138-
raise ValueError(
137+
if isinstance(values, (ABCSeries, ABCIndexClass)):
138+
values = values._values
139+
140+
inferred_freq = getattr(values, "_freq", None)
141+
142+
if isinstance(values, type(self)):
143+
if freq is None:
144+
freq = values.freq
145+
elif freq and values.freq:
146+
freq = to_offset(freq)
147+
freq, _ = dtl.validate_inferred_freq(freq, values.freq, False)
148+
values = values._data
149+
150+
if not isinstance(values, np.ndarray):
151+
msg = (
139152
"Unexpected type '{}'. 'values' must be a TimedeltaArray "
140153
"ndarray, or Series or Index containing one of those."
141-
.format(type(values).__name__))
154+
)
155+
raise ValueError(msg.format(type(values).__name__))
156+
157+
if values.dtype == 'i8':
158+
# for compat with datetime/timedelta/period shared methods,
159+
# we can sometimes get here with int64 values. These represent
160+
# nanosecond UTC (or tz-naive) unix timestamps
161+
values = values.view(_TD_DTYPE)
162+
163+
if values.dtype != _TD_DTYPE:
164+
raise TypeError(_BAD_DTYPE.format(dtype=values.dtype))
165+
166+
try:
167+
dtype_mismatch = dtype != _TD_DTYPE
168+
except TypeError:
169+
raise TypeError(_BAD_DTYPE.format(dtype=dtype))
170+
else:
171+
if dtype_mismatch:
172+
raise TypeError(_BAD_DTYPE.format(dtype=dtype))
173+
142174
if freq == "infer":
143-
raise ValueError(
175+
msg = (
144176
"Frequency inference not allowed in TimedeltaArray.__init__. "
145-
"Use 'pd.array()' instead.")
177+
"Use 'pd.array()' instead."
178+
)
179+
raise ValueError(msg)
146180

147-
if dtype is not None and not is_dtype_equal(dtype, _TD_DTYPE):
148-
raise TypeError("dtype {dtype} cannot be converted to "
149-
"timedelta64[ns]".format(dtype=dtype))
181+
if copy:
182+
values = values.copy()
183+
if freq:
184+
freq = to_offset(freq)
150185

151-
if values.dtype == 'i8':
152-
values = values.view('timedelta64[ns]')
186+
self._data = values
187+
self._dtype = dtype
188+
self._freq = freq
153189

154-
result = type(self)._from_sequence(values, dtype=dtype,
155-
copy=copy, freq=freq)
156-
self._data = result._data
157-
self._freq = result._freq
158-
self._dtype = result._dtype
190+
if inferred_freq is None and freq is not None:
191+
type(self)._validate_frequency(self, freq)
159192

160193
@classmethod
161194
def _simple_new(cls, values, freq=None, dtype=_TD_DTYPE):

pandas/tests/arrays/test_timedeltas.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_incorrect_dtype_raises(self):
4343
def test_copy(self):
4444
data = np.array([1, 2, 3], dtype='m8[ns]')
4545
arr = TimedeltaArray(data, copy=False)
46-
assert arr._data.base is data
46+
assert arr._data is data
4747

4848
arr = TimedeltaArray(data, copy=True)
4949
assert arr._data is not data

0 commit comments

Comments
 (0)