52
52
from pandas .compat .numpy import function as nv
53
53
from pandas .errors import (
54
54
DuplicateLabelError ,
55
+ IntCastingNaNError ,
55
56
InvalidIndexError ,
56
57
)
57
58
from pandas .util ._decorators import (
65
66
rewrite_exception ,
66
67
)
67
68
69
+ from pandas .core .dtypes .astype import astype_nansafe
68
70
from pandas .core .dtypes .cast import (
69
71
can_hold_element ,
70
72
common_dtype_categorical_compat ,
@@ -1051,6 +1053,14 @@ def astype(self, dtype, copy: bool = True):
1051
1053
with rewrite_exception (type (values ).__name__ , type (self ).__name__ ):
1052
1054
new_values = values .astype (dtype , copy = copy )
1053
1055
1056
+ elif is_float_dtype (self .dtype ) and needs_i8_conversion (dtype ):
1057
+ # NB: this must come before the ExtensionDtype check below
1058
+ # TODO: this differs from Series behavior; can/should we align them?
1059
+ raise TypeError (
1060
+ f"Cannot convert Float64Index to dtype { dtype } ; integer "
1061
+ "values are required for conversion"
1062
+ )
1063
+
1054
1064
elif isinstance (dtype , ExtensionDtype ):
1055
1065
cls = dtype .construct_array_type ()
1056
1066
# Note: for RangeIndex and CategoricalDtype self vs self._values
@@ -1059,13 +1069,31 @@ def astype(self, dtype, copy: bool = True):
1059
1069
1060
1070
else :
1061
1071
try :
1062
- new_values = values .astype (dtype , copy = copy )
1072
+ if dtype == str :
1073
+ # GH#38607
1074
+ new_values = values .astype (dtype , copy = copy )
1075
+ else :
1076
+ # GH#13149 specifically use astype_nansafe instead of astype
1077
+ new_values = astype_nansafe (values , dtype = dtype , copy = copy )
1078
+ except IntCastingNaNError :
1079
+ raise
1063
1080
except (TypeError , ValueError ) as err :
1081
+ if dtype .kind == "u" and "losslessly" in str (err ):
1082
+ # keep the message from _astype_float_to_int_nansafe
1083
+ raise
1064
1084
raise TypeError (
1065
1085
f"Cannot cast { type (self ).__name__ } to dtype { dtype } "
1066
1086
) from err
1067
1087
1068
1088
# pass copy=False because any copying will be done in the astype above
1089
+ if self ._is_backward_compat_public_numeric_index :
1090
+ # this block is needed so e.g. NumericIndex[int8].astype("int32") returns
1091
+ # NumericIndex[int32] and not Int64Index with dtype int64.
1092
+ # When Int64Index etc. are removed from the code base, removed this also.
1093
+ if isinstance (dtype , np .dtype ) and is_numeric_dtype (dtype ):
1094
+ return self ._constructor (
1095
+ new_values , name = self .name , dtype = dtype , copy = False
1096
+ )
1069
1097
return Index (new_values , name = self .name , dtype = new_values .dtype , copy = False )
1070
1098
1071
1099
_index_shared_docs [
0 commit comments