Skip to content

Commit 8d8a69c

Browse files
jbrockmendelphofl
authored andcommitted
DEPR: datetimelike.astype(int_other_than_i8) return requested dtype (pandas-dev#45574)
1 parent 8a3a7b7 commit 8d8a69c

File tree

9 files changed

+87
-13
lines changed

9 files changed

+87
-13
lines changed

doc/source/whatsnew/v1.5.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ Other Deprecations
238238
- Deprecated behavior of :meth:`DatetimeIndex.intersection` and :meth:`DatetimeIndex.symmetric_difference` (``union`` behavior was already deprecated in version 1.3.0) with mixed time zones; in a future version both will be cast to UTC instead of object dtype (:issue:`39328`, :issue:`45357`)
239239
- Deprecated :meth:`DataFrame.iteritems`, :meth:`Series.iteritems`, :meth:`HDFStore.iteritems` in favor of :meth:`DataFrame.items`, :meth:`Series.items`, :meth:`HDFStore.items` (:issue:`45321`)
240240
- Deprecated :meth:`Series.is_monotonic` and :meth:`Index.is_monotonic` in favor of :meth:`Series.is_monotonic_increasing` and :meth:`Index.is_monotonic_increasing` (:issue:`45422`, :issue:`21335`)
241+
- Deprecated behavior of :meth:`DatetimeIndex.astype`, :meth:`TimedeltaIndex.astype`, :meth:`PeriodIndex.astype` when converting to an integer dtype other than ``int64``. In a future version, these will convert to exactly the specified dtype (instead of always ``int64``) and will raise if the conversion overflows (:issue:`45034`)
241242
- Deprecated the ``__array_wrap__`` method of DataFrame and Series, rely on standard numpy ufuncs instead (:issue:`45451`)
242243
- Deprecated the behavior of :meth:`Series.fillna` and :meth:`DataFrame.fillna` with ``timedelta64[ns]`` dtype and incompatible fill value; in a future version this will cast to a common dtype (usually object) instead of raising, matching the behavior of other dtypes (:issue:`45746`)
243244
- Deprecated the ``warn`` parameter in :func:`infer_freq` (:issue:`45947`)

pandas/core/arrays/datetimelike.py

+30
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,36 @@ def astype(self, dtype, copy: bool = True):
446446
if is_unsigned_integer_dtype(dtype):
447447
# Again, we ignore int32 vs. int64
448448
values = values.view("uint64")
449+
if dtype != np.uint64:
450+
# GH#45034
451+
warnings.warn(
452+
f"The behavior of .astype from {self.dtype} to {dtype} is "
453+
"deprecated. In a future version, this astype will return "
454+
"exactly the specified dtype instead of uint64, and will "
455+
"raise if that conversion overflows.",
456+
FutureWarning,
457+
stacklevel=find_stack_level(),
458+
)
459+
elif (self.asi8 < 0).any():
460+
# GH#45034
461+
warnings.warn(
462+
f"The behavior of .astype from {self.dtype} to {dtype} is "
463+
"deprecated. In a future version, this astype will "
464+
"raise if the conversion overflows, as it did in this "
465+
"case with negative int64 values.",
466+
FutureWarning,
467+
stacklevel=find_stack_level(),
468+
)
469+
elif dtype != np.int64:
470+
# GH#45034
471+
warnings.warn(
472+
f"The behavior of .astype from {self.dtype} to {dtype} is "
473+
"deprecated. In a future version, this astype will return "
474+
"exactly the specified dtype instead of int64, and will "
475+
"raise if that conversion overflows.",
476+
FutureWarning,
477+
stacklevel=find_stack_level(),
478+
)
449479

450480
if copy:
451481
values = values.copy()

pandas/tests/arrays/period/test_astype.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,29 @@
99

1010

1111
@pytest.mark.parametrize("dtype", [int, np.int32, np.int64, "uint32", "uint64"])
12-
def test_astype(dtype):
12+
def test_astype_int(dtype):
1313
# We choose to ignore the sign and size of integers for
1414
# Period/Datetime/Timedelta astype
1515
arr = period_array(["2000", "2001", None], freq="D")
16-
result = arr.astype(dtype)
1716

1817
if np.dtype(dtype).kind == "u":
1918
expected_dtype = np.dtype("uint64")
19+
warn1 = FutureWarning
2020
else:
2121
expected_dtype = np.dtype("int64")
22-
23-
expected = arr.astype(expected_dtype)
22+
warn1 = None
23+
24+
msg_overflow = "will raise if the conversion overflows"
25+
with tm.assert_produces_warning(warn1, match=msg_overflow):
26+
expected = arr.astype(expected_dtype)
27+
28+
warn = None if dtype == expected_dtype else FutureWarning
29+
msg = " will return exactly the specified dtype"
30+
if warn is None and warn1 is not None:
31+
warn = warn1
32+
msg = msg_overflow
33+
with tm.assert_produces_warning(warn, match=msg):
34+
result = arr.astype(dtype)
2435

2536
assert result.dtype == expected_dtype
2637
tm.assert_numpy_array_equal(result, expected)

pandas/tests/arrays/test_datetimes.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,20 @@ def test_astype_copies(self, dtype, other):
7777
@pytest.mark.parametrize("dtype", [int, np.int32, np.int64, "uint32", "uint64"])
7878
def test_astype_int(self, dtype):
7979
arr = DatetimeArray._from_sequence([pd.Timestamp("2000"), pd.Timestamp("2001")])
80-
result = arr.astype(dtype)
8180

8281
if np.dtype(dtype).kind == "u":
8382
expected_dtype = np.dtype("uint64")
8483
else:
8584
expected_dtype = np.dtype("int64")
8685
expected = arr.astype(expected_dtype)
8786

87+
warn = None
88+
if dtype != expected_dtype:
89+
warn = FutureWarning
90+
msg = " will return exactly the specified dtype"
91+
with tm.assert_produces_warning(warn, match=msg):
92+
result = arr.astype(dtype)
93+
8894
assert result.dtype == expected_dtype
8995
tm.assert_numpy_array_equal(result, expected)
9096

pandas/tests/arrays/test_timedeltas.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,20 @@ class TestTimedeltaArray:
1111
@pytest.mark.parametrize("dtype", [int, np.int32, np.int64, "uint32", "uint64"])
1212
def test_astype_int(self, dtype):
1313
arr = TimedeltaArray._from_sequence([Timedelta("1H"), Timedelta("2H")])
14-
result = arr.astype(dtype)
1514

1615
if np.dtype(dtype).kind == "u":
1716
expected_dtype = np.dtype("uint64")
1817
else:
1918
expected_dtype = np.dtype("int64")
2019
expected = arr.astype(expected_dtype)
2120

21+
warn = None
22+
if dtype != expected_dtype:
23+
warn = FutureWarning
24+
msg = " will return exactly the specified dtype"
25+
with tm.assert_produces_warning(warn, match=msg):
26+
result = arr.astype(dtype)
27+
2228
assert result.dtype == expected_dtype
2329
tm.assert_numpy_array_equal(result, expected)
2430

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ def test_astype_uint(self):
5252
name="idx",
5353
)
5454
tm.assert_index_equal(arr.astype("uint64"), expected)
55-
tm.assert_index_equal(arr.astype("uint32"), expected)
55+
56+
msg = "will return exactly the specified dtype instead of uint64"
57+
with tm.assert_produces_warning(FutureWarning, match=msg):
58+
res = arr.astype("uint32")
59+
tm.assert_index_equal(res, expected)
5660

5761
def test_astype_with_tz(self):
5862

pandas/tests/indexes/interval/test_astype.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,18 @@ def index(self, request):
205205
@pytest.mark.parametrize("subtype", ["int64", "uint64"])
206206
def test_subtype_integer(self, index, subtype):
207207
dtype = IntervalDtype(subtype, "right")
208-
result = index.astype(dtype)
209-
expected = IntervalIndex.from_arrays(
210-
index.left.astype(subtype), index.right.astype(subtype), closed=index.closed
211-
)
208+
209+
warn = None
210+
if index.isna().any() and subtype == "uint64":
211+
warn = FutureWarning
212+
msg = "In a future version, this astype will raise if the conversion overflows"
213+
214+
with tm.assert_produces_warning(warn, match=msg):
215+
result = index.astype(dtype)
216+
new_left = index.left.astype(subtype)
217+
new_right = index.right.astype(subtype)
218+
219+
expected = IntervalIndex.from_arrays(new_left, new_right, closed=index.closed)
212220
tm.assert_index_equal(result, expected)
213221

214222
def test_subtype_float(self, index):

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ def test_astype_uint(self):
5858
arr = period_range("2000", periods=2, name="idx")
5959
expected = UInt64Index(np.array([10957, 10958], dtype="uint64"), name="idx")
6060
tm.assert_index_equal(arr.astype("uint64"), expected)
61-
tm.assert_index_equal(arr.astype("uint32"), expected)
61+
62+
msg = "will return exactly the specified dtype instead of uint64"
63+
with tm.assert_produces_warning(FutureWarning, match=msg):
64+
res = arr.astype("uint32")
65+
tm.assert_index_equal(res, expected)
6266

6367
def test_astype_object(self):
6468
idx = PeriodIndex([], freq="M")

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ def test_astype_uint(self):
7979
np.array([3600000000000, 90000000000000], dtype="uint64")
8080
)
8181
tm.assert_index_equal(arr.astype("uint64"), expected)
82-
tm.assert_index_equal(arr.astype("uint32"), expected)
82+
83+
msg = "will return exactly the specified dtype instead of uint64"
84+
with tm.assert_produces_warning(FutureWarning, match=msg):
85+
res = arr.astype("uint32")
86+
tm.assert_index_equal(res, expected)
8387

8488
def test_astype_timedelta64(self):
8589
# GH 13149, GH 13209

0 commit comments

Comments
 (0)