Skip to content

Commit 8ce6740

Browse files
authored
DEPR: DatetimeArray/TimedeltaArray.__init__ (#56043)
* DEPR: DatetimeArray/TimedeltaArray.__init__ * mypy fixup * fix PeriodArray test * update doctest * remove accidental
1 parent 4ac340e commit 8ce6740

26 files changed

+258
-193
lines changed

doc/source/whatsnew/v2.2.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ Other Deprecations
443443
- Deprecated :func:`pd.core.internals.api.make_block`, use public APIs instead (:issue:`40226`)
444444
- Deprecated :func:`read_gbq` and :meth:`DataFrame.to_gbq`. Use ``pandas_gbq.read_gbq`` and ``pandas_gbq.to_gbq`` instead https://pandas-gbq.readthedocs.io/en/latest/api.html (:issue:`55525`)
445445
- Deprecated :meth:`.DataFrameGroupBy.fillna` and :meth:`.SeriesGroupBy.fillna`; use :meth:`.DataFrameGroupBy.ffill`, :meth:`.DataFrameGroupBy.bfill` for forward and backward filling or :meth:`.DataFrame.fillna` to fill with a single value (or the Series equivalents) (:issue:`55718`)
446+
- Deprecated :meth:`DatetimeArray.__init__` and :meth:`TimedeltaArray.__init__`, use :func:`array` instead (:issue:`55623`)
446447
- Deprecated :meth:`Index.format`, use ``index.astype(str)`` or ``index.map(formatter)`` instead (:issue:`55413`)
447448
- Deprecated :meth:`Series.ravel`, the underlying array is already 1D, so ravel is not necessary (:issue:`52511`)
448449
- Deprecated :meth:`Series.resample` and :meth:`DataFrame.resample` with a :class:`PeriodIndex` (and the 'convention' keyword), convert to :class:`DatetimeIndex` (with ``.to_timestamp()``) before resampling instead (:issue:`53481`)

pandas/core/arrays/_mixins.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,20 @@ def view(self, dtype: Dtype | None = None) -> ArrayLike:
133133
cls = dtype.construct_array_type()
134134
return cls(arr.view("i8"), dtype=dtype)
135135
elif isinstance(dtype, DatetimeTZDtype):
136-
# error: Incompatible types in assignment (expression has type
137-
# "type[DatetimeArray]", variable has type "type[PeriodArray]")
138-
cls = dtype.construct_array_type() # type: ignore[assignment]
136+
dt_cls = dtype.construct_array_type()
139137
dt64_values = arr.view(f"M8[{dtype.unit}]")
140-
return cls(dt64_values, dtype=dtype)
138+
return dt_cls._simple_new(dt64_values, dtype=dtype)
141139
elif lib.is_np_dtype(dtype, "M") and is_supported_dtype(dtype):
142140
from pandas.core.arrays import DatetimeArray
143141

144142
dt64_values = arr.view(dtype)
145-
return DatetimeArray(dt64_values, dtype=dtype)
143+
return DatetimeArray._simple_new(dt64_values, dtype=dtype)
144+
146145
elif lib.is_np_dtype(dtype, "m") and is_supported_dtype(dtype):
147146
from pandas.core.arrays import TimedeltaArray
148147

149148
td64_values = arr.view(dtype)
150-
return TimedeltaArray(td64_values, dtype=dtype)
149+
return TimedeltaArray._simple_new(td64_values, dtype=dtype)
151150

152151
# error: Argument "dtype" to "view" of "_ArrayOrScalarCommon" has incompatible
153152
# type "Union[ExtensionDtype, dtype[Any]]"; expected "Union[dtype[Any], None,

pandas/core/arrays/datetimelike.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def _unbox_scalar(
269269
270270
Examples
271271
--------
272-
>>> arr = pd.arrays.DatetimeArray(np.array(['1970-01-01'], 'datetime64[ns]'))
272+
>>> arr = pd.array(np.array(['1970-01-01'], 'datetime64[ns]'))
273273
>>> arr._unbox_scalar(arr[0])
274274
numpy.datetime64('1970-01-01T00:00:00.000000000')
275275
"""
@@ -1409,7 +1409,7 @@ def __add__(self, other):
14091409
if isinstance(result, np.ndarray) and lib.is_np_dtype(result.dtype, "m"):
14101410
from pandas.core.arrays import TimedeltaArray
14111411

1412-
return TimedeltaArray(result)
1412+
return TimedeltaArray._from_sequence(result)
14131413
return result
14141414

14151415
def __radd__(self, other):
@@ -1469,7 +1469,7 @@ def __sub__(self, other):
14691469
if isinstance(result, np.ndarray) and lib.is_np_dtype(result.dtype, "m"):
14701470
from pandas.core.arrays import TimedeltaArray
14711471

1472-
return TimedeltaArray(result)
1472+
return TimedeltaArray._from_sequence(result)
14731473
return result
14741474

14751475
def __rsub__(self, other):
@@ -1488,7 +1488,7 @@ def __rsub__(self, other):
14881488
# Avoid down-casting DatetimeIndex
14891489
from pandas.core.arrays import DatetimeArray
14901490

1491-
other = DatetimeArray(other)
1491+
other = DatetimeArray._from_sequence(other)
14921492
return other - self
14931493
elif self.dtype.kind == "M" and hasattr(other, "dtype") and not other_is_dt64:
14941494
# GH#19959 datetime - datetime is well-defined as timedelta,
@@ -1725,7 +1725,7 @@ def _groupby_op(
17251725
self = cast("DatetimeArray | TimedeltaArray", self)
17261726
new_dtype = f"m8[{self.unit}]"
17271727
res_values = res_values.view(new_dtype)
1728-
return TimedeltaArray(res_values)
1728+
return TimedeltaArray._simple_new(res_values, dtype=res_values.dtype)
17291729

17301730
res_values = res_values.view(self._ndarray.dtype)
17311731
return self._from_backing_data(res_values)
@@ -1944,6 +1944,13 @@ class TimelikeOps(DatetimeLikeArrayMixin):
19441944
def __init__(
19451945
self, values, dtype=None, freq=lib.no_default, copy: bool = False
19461946
) -> None:
1947+
warnings.warn(
1948+
# GH#55623
1949+
f"{type(self).__name__}.__init__ is deprecated and will be "
1950+
"removed in a future version. Use pd.array instead.",
1951+
FutureWarning,
1952+
stacklevel=find_stack_level(),
1953+
)
19471954
if dtype is not None:
19481955
dtype = pandas_dtype(dtype)
19491956

pandas/core/arrays/datetimes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ class DatetimeArray(dtl.TimelikeOps, dtl.DatelikeOps): # type: ignore[misc]
202202
203203
Examples
204204
--------
205-
>>> pd.arrays.DatetimeArray(pd.DatetimeIndex(['2023-01-01', '2023-01-02']),
206-
... freq='D')
205+
>>> pd.arrays.DatetimeArray._from_sequence(
206+
... pd.DatetimeIndex(['2023-01-01', '2023-01-02'], freq='D'))
207207
<DatetimeArray>
208208
['2023-01-01 00:00:00', '2023-01-02 00:00:00']
209209
Length: 2, dtype: datetime64[ns]

pandas/core/arrays/period.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ def to_timestamp(self, freq=None, how: str = "start") -> DatetimeArray:
664664
new_parr = self.asfreq(freq, how=how)
665665

666666
new_data = libperiod.periodarr_to_dt64arr(new_parr.asi8, base)
667-
dta = DatetimeArray(new_data)
667+
dta = DatetimeArray._from_sequence(new_data)
668668

669669
if self.freq.name == "B":
670670
# See if we can retain BDay instead of Day in cases where

pandas/core/arrays/timedeltas.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class TimedeltaArray(dtl.TimelikeOps):
132132
133133
Examples
134134
--------
135-
>>> pd.arrays.TimedeltaArray(pd.TimedeltaIndex(['1h', '2h']))
135+
>>> pd.arrays.TimedeltaArray._from_sequence(pd.TimedeltaIndex(['1h', '2h']))
136136
<TimedeltaArray>
137137
['0 days 01:00:00', '0 days 02:00:00']
138138
Length: 2, dtype: timedelta64[ns]
@@ -709,11 +709,13 @@ def __neg__(self) -> TimedeltaArray:
709709
return type(self)._simple_new(-self._ndarray, dtype=self.dtype, freq=freq)
710710

711711
def __pos__(self) -> TimedeltaArray:
712-
return type(self)(self._ndarray.copy(), freq=self.freq)
712+
return type(self)._simple_new(
713+
self._ndarray.copy(), dtype=self.dtype, freq=self.freq
714+
)
713715

714716
def __abs__(self) -> TimedeltaArray:
715717
# Note: freq is not preserved
716-
return type(self)(np.abs(self._ndarray))
718+
return type(self)._simple_new(np.abs(self._ndarray), dtype=self.dtype)
717719

718720
# ----------------------------------------------------------------
719721
# Conversion Methods - Vectorized analogues of Timedelta methods

pandas/core/dtypes/dtypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ def __from_arrow__(self, array: pa.Array | pa.ChunkedArray) -> DatetimeArray:
919919
else:
920920
np_arr = array.to_numpy()
921921

922-
return DatetimeArray(np_arr, dtype=self, copy=False)
922+
return DatetimeArray._from_sequence(np_arr, dtype=self, copy=False)
923923

924924
def __setstate__(self, state) -> None:
925925
# for pickle compat. __get_state__ is defined in the

pandas/core/indexes/datetimelike.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,10 @@ def _fast_union(self, other: Self, sort=None) -> Self:
697697
dates = concat_compat([left._values, right_chunk])
698698
# The can_fast_union check ensures that the result.freq
699699
# should match self.freq
700-
dates = type(self._data)(dates, freq=self.freq)
700+
assert isinstance(dates, type(self._data))
701+
# error: Item "ExtensionArray" of "ExtensionArray |
702+
# ndarray[Any, Any]" has no attribute "_freq"
703+
assert dates._freq == self.freq # type: ignore[union-attr]
701704
result = type(self)._simple_new(dates)
702705
return result
703706
else:

pandas/core/internals/managers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2345,7 +2345,7 @@ def make_na_array(dtype: DtypeObj, shape: Shape, fill_value) -> ArrayLike:
23452345
ts = Timestamp(fill_value).as_unit(dtype.unit)
23462346
i8values = np.full(shape, ts._value)
23472347
dt64values = i8values.view(f"M8[{dtype.unit}]")
2348-
return DatetimeArray(dt64values, dtype=dtype)
2348+
return DatetimeArray._simple_new(dt64values, dtype=dtype)
23492349

23502350
elif is_1d_only_ea_dtype(dtype):
23512351
dtype = cast(ExtensionDtype, dtype)

pandas/core/ops/array_ops.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ def maybe_prepare_scalar_for_op(obj, shape: Shape):
545545
new_dtype = get_supported_dtype(obj.dtype)
546546
obj = obj.astype(new_dtype)
547547
right = np.broadcast_to(obj, shape)
548-
return DatetimeArray(right)
548+
return DatetimeArray._simple_new(right, dtype=right.dtype)
549549

550550
return Timestamp(obj)
551551

@@ -563,7 +563,7 @@ def maybe_prepare_scalar_for_op(obj, shape: Shape):
563563
new_dtype = get_supported_dtype(obj.dtype)
564564
obj = obj.astype(new_dtype)
565565
right = np.broadcast_to(obj, shape)
566-
return TimedeltaArray(right)
566+
return TimedeltaArray._simple_new(right, dtype=right.dtype)
567567

568568
# In particular non-nanosecond timedelta64 needs to be cast to
569569
# nanoseconds, or else we get undesired behavior like

0 commit comments

Comments
 (0)