Skip to content

Commit 7db5f57

Browse files
authored
DEPR: datetimelike.astype(int) (#38544)
1 parent d388dcf commit 7db5f57

File tree

15 files changed

+122
-39
lines changed

15 files changed

+122
-39
lines changed

doc/source/whatsnew/v1.3.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ Deprecations
146146
~~~~~~~~~~~~
147147
- Deprecating allowing scalars passed to the :class:`Categorical` constructor (:issue:`38433`)
148148
- Deprecated allowing subclass-specific keyword arguments in the :class:`Index` constructor, use the specific subclass directly instead (:issue:`14093`,:issue:`21311`,:issue:`22315`,:issue:`26974`)
149+
- Deprecated ``astype`` of datetimelike (``timedelta64[ns]``, ``datetime64[ns]``, ``Datetime64TZDtype``, ``PeriodDtype``) to integer dtypes, use ``values.view(...)`` instead (:issue:`38544`)
149150
-
150151
-
151152

pandas/core/arrays/datetimelike.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,14 @@ def astype(self, dtype, copy=True):
352352
elif is_integer_dtype(dtype):
353353
# we deliberately ignore int32 vs. int64 here.
354354
# See https://github.com/pandas-dev/pandas/issues/24381 for more.
355+
warnings.warn(
356+
f"casting {self.dtype} values to int64 with .astype(...) is "
357+
"deprecated and will raise in a future version. "
358+
"Use .view(...) instead.",
359+
FutureWarning,
360+
stacklevel=3,
361+
)
362+
355363
values = self.asi8
356364

357365
if is_unsigned_integer_dtype(dtype):

pandas/core/dtypes/cast.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""
22
Routines for casting.
33
"""
4-
54
from contextlib import suppress
65
from datetime import datetime, timedelta
76
from typing import (
@@ -17,6 +16,7 @@
1716
Type,
1817
Union,
1918
)
19+
import warnings
2020

2121
import numpy as np
2222

@@ -997,6 +997,14 @@ def astype_nansafe(
997997

998998
elif is_datetime64_dtype(arr):
999999
if dtype == np.int64:
1000+
warnings.warn(
1001+
f"casting {arr.dtype} values to int64 with .astype(...) "
1002+
"is deprecated and will raise in a future version. "
1003+
"Use .view(...) instead.",
1004+
FutureWarning,
1005+
# stacklevel chosen to be correct when reached via Series.astype
1006+
stacklevel=7,
1007+
)
10001008
if isna(arr).any():
10011009
raise ValueError("Cannot convert NaT values to integer")
10021010
return arr.view(dtype)
@@ -1009,6 +1017,14 @@ def astype_nansafe(
10091017

10101018
elif is_timedelta64_dtype(arr):
10111019
if dtype == np.int64:
1020+
warnings.warn(
1021+
f"casting {arr.dtype} values to int64 with .astype(...) "
1022+
"is deprecated and will raise in a future version. "
1023+
"Use .view(...) instead.",
1024+
FutureWarning,
1025+
# stacklevel chosen to be correct when reached via Series.astype
1026+
stacklevel=7,
1027+
)
10121028
if isna(arr).any():
10131029
raise ValueError("Cannot convert NaT values to integer")
10141030
return arr.view(dtype)

pandas/tests/arrays/test_datetimes.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,18 @@ def test_astype_copies(self, dtype, other):
184184
@pytest.mark.parametrize("dtype", [int, np.int32, np.int64, "uint32", "uint64"])
185185
def test_astype_int(self, dtype):
186186
arr = DatetimeArray._from_sequence([pd.Timestamp("2000"), pd.Timestamp("2001")])
187-
result = arr.astype(dtype)
187+
with tm.assert_produces_warning(FutureWarning):
188+
# astype(int..) deprecated
189+
result = arr.astype(dtype)
188190

189191
if np.dtype(dtype).kind == "u":
190192
expected_dtype = np.dtype("uint64")
191193
else:
192194
expected_dtype = np.dtype("int64")
193-
expected = arr.astype(expected_dtype)
195+
196+
with tm.assert_produces_warning(FutureWarning):
197+
# astype(int..) deprecated
198+
expected = arr.astype(expected_dtype)
194199

195200
assert result.dtype == expected_dtype
196201
tm.assert_numpy_array_equal(result, expected)

pandas/tests/arrays/test_period.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,26 +123,36 @@ def test_astype(dtype):
123123
# We choose to ignore the sign and size of integers for
124124
# Period/Datetime/Timedelta astype
125125
arr = period_array(["2000", "2001", None], freq="D")
126-
result = arr.astype(dtype)
126+
with tm.assert_produces_warning(FutureWarning):
127+
# astype(int..) deprecated
128+
result = arr.astype(dtype)
127129

128130
if np.dtype(dtype).kind == "u":
129131
expected_dtype = np.dtype("uint64")
130132
else:
131133
expected_dtype = np.dtype("int64")
132-
expected = arr.astype(expected_dtype)
134+
135+
with tm.assert_produces_warning(FutureWarning):
136+
# astype(int..) deprecated
137+
expected = arr.astype(expected_dtype)
133138

134139
assert result.dtype == expected_dtype
135140
tm.assert_numpy_array_equal(result, expected)
136141

137142

138143
def test_astype_copies():
139144
arr = period_array(["2000", "2001", None], freq="D")
140-
result = arr.astype(np.int64, copy=False)
145+
with tm.assert_produces_warning(FutureWarning):
146+
# astype(int..) deprecated
147+
result = arr.astype(np.int64, copy=False)
148+
141149
# Add the `.base`, since we now use `.asi8` which returns a view.
142150
# We could maybe override it in PeriodArray to return ._data directly.
143151
assert result.base is arr._data
144152

145-
result = arr.astype(np.int64, copy=True)
153+
with tm.assert_produces_warning(FutureWarning):
154+
# astype(int..) deprecated
155+
result = arr.astype(np.int64, copy=True)
146156
assert result is not arr._data
147157
tm.assert_numpy_array_equal(result, arr._data.view("i8"))
148158

pandas/tests/arrays/test_timedeltas.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,18 @@ def test_from_sequence_dtype(self):
8282
@pytest.mark.parametrize("dtype", [int, np.int32, np.int64, "uint32", "uint64"])
8383
def test_astype_int(self, dtype):
8484
arr = TimedeltaArray._from_sequence([Timedelta("1H"), Timedelta("2H")])
85-
result = arr.astype(dtype)
85+
with tm.assert_produces_warning(FutureWarning):
86+
# astype(int..) deprecated
87+
result = arr.astype(dtype)
8688

8789
if np.dtype(dtype).kind == "u":
8890
expected_dtype = np.dtype("uint64")
8991
else:
9092
expected_dtype = np.dtype("int64")
91-
expected = arr.astype(expected_dtype)
93+
94+
with tm.assert_produces_warning(FutureWarning):
95+
# astype(int..) deprecated
96+
expected = arr.astype(expected_dtype)
9297

9398
assert result.dtype == expected_dtype
9499
tm.assert_numpy_array_equal(result, expected)

pandas/tests/dtypes/test_common.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,9 @@ def test_astype_nansafe(val, typ):
719719

720720
msg = "Cannot convert NaT values to integer"
721721
with pytest.raises(ValueError, match=msg):
722-
astype_nansafe(arr, dtype=typ)
722+
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
723+
# datetimelike astype(int64) deprecated
724+
astype_nansafe(arr, dtype=typ)
723725

724726

725727
@pytest.mark.parametrize("from_type", [np.datetime64, np.timedelta64])

pandas/tests/indexes/datetimes/methods/test_astype.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def test_astype(self):
2929
)
3030
tm.assert_index_equal(result, expected)
3131

32-
result = idx.astype(int)
32+
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
33+
result = idx.astype(int)
3334
expected = Int64Index(
3435
[1463356800000000000] + [-9223372036854775808] * 3,
3536
dtype=np.int64,
@@ -38,7 +39,8 @@ def test_astype(self):
3839
tm.assert_index_equal(result, expected)
3940

4041
rng = date_range("1/1/2000", periods=10, name="idx")
41-
result = rng.astype("i8")
42+
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
43+
result = rng.astype("i8")
4244
tm.assert_index_equal(result, Index(rng.asi8, name="idx"))
4345
tm.assert_numpy_array_equal(result.values, rng.asi8)
4446

@@ -48,9 +50,9 @@ def test_astype_uint(self):
4850
np.array([946684800000000000, 946771200000000000], dtype="uint64"),
4951
name="idx",
5052
)
51-
52-
tm.assert_index_equal(arr.astype("uint64"), expected)
53-
tm.assert_index_equal(arr.astype("uint32"), expected)
53+
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
54+
tm.assert_index_equal(arr.astype("uint64"), expected)
55+
tm.assert_index_equal(arr.astype("uint32"), expected)
5456

5557
def test_astype_with_tz(self):
5658

pandas/tests/indexes/interval/test_astype.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,13 @@ def index(self, request):
197197
@pytest.mark.parametrize("subtype", ["int64", "uint64"])
198198
def test_subtype_integer(self, index, subtype):
199199
dtype = IntervalDtype(subtype)
200-
result = index.astype(dtype)
201-
expected = IntervalIndex.from_arrays(
202-
index.left.astype(subtype), index.right.astype(subtype), closed=index.closed
203-
)
200+
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
201+
result = index.astype(dtype)
202+
expected = IntervalIndex.from_arrays(
203+
index.left.astype(subtype),
204+
index.right.astype(subtype),
205+
closed=index.closed,
206+
)
204207
tm.assert_index_equal(result, expected)
205208

206209
def test_subtype_float(self, index):

pandas/tests/indexes/interval/test_constructors.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,21 @@ def test_constructor(self, constructor, breaks, closed, name):
7272
)
7373
def test_constructor_dtype(self, constructor, breaks, subtype):
7474
# GH 19262: conversion via dtype parameter
75-
expected_kwargs = self.get_kwargs_from_breaks(breaks.astype(subtype))
75+
warn = None
76+
if subtype == "int64" and breaks.dtype.kind in ["M", "m"]:
77+
# astype(int64) deprecated
78+
warn = FutureWarning
79+
80+
with tm.assert_produces_warning(warn, check_stacklevel=False):
81+
expected_kwargs = self.get_kwargs_from_breaks(breaks.astype(subtype))
7682
expected = constructor(**expected_kwargs)
7783

7884
result_kwargs = self.get_kwargs_from_breaks(breaks)
7985
iv_dtype = IntervalDtype(subtype)
8086
for dtype in (iv_dtype, str(iv_dtype)):
81-
result = constructor(dtype=dtype, **result_kwargs)
87+
with tm.assert_produces_warning(warn, check_stacklevel=False):
88+
89+
result = constructor(dtype=dtype, **result_kwargs)
8290
tm.assert_index_equal(result, expected)
8391

8492
@pytest.mark.filterwarnings("ignore:Passing keywords other:FutureWarning")

0 commit comments

Comments
 (0)