diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index f7017aba1d9964..70039cc697b8ad 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -443,6 +443,7 @@ Other Deprecations - Deprecated :func:`pd.core.internals.api.make_block`, use public APIs instead (:issue:`40226`) - 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`) - 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`) +- Deprecated :meth:`DatetimeArray.__init__` and :meth:`TimedeltaArray.__init__`, use :func:`array` instead (:issue:`55623`) - Deprecated :meth:`Index.format`, use ``index.astype(str)`` or ``index.map(formatter)`` instead (:issue:`55413`) - Deprecated :meth:`Series.ravel`, the underlying array is already 1D, so ravel is not necessary (:issue:`52511`) - 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`) diff --git a/pandas/core/arrays/_mixins.py b/pandas/core/arrays/_mixins.py index cb8f8022391460..9ece12cf51a7b4 100644 --- a/pandas/core/arrays/_mixins.py +++ b/pandas/core/arrays/_mixins.py @@ -133,21 +133,20 @@ def view(self, dtype: Dtype | None = None) -> ArrayLike: cls = dtype.construct_array_type() return cls(arr.view("i8"), dtype=dtype) elif isinstance(dtype, DatetimeTZDtype): - # error: Incompatible types in assignment (expression has type - # "type[DatetimeArray]", variable has type "type[PeriodArray]") - cls = dtype.construct_array_type() # type: ignore[assignment] + dt_cls = dtype.construct_array_type() dt64_values = arr.view(f"M8[{dtype.unit}]") - return cls(dt64_values, dtype=dtype) + return dt_cls._simple_new(dt64_values, dtype=dtype) elif lib.is_np_dtype(dtype, "M") and is_supported_dtype(dtype): from pandas.core.arrays import DatetimeArray dt64_values = arr.view(dtype) - return DatetimeArray(dt64_values, dtype=dtype) + return DatetimeArray._simple_new(dt64_values, dtype=dtype) + elif lib.is_np_dtype(dtype, "m") and is_supported_dtype(dtype): from pandas.core.arrays import TimedeltaArray td64_values = arr.view(dtype) - return TimedeltaArray(td64_values, dtype=dtype) + return TimedeltaArray._simple_new(td64_values, dtype=dtype) # error: Argument "dtype" to "view" of "_ArrayOrScalarCommon" has incompatible # type "Union[ExtensionDtype, dtype[Any]]"; expected "Union[dtype[Any], None, diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 1530fae89aa004..11a0c7bf18fcbc 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -269,7 +269,7 @@ def _unbox_scalar( Examples -------- - >>> arr = pd.arrays.DatetimeArray(np.array(['1970-01-01'], 'datetime64[ns]')) + >>> arr = pd.array(np.array(['1970-01-01'], 'datetime64[ns]')) >>> arr._unbox_scalar(arr[0]) numpy.datetime64('1970-01-01T00:00:00.000000000') """ @@ -1409,7 +1409,7 @@ def __add__(self, other): if isinstance(result, np.ndarray) and lib.is_np_dtype(result.dtype, "m"): from pandas.core.arrays import TimedeltaArray - return TimedeltaArray(result) + return TimedeltaArray._from_sequence(result) return result def __radd__(self, other): @@ -1469,7 +1469,7 @@ def __sub__(self, other): if isinstance(result, np.ndarray) and lib.is_np_dtype(result.dtype, "m"): from pandas.core.arrays import TimedeltaArray - return TimedeltaArray(result) + return TimedeltaArray._from_sequence(result) return result def __rsub__(self, other): @@ -1488,7 +1488,7 @@ def __rsub__(self, other): # Avoid down-casting DatetimeIndex from pandas.core.arrays import DatetimeArray - other = DatetimeArray(other) + other = DatetimeArray._from_sequence(other) return other - self elif self.dtype.kind == "M" and hasattr(other, "dtype") and not other_is_dt64: # GH#19959 datetime - datetime is well-defined as timedelta, @@ -1725,7 +1725,7 @@ def _groupby_op( self = cast("DatetimeArray | TimedeltaArray", self) new_dtype = f"m8[{self.unit}]" res_values = res_values.view(new_dtype) - return TimedeltaArray(res_values) + return TimedeltaArray._simple_new(res_values, dtype=res_values.dtype) res_values = res_values.view(self._ndarray.dtype) return self._from_backing_data(res_values) @@ -1944,6 +1944,13 @@ class TimelikeOps(DatetimeLikeArrayMixin): def __init__( self, values, dtype=None, freq=lib.no_default, copy: bool = False ) -> None: + warnings.warn( + # GH#55623 + f"{type(self).__name__}.__init__ is deprecated and will be " + "removed in a future version. Use pd.array instead.", + FutureWarning, + stacklevel=find_stack_level(), + ) if dtype is not None: dtype = pandas_dtype(dtype) diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 9329f82c1b6462..6b7ddc4a729573 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -202,8 +202,8 @@ class DatetimeArray(dtl.TimelikeOps, dtl.DatelikeOps): # type: ignore[misc] Examples -------- - >>> pd.arrays.DatetimeArray(pd.DatetimeIndex(['2023-01-01', '2023-01-02']), - ... freq='D') + >>> pd.arrays.DatetimeArray._from_sequence( + ... pd.DatetimeIndex(['2023-01-01', '2023-01-02'], freq='D')) ['2023-01-01 00:00:00', '2023-01-02 00:00:00'] Length: 2, dtype: datetime64[ns] diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 0e2d4409b9f393..2930b979bfe781 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -664,7 +664,7 @@ def to_timestamp(self, freq=None, how: str = "start") -> DatetimeArray: new_parr = self.asfreq(freq, how=how) new_data = libperiod.periodarr_to_dt64arr(new_parr.asi8, base) - dta = DatetimeArray(new_data) + dta = DatetimeArray._from_sequence(new_data) if self.freq.name == "B": # See if we can retain BDay instead of Day in cases where diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 95c3c641fd51af..1b885a2bdcd47b 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -132,7 +132,7 @@ class TimedeltaArray(dtl.TimelikeOps): Examples -------- - >>> pd.arrays.TimedeltaArray(pd.TimedeltaIndex(['1h', '2h'])) + >>> pd.arrays.TimedeltaArray._from_sequence(pd.TimedeltaIndex(['1h', '2h'])) ['0 days 01:00:00', '0 days 02:00:00'] Length: 2, dtype: timedelta64[ns] @@ -709,11 +709,13 @@ def __neg__(self) -> TimedeltaArray: return type(self)._simple_new(-self._ndarray, dtype=self.dtype, freq=freq) def __pos__(self) -> TimedeltaArray: - return type(self)(self._ndarray.copy(), freq=self.freq) + return type(self)._simple_new( + self._ndarray.copy(), dtype=self.dtype, freq=self.freq + ) def __abs__(self) -> TimedeltaArray: # Note: freq is not preserved - return type(self)(np.abs(self._ndarray)) + return type(self)._simple_new(np.abs(self._ndarray), dtype=self.dtype) # ---------------------------------------------------------------- # Conversion Methods - Vectorized analogues of Timedelta methods diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index 4c1654ab0f5e4c..ed5256922377ac 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -919,7 +919,7 @@ def __from_arrow__(self, array: pa.Array | pa.ChunkedArray) -> DatetimeArray: else: np_arr = array.to_numpy() - return DatetimeArray(np_arr, dtype=self, copy=False) + return DatetimeArray._from_sequence(np_arr, dtype=self, copy=False) def __setstate__(self, state) -> None: # for pickle compat. __get_state__ is defined in the diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 4fc2fdb3202b10..cad8737a987d44 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -697,7 +697,10 @@ def _fast_union(self, other: Self, sort=None) -> Self: dates = concat_compat([left._values, right_chunk]) # The can_fast_union check ensures that the result.freq # should match self.freq - dates = type(self._data)(dates, freq=self.freq) + assert isinstance(dates, type(self._data)) + # error: Item "ExtensionArray" of "ExtensionArray | + # ndarray[Any, Any]" has no attribute "_freq" + assert dates._freq == self.freq # type: ignore[union-attr] result = type(self)._simple_new(dates) return result else: diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index 781b6df5ebd3da..3719bf1f77f85b 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -2345,7 +2345,7 @@ def make_na_array(dtype: DtypeObj, shape: Shape, fill_value) -> ArrayLike: ts = Timestamp(fill_value).as_unit(dtype.unit) i8values = np.full(shape, ts._value) dt64values = i8values.view(f"M8[{dtype.unit}]") - return DatetimeArray(dt64values, dtype=dtype) + return DatetimeArray._simple_new(dt64values, dtype=dtype) elif is_1d_only_ea_dtype(dtype): dtype = cast(ExtensionDtype, dtype) diff --git a/pandas/core/ops/array_ops.py b/pandas/core/ops/array_ops.py index d8a772aac60829..ee3f8787d78b5c 100644 --- a/pandas/core/ops/array_ops.py +++ b/pandas/core/ops/array_ops.py @@ -545,7 +545,7 @@ def maybe_prepare_scalar_for_op(obj, shape: Shape): new_dtype = get_supported_dtype(obj.dtype) obj = obj.astype(new_dtype) right = np.broadcast_to(obj, shape) - return DatetimeArray(right) + return DatetimeArray._simple_new(right, dtype=right.dtype) return Timestamp(obj) @@ -563,7 +563,7 @@ def maybe_prepare_scalar_for_op(obj, shape: Shape): new_dtype = get_supported_dtype(obj.dtype) obj = obj.astype(new_dtype) right = np.broadcast_to(obj, shape) - return TimedeltaArray(right) + return TimedeltaArray._simple_new(right, dtype=right.dtype) # In particular non-nanosecond timedelta64 needs to be cast to # nanoseconds, or else we get undesired behavior like diff --git a/pandas/tests/arrays/datetimes/test_constructors.py b/pandas/tests/arrays/datetimes/test_constructors.py index 97fa6e8d529b7c..daf4aa3b47f569 100644 --- a/pandas/tests/arrays/datetimes/test_constructors.py +++ b/pandas/tests/arrays/datetimes/test_constructors.py @@ -19,13 +19,16 @@ def test_from_sequence_invalid_type(self): def test_only_1dim_accepted(self): arr = np.array([0, 1, 2, 3], dtype="M8[h]").astype("M8[ns]") - with pytest.raises(ValueError, match="Only 1-dimensional"): - # 3-dim, we allow 2D to sneak in for ops purposes GH#29853 - DatetimeArray(arr.reshape(2, 2, 1)) + depr_msg = "DatetimeArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Only 1-dimensional"): + # 3-dim, we allow 2D to sneak in for ops purposes GH#29853 + DatetimeArray(arr.reshape(2, 2, 1)) - with pytest.raises(ValueError, match="Only 1-dimensional"): - # 0-dim - DatetimeArray(arr[[0]].squeeze()) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Only 1-dimensional"): + # 0-dim + DatetimeArray(arr[[0]].squeeze()) def test_freq_validation(self): # GH#24623 check that invalid instances cannot be created with the @@ -36,8 +39,10 @@ def test_freq_validation(self): "Inferred frequency h from passed values does not " "conform to passed frequency W-SUN" ) - with pytest.raises(ValueError, match=msg): - DatetimeArray(arr, freq="W") + depr_msg = "DatetimeArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match=msg): + DatetimeArray(arr, freq="W") @pytest.mark.parametrize( "meth", @@ -72,31 +77,40 @@ def test_from_pandas_array(self): tm.assert_datetime_array_equal(result, expected) def test_mismatched_timezone_raises(self): - arr = DatetimeArray( - np.array(["2000-01-01T06:00:00"], dtype="M8[ns]"), - dtype=DatetimeTZDtype(tz="US/Central"), - ) + depr_msg = "DatetimeArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + arr = DatetimeArray( + np.array(["2000-01-01T06:00:00"], dtype="M8[ns]"), + dtype=DatetimeTZDtype(tz="US/Central"), + ) dtype = DatetimeTZDtype(tz="US/Eastern") msg = r"dtype=datetime64\[ns.*\] does not match data dtype datetime64\[ns.*\]" - with pytest.raises(TypeError, match=msg): - DatetimeArray(arr, dtype=dtype) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(TypeError, match=msg): + DatetimeArray(arr, dtype=dtype) # also with mismatched tzawareness - with pytest.raises(TypeError, match=msg): - DatetimeArray(arr, dtype=np.dtype("M8[ns]")) - with pytest.raises(TypeError, match=msg): - DatetimeArray(arr.tz_localize(None), dtype=arr.dtype) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(TypeError, match=msg): + DatetimeArray(arr, dtype=np.dtype("M8[ns]")) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(TypeError, match=msg): + DatetimeArray(arr.tz_localize(None), dtype=arr.dtype) def test_non_array_raises(self): - with pytest.raises(ValueError, match="list"): - DatetimeArray([1, 2, 3]) + depr_msg = "DatetimeArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="list"): + DatetimeArray([1, 2, 3]) def test_bool_dtype_raises(self): arr = np.array([1, 2, 3], dtype="bool") + depr_msg = "DatetimeArray.__init__ is deprecated" msg = "Unexpected value for 'dtype': 'bool'. Must be" - with pytest.raises(ValueError, match=msg): - DatetimeArray(arr) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match=msg): + DatetimeArray(arr) msg = r"dtype bool cannot be converted to datetime64\[ns\]" with pytest.raises(TypeError, match=msg): @@ -109,43 +123,52 @@ def test_bool_dtype_raises(self): pd.to_datetime(arr) def test_incorrect_dtype_raises(self): - with pytest.raises(ValueError, match="Unexpected value for 'dtype'."): - DatetimeArray(np.array([1, 2, 3], dtype="i8"), dtype="category") + depr_msg = "DatetimeArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Unexpected value for 'dtype'."): + DatetimeArray(np.array([1, 2, 3], dtype="i8"), dtype="category") - with pytest.raises(ValueError, match="Unexpected value for 'dtype'."): - DatetimeArray(np.array([1, 2, 3], dtype="i8"), dtype="m8[s]") + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Unexpected value for 'dtype'."): + DatetimeArray(np.array([1, 2, 3], dtype="i8"), dtype="m8[s]") - with pytest.raises(ValueError, match="Unexpected value for 'dtype'."): - DatetimeArray(np.array([1, 2, 3], dtype="i8"), dtype="M8[D]") + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Unexpected value for 'dtype'."): + DatetimeArray(np.array([1, 2, 3], dtype="i8"), dtype="M8[D]") def test_mismatched_values_dtype_units(self): arr = np.array([1, 2, 3], dtype="M8[s]") dtype = np.dtype("M8[ns]") msg = "Values resolution does not match dtype." + depr_msg = "DatetimeArray.__init__ is deprecated" - with pytest.raises(ValueError, match=msg): - DatetimeArray(arr, dtype=dtype) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match=msg): + DatetimeArray(arr, dtype=dtype) dtype2 = DatetimeTZDtype(tz="UTC", unit="ns") - with pytest.raises(ValueError, match=msg): - DatetimeArray(arr, dtype=dtype2) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match=msg): + DatetimeArray(arr, dtype=dtype2) def test_freq_infer_raises(self): - with pytest.raises(ValueError, match="Frequency inference"): - DatetimeArray(np.array([1, 2, 3], dtype="i8"), freq="infer") + depr_msg = "DatetimeArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Frequency inference"): + DatetimeArray(np.array([1, 2, 3], dtype="i8"), freq="infer") def test_copy(self): data = np.array([1, 2, 3], dtype="M8[ns]") - arr = DatetimeArray(data, copy=False) + arr = DatetimeArray._from_sequence(data, copy=False) assert arr._ndarray is data - arr = DatetimeArray(data, copy=True) + arr = DatetimeArray._from_sequence(data, copy=True) assert arr._ndarray is not data @pytest.mark.parametrize("unit", ["s", "ms", "us", "ns"]) def test_numpy_datetime_unit(self, unit): data = np.array([1, 2, 3], dtype=f"M8[{unit}]") - arr = DatetimeArray(data) + arr = DatetimeArray._from_sequence(data) assert arr.unit == unit assert arr[0].unit == unit @@ -210,7 +233,7 @@ def test_from_arrowtest_from_arrow_with_different_units_and_timezones_with_( dtype = DatetimeTZDtype(unit=pd_unit, tz=pd_tz) result = dtype.__from_arrow__(arr) - expected = DatetimeArray( + expected = DatetimeArray._from_sequence( np.array(data, dtype=f"datetime64[{pa_unit}]").astype(f"datetime64[{pd_unit}]"), dtype=dtype, ) @@ -238,7 +261,7 @@ def test_from_arrow_from_empty(unit, tz): dtype = DatetimeTZDtype(unit=unit, tz=tz) result = dtype.__from_arrow__(arr) - expected = DatetimeArray(np.array(data, dtype=f"datetime64[{unit}]")) + expected = DatetimeArray._from_sequence(np.array(data, dtype=f"datetime64[{unit}]")) expected = expected.tz_localize(tz=tz) tm.assert_extension_array_equal(result, expected) @@ -254,7 +277,7 @@ def test_from_arrow_from_integers(): dtype = DatetimeTZDtype(unit="ns", tz="UTC") result = dtype.__from_arrow__(arr) - expected = DatetimeArray(np.array(data, dtype="datetime64[ns]")) + expected = DatetimeArray._from_sequence(np.array(data, dtype="datetime64[ns]")) expected = expected.tz_localize("UTC") tm.assert_extension_array_equal(result, expected) diff --git a/pandas/tests/arrays/test_array.py b/pandas/tests/arrays/test_array.py index 4381469196e18c..96263f498935b0 100644 --- a/pandas/tests/arrays/test_array.py +++ b/pandas/tests/arrays/test_array.py @@ -296,7 +296,7 @@ def test_array_copy(): ), ( np.array([1, 2], dtype="M8[ns]"), - DatetimeArray(np.array([1, 2], dtype="M8[ns]")), + DatetimeArray._from_sequence(np.array([1, 2], dtype="M8[ns]")), ), ( np.array([1, 2], dtype="M8[us]"), @@ -327,11 +327,11 @@ def test_array_copy(): ), ( np.array([1, 2], dtype="m8[ns]"), - TimedeltaArray(np.array([1, 2], dtype="m8[ns]")), + TimedeltaArray._from_sequence(np.array([1, 2], dtype="m8[ns]")), ), ( np.array([1, 2], dtype="m8[us]"), - TimedeltaArray(np.array([1, 2], dtype="m8[us]")), + TimedeltaArray._from_sequence(np.array([1, 2], dtype="m8[us]")), ), # integer ([1, 2], IntegerArray._from_sequence([1, 2], dtype="Int64")), diff --git a/pandas/tests/arrays/test_datetimelike.py b/pandas/tests/arrays/test_datetimelike.py index 4fba662631b420..82524ea1150198 100644 --- a/pandas/tests/arrays/test_datetimelike.py +++ b/pandas/tests/arrays/test_datetimelike.py @@ -89,7 +89,10 @@ class SharedTests: def arr1d(self): """Fixture returning DatetimeArray with daily frequency.""" data = np.arange(10, dtype="i8") * 24 * 3600 * 10**9 - arr = self.array_cls(data, freq="D") + if self.array_cls is PeriodArray: + arr = self.array_cls(data, freq="D") + else: + arr = self.index_cls(data, freq="D")._data return arr def test_compare_len1_raises(self, arr1d): @@ -161,7 +164,7 @@ def test_take(self): if self.array_cls is PeriodArray: arr = PeriodArray(data, dtype="period[D]") else: - arr = self.array_cls(data) + arr = self.index_cls(data)._data idx = self.index_cls._simple_new(arr) takers = [1, 4, 94] @@ -211,7 +214,7 @@ def test_concat_same_type(self, arr1d): arr = arr1d idx = self.index_cls(arr) idx = idx.insert(0, NaT) - arr = self.array_cls(idx) + arr = arr1d result = arr._concat_same_type([arr[:-1], arr[1:], arr]) arr2 = arr.astype(object) @@ -251,7 +254,7 @@ def test_fillna_method_doesnt_change_orig(self, method): if self.array_cls is PeriodArray: arr = self.array_cls(data, dtype="period[D]") else: - arr = self.array_cls(data) + arr = self.array_cls._from_sequence(data) arr[4] = NaT fill_value = arr[3] if method == "pad" else arr[5] @@ -267,7 +270,7 @@ def test_searchsorted(self): if self.array_cls is PeriodArray: arr = self.array_cls(data, dtype="period[D]") else: - arr = self.array_cls(data) + arr = self.array_cls._from_sequence(data) # scalar result = arr.searchsorted(arr[1]) @@ -339,7 +342,7 @@ def test_getitem_near_implementation_bounds(self): if self.array_cls is PeriodArray: arr = self.array_cls(i8vals, dtype="period[ns]") else: - arr = self.array_cls(i8vals, freq="ns") + arr = self.index_cls(i8vals, freq="ns")._data arr[0] # should not raise OutOfBoundsDatetime index = pd.Index(arr) @@ -350,13 +353,15 @@ def test_getitem_near_implementation_bounds(self): def test_getitem_2d(self, arr1d): # 2d slicing on a 1D array - expected = type(arr1d)(arr1d._ndarray[:, np.newaxis], dtype=arr1d.dtype) + expected = type(arr1d)._simple_new( + arr1d._ndarray[:, np.newaxis], dtype=arr1d.dtype + ) result = arr1d[:, np.newaxis] tm.assert_equal(result, expected) # Lookup on a 2D array arr2d = expected - expected = type(arr2d)(arr2d._ndarray[:3, 0], dtype=arr2d.dtype) + expected = type(arr2d)._simple_new(arr2d._ndarray[:3, 0], dtype=arr2d.dtype) result = arr2d[:3, 0] tm.assert_equal(result, expected) @@ -409,7 +414,7 @@ def test_setitem(self): if self.array_cls is PeriodArray: arr = self.array_cls(data, dtype="period[D]") else: - arr = self.array_cls(data, freq="D") + arr = self.index_cls(data, freq="D")._data arr[0] = arr[1] expected = np.arange(10, dtype="i8") * 24 * 3600 * 10**9 @@ -524,7 +529,7 @@ def test_inplace_arithmetic(self): if self.array_cls is PeriodArray: arr = self.array_cls(data, dtype="period[D]") else: - arr = self.array_cls(data, freq="D") + arr = self.index_cls(data, freq="D")._data expected = arr + pd.Timedelta(days=1) arr += pd.Timedelta(days=1) @@ -589,10 +594,13 @@ def test_median(self, arr1d): def test_from_integer_array(self): arr = np.array([1, 2, 3], dtype=np.int64) - expected = self.array_cls(arr, dtype=self.example_dtype) - data = pd.array(arr, dtype="Int64") - result = self.array_cls(data, dtype=self.example_dtype) + if self.array_cls is PeriodArray: + expected = self.array_cls(arr, dtype=self.example_dtype) + result = self.array_cls(data, dtype=self.example_dtype) + else: + expected = self.array_cls._from_sequence(arr, dtype=self.example_dtype) + result = self.array_cls._from_sequence(data, dtype=self.example_dtype) tm.assert_extension_array_equal(result, expected) @@ -629,7 +637,7 @@ def test_round(self, arr1d): tm.assert_datetime_array_equal(result, expected) def test_array_interface(self, datetime_index): - arr = DatetimeArray(datetime_index) + arr = datetime_index._data # default asarray gives the same underlying data (for tz naive) result = np.asarray(arr) @@ -723,10 +731,10 @@ def test_array_i8_dtype(self, arr1d): def test_from_array_keeps_base(self): # Ensure that DatetimeArray._ndarray.base isn't lost. arr = np.array(["2000-01-01", "2000-01-02"], dtype="M8[ns]") - dta = DatetimeArray(arr) + dta = DatetimeArray._from_sequence(arr) assert dta._ndarray is arr - dta = DatetimeArray(arr[:0]) + dta = DatetimeArray._from_sequence(arr[:0]) assert dta._ndarray.base is arr def test_from_dti(self, arr1d): @@ -751,7 +759,7 @@ def test_astype_object(self, arr1d): @pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning") def test_to_period(self, datetime_index, freqstr): dti = datetime_index - arr = DatetimeArray(dti) + arr = dti._data freqstr = freq_to_period_freqstr(1, freqstr) expected = dti.to_period(freq=freqstr) @@ -853,14 +861,10 @@ def test_concat_same_type_invalid(self, arr1d): def test_concat_same_type_different_freq(self, unit): # we *can* concatenate DTI with different freqs. - a = DatetimeArray( - pd.date_range("2000", periods=2, freq="D", tz="US/Central", unit=unit) - ) - b = DatetimeArray( - pd.date_range("2000", periods=2, freq="h", tz="US/Central", unit=unit) - ) + a = pd.date_range("2000", periods=2, freq="D", tz="US/Central", unit=unit)._data + b = pd.date_range("2000", periods=2, freq="h", tz="US/Central", unit=unit)._data result = DatetimeArray._concat_same_type([a, b]) - expected = DatetimeArray( + expected = ( pd.to_datetime( [ "2000-01-01 00:00:00", @@ -871,6 +875,7 @@ def test_concat_same_type_different_freq(self, unit): ) .tz_localize("US/Central") .as_unit(unit) + ._data ) tm.assert_datetime_array_equal(result, expected) @@ -884,7 +889,7 @@ def test_strftime(self, arr1d): def test_strftime_nat(self): # GH 29578 - arr = DatetimeArray(DatetimeIndex(["2019-01-01", NaT])) + arr = DatetimeIndex(["2019-01-01", NaT])._data result = arr.strftime("%Y-%m-%d") expected = np.array(["2019-01-01", np.nan], dtype=object) @@ -899,7 +904,7 @@ class TestTimedeltaArray(SharedTests): def test_from_tdi(self): tdi = TimedeltaIndex(["1 Day", "3 Hours"]) - arr = TimedeltaArray(tdi) + arr = tdi._data assert list(arr) == list(tdi) # Check that Index.__new__ knows what to do with TimedeltaArray @@ -909,7 +914,7 @@ def test_from_tdi(self): def test_astype_object(self): tdi = TimedeltaIndex(["1 Day", "3 Hours"]) - arr = TimedeltaArray(tdi) + arr = tdi._data asobj = arr.astype("O") assert isinstance(asobj, np.ndarray) assert asobj.dtype == "O" @@ -917,7 +922,7 @@ def test_astype_object(self): def test_to_pytimedelta(self, timedelta_index): tdi = timedelta_index - arr = TimedeltaArray(tdi) + arr = tdi._data expected = tdi.to_pytimedelta() result = arr.to_pytimedelta() @@ -926,7 +931,7 @@ def test_to_pytimedelta(self, timedelta_index): def test_total_seconds(self, timedelta_index): tdi = timedelta_index - arr = TimedeltaArray(tdi) + arr = tdi._data expected = tdi.total_seconds() result = arr.total_seconds() @@ -936,7 +941,7 @@ def test_total_seconds(self, timedelta_index): @pytest.mark.parametrize("propname", TimedeltaArray._field_ops) def test_int_properties(self, timedelta_index, propname): tdi = timedelta_index - arr = TimedeltaArray(tdi) + arr = tdi._data result = getattr(arr, propname) expected = np.array(getattr(tdi, propname), dtype=result.dtype) @@ -944,7 +949,7 @@ def test_int_properties(self, timedelta_index, propname): tm.assert_numpy_array_equal(result, expected) def test_array_interface(self, timedelta_index): - arr = TimedeltaArray(timedelta_index) + arr = timedelta_index._data # default asarray gives the same underlying data result = np.asarray(arr) @@ -987,7 +992,7 @@ def test_array_interface(self, timedelta_index): def test_take_fill_valid(self, timedelta_index, fixed_now_ts): tdi = timedelta_index - arr = TimedeltaArray(tdi) + arr = tdi._data td1 = pd.Timedelta(days=1) result = arr.take([-1, 1], allow_fill=True, fill_value=td1) @@ -1062,7 +1067,7 @@ def test_to_timestamp(self, how, arr1d): pi = self.index_cls(arr1d) arr = arr1d - expected = DatetimeArray(pi.to_timestamp(how=how)) + expected = DatetimeIndex(pi.to_timestamp(how=how))._data result = arr.to_timestamp(how=how) assert isinstance(result, DatetimeArray) @@ -1308,8 +1313,10 @@ def test_from_pandas_array(dtype): cls = {"M8[ns]": DatetimeArray, "m8[ns]": TimedeltaArray}[dtype] - result = cls(arr) - expected = cls(data) + depr_msg = f"{cls.__name__}.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + result = cls(arr) + expected = cls(data) tm.assert_extension_array_equal(result, expected) result = cls._from_sequence(arr, dtype=dtype) diff --git a/pandas/tests/arrays/test_datetimes.py b/pandas/tests/arrays/test_datetimes.py index db86f62a104841..9a576be10d5ca8 100644 --- a/pandas/tests/arrays/test_datetimes.py +++ b/pandas/tests/arrays/test_datetimes.py @@ -281,7 +281,7 @@ def test_cmp_dt64_arraylike_tznaive(self, comparison_op): op = comparison_op dti = pd.date_range("2016-01-1", freq="MS", periods=9, tz=None) - arr = DatetimeArray(dti) + arr = dti._data assert arr.freq == dti.freq assert arr.tz == dti.tz @@ -426,7 +426,7 @@ def test_setitem_str_impute_tz(self, tz_naive_fixture): data = np.array([1, 2, 3], dtype="M8[ns]") dtype = data.dtype if tz is None else DatetimeTZDtype(tz=tz) - arr = DatetimeArray(data, dtype=dtype) + arr = DatetimeArray._from_sequence(data, dtype=dtype) expected = arr.copy() ts = pd.Timestamp("2020-09-08 16:50").tz_localize(tz) @@ -446,7 +446,9 @@ def test_setitem_different_tz_raises(self): # pre-2.0 we required exact tz match, in 2.0 we require only # tzawareness-match data = np.array([1, 2, 3], dtype="M8[ns]") - arr = DatetimeArray(data, copy=False, dtype=DatetimeTZDtype(tz="US/Central")) + arr = DatetimeArray._from_sequence( + data, copy=False, dtype=DatetimeTZDtype(tz="US/Central") + ) with pytest.raises(TypeError, match="Cannot compare tz-naive and tz-aware"): arr[0] = pd.Timestamp("2000") @@ -455,7 +457,7 @@ def test_setitem_different_tz_raises(self): assert arr[0] == ts.tz_convert("US/Central") def test_setitem_clears_freq(self): - a = DatetimeArray(pd.date_range("2000", periods=2, freq="D", tz="US/Central")) + a = pd.date_range("2000", periods=2, freq="D", tz="US/Central")._data a[0] = pd.Timestamp("2000", tz="US/Central") assert a.freq is None @@ -477,7 +479,7 @@ def test_setitem_objects(self, obj): def test_repeat_preserves_tz(self): dti = pd.date_range("2000", periods=2, freq="D", tz="US/Central") - arr = DatetimeArray(dti) + arr = dti._data repeated = arr.repeat([1, 1]) @@ -487,7 +489,7 @@ def test_repeat_preserves_tz(self): def test_value_counts_preserves_tz(self): dti = pd.date_range("2000", periods=2, freq="D", tz="US/Central") - arr = DatetimeArray(dti).repeat([4, 3]) + arr = dti._data.repeat([4, 3]) result = arr.value_counts() @@ -502,7 +504,7 @@ def test_value_counts_preserves_tz(self): @pytest.mark.parametrize("method", ["pad", "backfill"]) def test_fillna_preserves_tz(self, method): dti = pd.date_range("2000-01-01", periods=5, freq="D", tz="US/Central") - arr = DatetimeArray(dti, copy=True) + arr = DatetimeArray._from_sequence(dti, copy=True) arr[2] = pd.NaT fill_val = dti[1] if method == "pad" else dti[3] @@ -561,7 +563,7 @@ def test_fillna_2d(self): def test_array_interface_tz(self): tz = "US/Central" - data = DatetimeArray(pd.date_range("2017", periods=2, tz=tz)) + data = pd.date_range("2017", periods=2, tz=tz)._data result = np.asarray(data) expected = np.array( @@ -584,7 +586,7 @@ def test_array_interface_tz(self): tm.assert_numpy_array_equal(result, expected) def test_array_interface(self): - data = DatetimeArray(pd.date_range("2017", periods=2)) + data = pd.date_range("2017", periods=2)._data expected = np.array( ["2017-01-01T00:00:00", "2017-01-02T00:00:00"], dtype="datetime64[ns]" ) @@ -602,7 +604,7 @@ def test_array_interface(self): @pytest.mark.parametrize("index", [True, False]) def test_searchsorted_different_tz(self, index): data = np.arange(10, dtype="i8") * 24 * 3600 * 10**9 - arr = DatetimeArray(data, freq="D").tz_localize("Asia/Tokyo") + arr = pd.DatetimeIndex(data, freq="D")._data.tz_localize("Asia/Tokyo") if index: arr = pd.Index(arr) @@ -617,7 +619,7 @@ def test_searchsorted_different_tz(self, index): @pytest.mark.parametrize("index", [True, False]) def test_searchsorted_tzawareness_compat(self, index): data = np.arange(10, dtype="i8") * 24 * 3600 * 10**9 - arr = DatetimeArray(data, freq="D") + arr = pd.DatetimeIndex(data, freq="D")._data if index: arr = pd.Index(arr) @@ -651,7 +653,7 @@ def test_searchsorted_tzawareness_compat(self, index): @pytest.mark.parametrize("index", [True, False]) def test_searchsorted_invalid_types(self, other, index): data = np.arange(10, dtype="i8") * 24 * 3600 * 10**9 - arr = DatetimeArray(data, freq="D") + arr = pd.DatetimeIndex(data, freq="D")._data if index: arr = pd.Index(arr) @@ -668,7 +670,7 @@ def test_shift_fill_value(self): dti = pd.date_range("2016-01-01", periods=3) dta = dti._data - expected = DatetimeArray(np.roll(dta._ndarray, 1)) + expected = DatetimeArray._from_sequence(np.roll(dta._ndarray, 1)) fv = dta[-1] for fill_value in [fv, fv.to_pydatetime(), fv.to_datetime64()]: @@ -741,7 +743,7 @@ def test_iter_zoneinfo_fold(self, tz): ) utc_vals *= 1_000_000_000 - dta = DatetimeArray(utc_vals).tz_localize("UTC").tz_convert(tz) + dta = DatetimeArray._from_sequence(utc_vals).tz_localize("UTC").tz_convert(tz) left = dta[2] right = list(dta)[2] diff --git a/pandas/tests/arrays/test_timedeltas.py b/pandas/tests/arrays/test_timedeltas.py index 3f5ee328bdfcf8..a3f15467feb144 100644 --- a/pandas/tests/arrays/test_timedeltas.py +++ b/pandas/tests/arrays/test_timedeltas.py @@ -210,7 +210,7 @@ def test_astype_int(self, dtype): tm.assert_numpy_array_equal(result, expected) def test_setitem_clears_freq(self): - a = TimedeltaArray(pd.timedelta_range("1h", periods=2, freq="h")) + a = pd.timedelta_range("1h", periods=2, freq="h")._data a[0] = Timedelta("1h") assert a.freq is None @@ -225,7 +225,7 @@ def test_setitem_clears_freq(self): def test_setitem_objects(self, obj): # make sure we accept timedelta64 and timedelta in addition to Timedelta tdi = pd.timedelta_range("2 Days", periods=4, freq="h") - arr = TimedeltaArray(tdi, freq=tdi.freq) + arr = tdi._data arr[0] = obj assert arr[0] == Timedelta(seconds=1) @@ -247,7 +247,7 @@ def test_setitem_objects(self, obj): @pytest.mark.parametrize("index", [True, False]) def test_searchsorted_invalid_types(self, other, index): data = np.arange(10, dtype="i8") * 24 * 3600 * 10**9 - arr = TimedeltaArray(data, freq="D") + arr = pd.TimedeltaIndex(data, freq="D")._data if index: arr = pd.Index(arr) @@ -264,10 +264,10 @@ def test_searchsorted_invalid_types(self, other, index): class TestUnaryOps: def test_abs(self): vals = np.array([-3600 * 10**9, "NaT", 7200 * 10**9], dtype="m8[ns]") - arr = TimedeltaArray(vals) + arr = TimedeltaArray._from_sequence(vals) evals = np.array([3600 * 10**9, "NaT", 7200 * 10**9], dtype="m8[ns]") - expected = TimedeltaArray(evals) + expected = TimedeltaArray._from_sequence(evals) result = abs(arr) tm.assert_timedelta_array_equal(result, expected) @@ -277,7 +277,7 @@ def test_abs(self): def test_pos(self): vals = np.array([-3600 * 10**9, "NaT", 7200 * 10**9], dtype="m8[ns]") - arr = TimedeltaArray(vals) + arr = TimedeltaArray._from_sequence(vals) result = +arr tm.assert_timedelta_array_equal(result, arr) @@ -289,10 +289,10 @@ def test_pos(self): def test_neg(self): vals = np.array([-3600 * 10**9, "NaT", 7200 * 10**9], dtype="m8[ns]") - arr = TimedeltaArray(vals) + arr = TimedeltaArray._from_sequence(vals) evals = np.array([3600 * 10**9, "NaT", -7200 * 10**9], dtype="m8[ns]") - expected = TimedeltaArray(evals) + expected = TimedeltaArray._from_sequence(evals) result = -arr tm.assert_timedelta_array_equal(result, expected) @@ -302,9 +302,9 @@ def test_neg(self): def test_neg_freq(self): tdi = pd.timedelta_range("2 Days", periods=4, freq="h") - arr = TimedeltaArray(tdi, freq=tdi.freq) + arr = tdi._data - expected = TimedeltaArray(-tdi._data, freq=-tdi.freq) + expected = -tdi._data result = -arr tm.assert_timedelta_array_equal(result, expected) diff --git a/pandas/tests/arrays/timedeltas/test_constructors.py b/pandas/tests/arrays/timedeltas/test_constructors.py index 30894becc35cfa..91b6f7fa222f9a 100644 --- a/pandas/tests/arrays/timedeltas/test_constructors.py +++ b/pandas/tests/arrays/timedeltas/test_constructors.py @@ -1,6 +1,7 @@ import numpy as np import pytest +import pandas._testing as tm from pandas.core.arrays import TimedeltaArray @@ -9,13 +10,16 @@ def test_only_1dim_accepted(self): # GH#25282 arr = np.array([0, 1, 2, 3], dtype="m8[h]").astype("m8[ns]") - with pytest.raises(ValueError, match="Only 1-dimensional"): - # 3-dim, we allow 2D to sneak in for ops purposes GH#29853 - TimedeltaArray(arr.reshape(2, 2, 1)) + depr_msg = "TimedeltaArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Only 1-dimensional"): + # 3-dim, we allow 2D to sneak in for ops purposes GH#29853 + TimedeltaArray(arr.reshape(2, 2, 1)) - with pytest.raises(ValueError, match="Only 1-dimensional"): - # 0-dim - TimedeltaArray(arr[[0]].squeeze()) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="Only 1-dimensional"): + # 0-dim + TimedeltaArray(arr[[0]].squeeze()) def test_freq_validation(self): # ensure that the public constructor cannot create an invalid instance @@ -25,54 +29,71 @@ def test_freq_validation(self): "Inferred frequency None from passed values does not " "conform to passed frequency D" ) - with pytest.raises(ValueError, match=msg): - TimedeltaArray(arr.view("timedelta64[ns]"), freq="D") + depr_msg = "TimedeltaArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match=msg): + TimedeltaArray(arr.view("timedelta64[ns]"), freq="D") def test_non_array_raises(self): - with pytest.raises(ValueError, match="list"): - TimedeltaArray([1, 2, 3]) + depr_msg = "TimedeltaArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match="list"): + TimedeltaArray([1, 2, 3]) def test_other_type_raises(self): - msg = "dtype 'bool' is invalid, should be np.timedelta64 dtype" - with pytest.raises(ValueError, match=msg): - TimedeltaArray(np.array([1, 2, 3], dtype="bool")) + msg = r"dtype bool cannot be converted to timedelta64\[ns\]" + with pytest.raises(TypeError, match=msg): + TimedeltaArray._from_sequence(np.array([1, 2, 3], dtype="bool")) def test_incorrect_dtype_raises(self): msg = "dtype 'category' is invalid, should be np.timedelta64 dtype" with pytest.raises(ValueError, match=msg): - TimedeltaArray(np.array([1, 2, 3], dtype="i8"), dtype="category") + TimedeltaArray._from_sequence( + np.array([1, 2, 3], dtype="i8"), dtype="category" + ) msg = "dtype 'int64' is invalid, should be np.timedelta64 dtype" with pytest.raises(ValueError, match=msg): - TimedeltaArray(np.array([1, 2, 3], dtype="i8"), dtype=np.dtype("int64")) + TimedeltaArray._from_sequence( + np.array([1, 2, 3], dtype="i8"), dtype=np.dtype("int64") + ) msg = r"dtype 'datetime64\[ns\]' is invalid, should be np.timedelta64 dtype" with pytest.raises(ValueError, match=msg): - TimedeltaArray(np.array([1, 2, 3], dtype="i8"), dtype=np.dtype("M8[ns]")) + TimedeltaArray._from_sequence( + np.array([1, 2, 3], dtype="i8"), dtype=np.dtype("M8[ns]") + ) msg = ( r"dtype 'datetime64\[us, UTC\]' is invalid, should be np.timedelta64 dtype" ) with pytest.raises(ValueError, match=msg): - TimedeltaArray(np.array([1, 2, 3], dtype="i8"), dtype="M8[us, UTC]") + TimedeltaArray._from_sequence( + np.array([1, 2, 3], dtype="i8"), dtype="M8[us, UTC]" + ) msg = "Supported timedelta64 resolutions are 's', 'ms', 'us', 'ns'" with pytest.raises(ValueError, match=msg): - TimedeltaArray(np.array([1, 2, 3], dtype="i8"), dtype=np.dtype("m8[Y]")) + TimedeltaArray._from_sequence( + np.array([1, 2, 3], dtype="i8"), dtype=np.dtype("m8[Y]") + ) def test_mismatched_values_dtype_units(self): arr = np.array([1, 2, 3], dtype="m8[s]") dtype = np.dtype("m8[ns]") msg = r"Values resolution does not match dtype" - with pytest.raises(ValueError, match=msg): - TimedeltaArray(arr, dtype=dtype) + depr_msg = "TimedeltaArray.__init__ is deprecated" + + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + with pytest.raises(ValueError, match=msg): + TimedeltaArray(arr, dtype=dtype) def test_copy(self): data = np.array([1, 2, 3], dtype="m8[ns]") - arr = TimedeltaArray(data, copy=False) + arr = TimedeltaArray._from_sequence(data, copy=False) assert arr._ndarray is data - arr = TimedeltaArray(data, copy=True) + arr = TimedeltaArray._from_sequence(data, copy=True) assert arr._ndarray is not data assert arr._ndarray.base is not data diff --git a/pandas/tests/arrays/timedeltas/test_reductions.py b/pandas/tests/arrays/timedeltas/test_reductions.py index f1d2cc6a905198..991dbf41c80879 100644 --- a/pandas/tests/arrays/timedeltas/test_reductions.py +++ b/pandas/tests/arrays/timedeltas/test_reductions.py @@ -105,7 +105,7 @@ def test_sum_2d_skipna_false(self): arr = np.arange(8).astype(np.int64).view("m8[s]").astype("m8[ns]").reshape(4, 2) arr[-1, -1] = "Nat" - tda = TimedeltaArray(arr) + tda = TimedeltaArray._from_sequence(arr) result = tda.sum(skipna=False) assert result is pd.NaT diff --git a/pandas/tests/base/test_conversion.py b/pandas/tests/base/test_conversion.py index 3955e0e88e7769..fe0f1f1454a550 100644 --- a/pandas/tests/base/test_conversion.py +++ b/pandas/tests/base/test_conversion.py @@ -254,10 +254,13 @@ def test_numpy_array_all_dtypes(any_numpy_dtype): (pd.array([0, np.nan], dtype="Int64"), "_data"), (IntervalArray.from_breaks([0, 1]), "_left"), (SparseArray([0, 1]), "_sparse_values"), - (DatetimeArray(np.array([1, 2], dtype="datetime64[ns]")), "_ndarray"), + ( + DatetimeArray._from_sequence(np.array([1, 2], dtype="datetime64[ns]")), + "_ndarray", + ), # tz-aware Datetime ( - DatetimeArray( + DatetimeArray._from_sequence( np.array( ["2000-01-01T12:00:00", "2000-01-02T12:00:00"], dtype="M8[ns]" ), @@ -303,17 +306,16 @@ def test_array_multiindex_raises(): (SparseArray([0, 1]), np.array([0, 1], dtype=np.int64)), # tz-naive datetime ( - DatetimeArray(np.array(["2000", "2001"], dtype="M8[ns]")), + DatetimeArray._from_sequence(np.array(["2000", "2001"], dtype="M8[ns]")), np.array(["2000", "2001"], dtype="M8[ns]"), ), # tz-aware stays tz`-aware ( - DatetimeArray( - np.array( - ["2000-01-01T06:00:00", "2000-01-02T06:00:00"], dtype="M8[ns]" - ), - dtype=DatetimeTZDtype(tz="US/Central"), - ), + DatetimeArray._from_sequence( + np.array(["2000-01-01T06:00:00", "2000-01-02T06:00:00"], dtype="M8[ns]") + ) + .tz_localize("UTC") + .tz_convert("US/Central"), np.array( [ Timestamp("2000-01-01", tz="US/Central"), @@ -323,8 +325,8 @@ def test_array_multiindex_raises(): ), # Timedelta ( - TimedeltaArray( - np.array([0, 3600000000000], dtype="i8").view("m8[ns]"), freq="h" + TimedeltaArray._from_sequence( + np.array([0, 3600000000000], dtype="i8").view("m8[ns]") ), np.array([0, 3600000000000], dtype="m8[ns]"), ), diff --git a/pandas/tests/dtypes/test_generic.py b/pandas/tests/dtypes/test_generic.py index 3da3237370e602..02c827853b29dc 100644 --- a/pandas/tests/dtypes/test_generic.py +++ b/pandas/tests/dtypes/test_generic.py @@ -19,8 +19,9 @@ class TestABCClasses: categorical_df = pd.DataFrame({"values": [1, 2, 3]}, index=categorical) df = pd.DataFrame({"names": ["a", "b", "c"]}, index=multi_index) sparse_array = pd.arrays.SparseArray(np.random.default_rng(2).standard_normal(10)) - datetime_array = pd.core.arrays.DatetimeArray(datetime_index) - timedelta_array = pd.core.arrays.TimedeltaArray(timedelta_index) + + datetime_array = pd.core.arrays.DatetimeArray._from_sequence(datetime_index) + timedelta_array = pd.core.arrays.TimedeltaArray._from_sequence(timedelta_index) abc_pairs = [ ("ABCMultiIndex", multi_index), diff --git a/pandas/tests/extension/test_datetime.py b/pandas/tests/extension/test_datetime.py index efb88dc7bd4e12..7f70957007dad9 100644 --- a/pandas/tests/extension/test_datetime.py +++ b/pandas/tests/extension/test_datetime.py @@ -31,13 +31,15 @@ def dtype(request): @pytest.fixture def data(dtype): - data = DatetimeArray(pd.date_range("2000", periods=100, tz=dtype.tz), dtype=dtype) + data = DatetimeArray._from_sequence( + pd.date_range("2000", periods=100, tz=dtype.tz), dtype=dtype + ) return data @pytest.fixture def data_missing(dtype): - return DatetimeArray( + return DatetimeArray._from_sequence( np.array(["NaT", "2000-01-01"], dtype="datetime64[ns]"), dtype=dtype ) @@ -47,14 +49,18 @@ def data_for_sorting(dtype): a = pd.Timestamp("2000-01-01") b = pd.Timestamp("2000-01-02") c = pd.Timestamp("2000-01-03") - return DatetimeArray(np.array([b, c, a], dtype="datetime64[ns]"), dtype=dtype) + return DatetimeArray._from_sequence( + np.array([b, c, a], dtype="datetime64[ns]"), dtype=dtype + ) @pytest.fixture def data_missing_for_sorting(dtype): a = pd.Timestamp("2000-01-01") b = pd.Timestamp("2000-01-02") - return DatetimeArray(np.array([b, "NaT", a], dtype="datetime64[ns]"), dtype=dtype) + return DatetimeArray._from_sequence( + np.array([b, "NaT", a], dtype="datetime64[ns]"), dtype=dtype + ) @pytest.fixture @@ -68,7 +74,7 @@ def data_for_grouping(dtype): b = pd.Timestamp("2000-01-02") c = pd.Timestamp("2000-01-03") na = "NaT" - return DatetimeArray( + return DatetimeArray._from_sequence( np.array([b, b, na, na, a, a, b, c], dtype="datetime64[ns]"), dtype=dtype ) diff --git a/pandas/tests/indexes/datetimes/test_constructors.py b/pandas/tests/indexes/datetimes/test_constructors.py index 15597ecad6aeaa..2abbcf6688833f 100644 --- a/pandas/tests/indexes/datetimes/test_constructors.py +++ b/pandas/tests/indexes/datetimes/test_constructors.py @@ -31,10 +31,7 @@ to_datetime, ) import pandas._testing as tm -from pandas.core.arrays import ( - DatetimeArray, - period_array, -) +from pandas.core.arrays import period_array class TestDatetimeIndex: @@ -1112,9 +1109,6 @@ def test_explicit_none_freq(self): result = DatetimeIndex(rng._data, freq=None) assert result.freq is None - dta = DatetimeArray(rng, freq=None) - assert dta.freq is None - def test_dti_constructor_small_int(self, any_int_numpy_dtype): # see gh-13721 exp = DatetimeIndex( diff --git a/pandas/tests/indexes/timedeltas/test_constructors.py b/pandas/tests/indexes/timedeltas/test_constructors.py index abf7e093fd6cd6..0510700bb64d7a 100644 --- a/pandas/tests/indexes/timedeltas/test_constructors.py +++ b/pandas/tests/indexes/timedeltas/test_constructors.py @@ -70,6 +70,7 @@ def test_infer_from_tdi_mismatch(self): # has one and it does not match the `freq` input tdi = timedelta_range("1 second", periods=100, freq="1s") + depr_msg = "TimedeltaArray.__init__ is deprecated" msg = ( "Inferred frequency .* from passed values does " "not conform to passed frequency" @@ -79,13 +80,15 @@ def test_infer_from_tdi_mismatch(self): with pytest.raises(ValueError, match=msg): # GH#23789 - TimedeltaArray(tdi, freq="D") + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + TimedeltaArray(tdi, freq="D") with pytest.raises(ValueError, match=msg): TimedeltaIndex(tdi._data, freq="D") with pytest.raises(ValueError, match=msg): - TimedeltaArray(tdi._data, freq="D") + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + TimedeltaArray(tdi._data, freq="D") def test_dt64_data_invalid(self): # GH#23539 @@ -270,7 +273,9 @@ def test_explicit_none_freq(self): result = TimedeltaIndex(tdi._data, freq=None) assert result.freq is None - tda = TimedeltaArray(tdi, freq=None) + msg = "TimedeltaArray.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + tda = TimedeltaArray(tdi, freq=None) assert tda.freq is None def test_from_categorical(self): diff --git a/pandas/tests/reductions/test_stat_reductions.py b/pandas/tests/reductions/test_stat_reductions.py index a94ed0e044598d..8fbb78737474c8 100644 --- a/pandas/tests/reductions/test_stat_reductions.py +++ b/pandas/tests/reductions/test_stat_reductions.py @@ -13,15 +13,10 @@ date_range, ) import pandas._testing as tm -from pandas.core.arrays import ( - DatetimeArray, - PeriodArray, - TimedeltaArray, -) class TestDatetimeLikeStatReductions: - @pytest.mark.parametrize("box", [Series, pd.Index, DatetimeArray]) + @pytest.mark.parametrize("box", [Series, pd.Index, pd.array]) def test_dt64_mean(self, tz_naive_fixture, box): tz = tz_naive_fixture @@ -41,7 +36,7 @@ def test_dt64_mean(self, tz_naive_fixture, box): assert obj.mean() == pd.Timestamp("2001-01-06 07:12:00", tz=tz) assert obj.mean(skipna=False) is pd.NaT - @pytest.mark.parametrize("box", [Series, pd.Index, PeriodArray]) + @pytest.mark.parametrize("box", [Series, pd.Index, pd.array]) @pytest.mark.parametrize("freq", ["s", "h", "D", "W", "B"]) def test_period_mean(self, box, freq): # GH#24757 @@ -67,7 +62,7 @@ def test_period_mean(self, box, freq): with pytest.raises(TypeError, match="ambiguous"): obj.mean(skipna=True) - @pytest.mark.parametrize("box", [Series, pd.Index, TimedeltaArray]) + @pytest.mark.parametrize("box", [Series, pd.Index, pd.array]) def test_td64_mean(self, box): m8values = np.array([0, 3, -2, -7, 1, 2, -1, 3, 5, -2, 4], "m8[D]") tdi = pd.TimedeltaIndex(m8values).as_unit("ns") diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py index 898a0272551903..51ce73ef54300c 100644 --- a/pandas/tests/test_downstream.py +++ b/pandas/tests/test_downstream.py @@ -304,7 +304,9 @@ def test_from_obscure_array(dtype, array_likes): cls = {"M8[ns]": DatetimeArray, "m8[ns]": TimedeltaArray}[dtype] - expected = cls(arr) + depr_msg = f"{cls.__name__}.__init__ is deprecated" + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + expected = cls(arr) result = cls._from_sequence(data, dtype=dtype) tm.assert_extension_array_equal(result, expected) diff --git a/pandas/tests/test_nanops.py b/pandas/tests/test_nanops.py index 632d9783c7f817..a50054f33f382e 100644 --- a/pandas/tests/test_nanops.py +++ b/pandas/tests/test_nanops.py @@ -14,7 +14,6 @@ ) import pandas._testing as tm from pandas.core import nanops -from pandas.core.arrays import DatetimeArray use_bn = nanops._USE_BOTTLENECK @@ -1113,17 +1112,13 @@ def test_nanmean(self, unit): dti = pd.date_range("2016-01-01", periods=3).as_unit(unit) expected = dti[1] - for obj in [dti, DatetimeArray(dti), Series(dti)]: - if isinstance(obj, Series): - obj = obj._values + for obj in [dti, dti._data]: result = nanops.nanmean(obj) assert result == expected dti2 = dti.insert(1, pd.NaT) - for obj in [dti2, DatetimeArray(dti2), Series(dti2)]: - if isinstance(obj, Series): - obj = obj._values + for obj in [dti2, dti2._data]: result = nanops.nanmean(obj) assert result == expected diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py index a23d2d3dc22af6..417a56dc074a64 100644 --- a/pandas/tests/tools/test_to_datetime.py +++ b/pandas/tests/tools/test_to_datetime.py @@ -991,7 +991,7 @@ def test_error_iso_week_year(self, msg, s, _format, errors): def test_to_datetime_dtarr(self, tz): # DatetimeArray dti = date_range("1965-04-03", periods=19, freq="2W", tz=tz) - arr = DatetimeArray(dti) + arr = dti._data result = to_datetime(arr) assert result is arr @@ -2822,7 +2822,7 @@ def test_dayfirst_warnings_invalid_input(self): ): to_datetime(arr, dayfirst=True) - @pytest.mark.parametrize("klass", [DatetimeIndex, DatetimeArray]) + @pytest.mark.parametrize("klass", [DatetimeIndex, DatetimeArray._from_sequence]) def test_to_datetime_dta_tz(self, klass): # GH#27733 dti = date_range("2015-04-05", periods=3).rename("foo")