Skip to content

Commit 279138c

Browse files
API: dtlike.astype(inty) (#49715)
* API: dtlike.astype(inty) * Update doc/source/whatsnew/v2.0.0.rst Co-authored-by: Matthew Roeschke <[email protected]> * int->int64 Co-authored-by: Matthew Roeschke <[email protected]>
1 parent 710b83b commit 279138c

File tree

11 files changed

+55
-138
lines changed

11 files changed

+55
-138
lines changed

doc/source/whatsnew/v2.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ Other API changes
515515
- Default value of ``dtype`` in :func:`get_dummies` is changed to ``bool`` from ``uint8`` (:issue:`45848`)
516516
- :meth:`DataFrame.astype`, :meth:`Series.astype`, and :meth:`DatetimeIndex.astype` casting datetime64 data to any of "datetime64[s]", "datetime64[ms]", "datetime64[us]" will return an object with the given resolution instead of coercing back to "datetime64[ns]" (:issue:`48928`)
517517
- :meth:`DataFrame.astype`, :meth:`Series.astype`, and :meth:`DatetimeIndex.astype` casting timedelta64 data to any of "timedelta64[s]", "timedelta64[ms]", "timedelta64[us]" will return an object with the given resolution instead of coercing to "float64" dtype (:issue:`48963`)
518+
- :meth:`DatetimeIndex.astype`, :meth:`TimedeltaIndex.astype`, :meth:`PeriodIndex.astype` :meth:`Series.astype`, :meth:`DataFrame.astype` with ``datetime64``, ``timedelta64`` or :class:`PeriodDtype` dtypes no longer allow converting to integer dtypes other than "int64", do ``obj.astype('int64', copy=False).astype(dtype)`` instead (:issue:`49715`)
518519
- :meth:`Index.astype` now allows casting from ``float64`` dtype to datetime-like dtypes, matching :class:`Series` behavior (:issue:`49660`)
519520
- Passing data with dtype of "timedelta64[s]", "timedelta64[ms]", or "timedelta64[us]" to :class:`TimedeltaIndex`, :class:`Series`, or :class:`DataFrame` constructors will now retain that dtype instead of casting to "timedelta64[ns]"; timedelta64 data with lower resolution will be cast to the lowest supported resolution "timedelta64[s]" (:issue:`49014`)
520521
- Passing ``dtype`` of "timedelta64[s]", "timedelta64[ms]", or "timedelta64[us]" to :class:`TimedeltaIndex`, :class:`Series`, or :class:`DataFrame` constructors will now retain that dtype instead of casting to "timedelta64[ns]"; passing a dtype with lower resolution for :class:`Series` or :class:`DataFrame` will be cast to the lowest supported resolution "timedelta64[s]" (:issue:`49014`)

pandas/core/arrays/datetimelike.py

+4-34
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696
is_period_dtype,
9797
is_string_dtype,
9898
is_timedelta64_dtype,
99-
is_unsigned_integer_dtype,
10099
pandas_dtype,
101100
)
102101
from pandas.core.dtypes.dtypes import (
@@ -468,39 +467,10 @@ def astype(self, dtype, copy: bool = True):
468467
# we deliberately ignore int32 vs. int64 here.
469468
# See https://github.com/pandas-dev/pandas/issues/24381 for more.
470469
values = self.asi8
471-
472-
if is_unsigned_integer_dtype(dtype):
473-
# Again, we ignore int32 vs. int64
474-
values = values.view("uint64")
475-
if dtype != np.uint64:
476-
# GH#45034
477-
warnings.warn(
478-
f"The behavior of .astype from {self.dtype} to {dtype} is "
479-
"deprecated. In a future version, this astype will return "
480-
"exactly the specified dtype instead of uint64, and will "
481-
"raise if that conversion overflows.",
482-
FutureWarning,
483-
stacklevel=find_stack_level(),
484-
)
485-
elif (self.asi8 < 0).any():
486-
# GH#45034
487-
warnings.warn(
488-
f"The behavior of .astype from {self.dtype} to {dtype} is "
489-
"deprecated. In a future version, this astype will "
490-
"raise if the conversion overflows, as it did in this "
491-
"case with negative int64 values.",
492-
FutureWarning,
493-
stacklevel=find_stack_level(),
494-
)
495-
elif dtype != np.int64:
496-
# GH#45034
497-
warnings.warn(
498-
f"The behavior of .astype from {self.dtype} to {dtype} is "
499-
"deprecated. In a future version, this astype will return "
500-
"exactly the specified dtype instead of int64, and will "
501-
"raise if that conversion overflows.",
502-
FutureWarning,
503-
stacklevel=find_stack_level(),
470+
if dtype != np.int64:
471+
raise TypeError(
472+
f"Converting from {self.dtype} to {dtype} is not supported. "
473+
"Do obj.astype('int64').astype(dtype) instead"
504474
)
505475

506476
if copy:

pandas/core/dtypes/astype.py

-10
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,6 @@ def astype_array(values: ArrayLike, dtype: DtypeObj, copy: bool = False) -> Arra
171171
-------
172172
ndarray or ExtensionArray
173173
"""
174-
if (
175-
values.dtype.kind in ["m", "M"]
176-
and dtype.kind in ["i", "u"]
177-
and isinstance(dtype, np.dtype)
178-
and dtype.itemsize != 8
179-
):
180-
# TODO(2.0) remove special case once deprecation on DTA/TDA is enforced
181-
msg = rf"cannot astype a datetimelike from [{values.dtype}] to [{dtype}]"
182-
raise TypeError(msg)
183-
184174
if is_dtype_equal(values.dtype, dtype):
185175
if copy:
186176
return values.copy()

pandas/tests/arrays/period/test_astype.py

+7-20
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,13 @@ def test_astype_int(dtype):
1414
# Period/Datetime/Timedelta astype
1515
arr = period_array(["2000", "2001", None], freq="D")
1616

17-
if np.dtype(dtype).kind == "u":
18-
expected_dtype = np.dtype("uint64")
19-
warn1 = FutureWarning
20-
else:
21-
expected_dtype = np.dtype("int64")
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)
35-
36-
assert result.dtype == expected_dtype
17+
if np.dtype(dtype) != np.int64:
18+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
19+
arr.astype(dtype)
20+
return
21+
22+
result = arr.astype(dtype)
23+
expected = arr._ndarray.view("i8")
3724
tm.assert_numpy_array_equal(result, expected)
3825

3926

pandas/tests/arrays/test_datetimes.py

+6-13
Original file line numberDiff line numberDiff line change
@@ -377,20 +377,13 @@ def test_astype_copies(self, dtype, other):
377377
def test_astype_int(self, dtype):
378378
arr = DatetimeArray._from_sequence([pd.Timestamp("2000"), pd.Timestamp("2001")])
379379

380-
if np.dtype(dtype).kind == "u":
381-
expected_dtype = np.dtype("uint64")
382-
else:
383-
expected_dtype = np.dtype("int64")
384-
expected = arr.astype(expected_dtype)
385-
386-
warn = None
387-
if dtype != expected_dtype:
388-
warn = FutureWarning
389-
msg = " will return exactly the specified dtype"
390-
with tm.assert_produces_warning(warn, match=msg):
391-
result = arr.astype(dtype)
380+
if np.dtype(dtype) != np.int64:
381+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
382+
arr.astype(dtype)
383+
return
392384

393-
assert result.dtype == expected_dtype
385+
result = arr.astype(dtype)
386+
expected = arr._ndarray.view("i8")
394387
tm.assert_numpy_array_equal(result, expected)
395388

396389
def test_astype_to_sparse_dt64(self):

pandas/tests/arrays/test_timedeltas.py

+7-14
Original file line numberDiff line numberDiff line change
@@ -190,20 +190,13 @@ class TestTimedeltaArray:
190190
def test_astype_int(self, dtype):
191191
arr = TimedeltaArray._from_sequence([Timedelta("1H"), Timedelta("2H")])
192192

193-
if np.dtype(dtype).kind == "u":
194-
expected_dtype = np.dtype("uint64")
195-
else:
196-
expected_dtype = np.dtype("int64")
197-
expected = arr.astype(expected_dtype)
198-
199-
warn = None
200-
if dtype != expected_dtype:
201-
warn = FutureWarning
202-
msg = " will return exactly the specified dtype"
203-
with tm.assert_produces_warning(warn, match=msg):
204-
result = arr.astype(dtype)
205-
206-
assert result.dtype == expected_dtype
193+
if np.dtype(dtype) != np.int64:
194+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
195+
arr.astype(dtype)
196+
return
197+
198+
result = arr.astype(dtype)
199+
expected = arr._ndarray.view("i8")
207200
tm.assert_numpy_array_equal(result, expected)
208201

209202
def test_setitem_clears_freq(self):

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

+5-13
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
date_range,
1616
)
1717
import pandas._testing as tm
18-
from pandas.core.api import (
19-
Int64Index,
20-
UInt64Index,
21-
)
18+
from pandas.core.api import Int64Index
2219

2320

2421
class TestDatetimeIndex:
@@ -47,16 +44,11 @@ def test_astype(self):
4744

4845
def test_astype_uint(self):
4946
arr = date_range("2000", periods=2, name="idx")
50-
expected = UInt64Index(
51-
np.array([946684800000000000, 946771200000000000], dtype="uint64"),
52-
name="idx",
53-
)
54-
tm.assert_index_equal(arr.astype("uint64"), expected)
5547

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)
48+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
49+
arr.astype("uint64")
50+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
51+
arr.astype("uint32")
6052

6153
def test_astype_with_tz(self):
6254

pandas/tests/indexes/interval/test_astype.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,18 @@ def index(self, request):
206206
def test_subtype_integer(self, index, subtype):
207207
dtype = IntervalDtype(subtype, "right")
208208

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)
209+
if subtype != "int64":
210+
msg = (
211+
r"Cannot convert interval\[(timedelta64|datetime64)\[ns.*\], .*\] "
212+
r"to interval\[uint64, .*\]"
213+
)
214+
with pytest.raises(TypeError, match=msg):
215+
index.astype(dtype)
216+
return
217+
218+
result = index.astype(dtype)
219+
new_left = index.left.astype(subtype)
220+
new_right = index.right.astype(subtype)
218221

219222
expected = IntervalIndex.from_arrays(new_left, new_right, closed=index.closed)
220223
tm.assert_index_equal(result, expected)

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

+5-10
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
period_range,
1212
)
1313
import pandas._testing as tm
14-
from pandas.core.indexes.api import (
15-
Int64Index,
16-
UInt64Index,
17-
)
14+
from pandas.core.indexes.api import Int64Index
1815

1916

2017
class TestPeriodIndexAsType:
@@ -55,13 +52,11 @@ def test_astype_conversion(self):
5552

5653
def test_astype_uint(self):
5754
arr = period_range("2000", periods=2, name="idx")
58-
expected = UInt64Index(np.array([10957, 10958], dtype="uint64"), name="idx")
59-
tm.assert_index_equal(arr.astype("uint64"), expected)
6055

61-
msg = "will return exactly the specified dtype instead of uint64"
62-
with tm.assert_produces_warning(FutureWarning, match=msg):
63-
res = arr.astype("uint32")
64-
tm.assert_index_equal(res, expected)
56+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
57+
arr.astype("uint64")
58+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
59+
arr.astype("uint32")
6560

6661
def test_astype_object(self):
6762
idx = PeriodIndex([], freq="M")

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

+6-13
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@
1212
timedelta_range,
1313
)
1414
import pandas._testing as tm
15-
from pandas.core.api import (
16-
Int64Index,
17-
UInt64Index,
18-
)
15+
from pandas.core.api import Int64Index
1916

2017

2118
class TestTimedeltaIndex:
@@ -57,7 +54,7 @@ def test_astype(self):
5754
)
5855
tm.assert_index_equal(result, expected)
5956

60-
result = idx.astype(int)
57+
result = idx.astype(np.int64)
6158
expected = Int64Index(
6259
[100000000000000] + [-9223372036854775808] * 3, dtype=np.int64, name="idx"
6360
)
@@ -74,15 +71,11 @@ def test_astype(self):
7471

7572
def test_astype_uint(self):
7673
arr = timedelta_range("1H", periods=2)
77-
expected = UInt64Index(
78-
np.array([3600000000000, 90000000000000], dtype="uint64")
79-
)
80-
tm.assert_index_equal(arr.astype("uint64"), expected)
8174

82-
msg = "will return exactly the specified dtype instead of uint64"
83-
with tm.assert_produces_warning(FutureWarning, match=msg):
84-
res = arr.astype("uint32")
85-
tm.assert_index_equal(res, expected)
75+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
76+
arr.astype("uint64")
77+
with pytest.raises(TypeError, match=r"Do obj.astype\('int64'\)"):
78+
arr.astype("uint32")
8679

8780
def test_astype_timedelta64(self):
8881
# GH 13149, GH 13209

pandas/tests/series/test_constructors.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,7 @@ def test_constructor_dtype_datetime64_11(self):
974974
dts.astype("int64")
975975

976976
# invalid casting
977-
msg = r"cannot astype a datetimelike from \[datetime64\[ns\]\] to \[int32\]"
977+
msg = r"Converting from datetime64\[ns\] to int32 is not supported"
978978
with pytest.raises(TypeError, match=msg):
979979
dts.astype("int32")
980980

@@ -1508,7 +1508,7 @@ def test_constructor_dtype_timedelta64(self):
15081508
td.astype("int64")
15091509

15101510
# invalid casting
1511-
msg = r"cannot astype a datetimelike from \[timedelta64\[ns\]\] to \[int32\]"
1511+
msg = r"Converting from timedelta64\[ns\] to int32 is not supported"
15121512
with pytest.raises(TypeError, match=msg):
15131513
td.astype("int32")
15141514

0 commit comments

Comments
 (0)