Skip to content

Commit c869e66

Browse files
jbrockmendelyehoshuadimarsky
authored andcommitted
REF: share NumericIndex.astype+Index.astype (pandas-dev#45405)
1 parent e8ff917 commit c869e66

File tree

2 files changed

+29
-33
lines changed

2 files changed

+29
-33
lines changed

pandas/core/indexes/base.py

+29-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
from pandas.compat.numpy import function as nv
5353
from pandas.errors import (
5454
DuplicateLabelError,
55+
IntCastingNaNError,
5556
InvalidIndexError,
5657
)
5758
from pandas.util._decorators import (
@@ -65,6 +66,7 @@
6566
rewrite_exception,
6667
)
6768

69+
from pandas.core.dtypes.astype import astype_nansafe
6870
from pandas.core.dtypes.cast import (
6971
can_hold_element,
7072
common_dtype_categorical_compat,
@@ -1051,6 +1053,14 @@ def astype(self, dtype, copy: bool = True):
10511053
with rewrite_exception(type(values).__name__, type(self).__name__):
10521054
new_values = values.astype(dtype, copy=copy)
10531055

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+
10541064
elif isinstance(dtype, ExtensionDtype):
10551065
cls = dtype.construct_array_type()
10561066
# Note: for RangeIndex and CategoricalDtype self vs self._values
@@ -1059,13 +1069,31 @@ def astype(self, dtype, copy: bool = True):
10591069

10601070
else:
10611071
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
10631080
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
10641084
raise TypeError(
10651085
f"Cannot cast {type(self).__name__} to dtype {dtype}"
10661086
) from err
10671087

10681088
# 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+
)
10691097
return Index(new_values, name=self.name, dtype=new_values.dtype, copy=False)
10701098

10711099
_index_shared_docs[

pandas/core/indexes/numeric.py

-32
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,15 @@
2323
)
2424
from pandas.util._exceptions import find_stack_level
2525

26-
from pandas.core.dtypes.astype import astype_nansafe
2726
from pandas.core.dtypes.common import (
2827
is_dtype_equal,
29-
is_extension_array_dtype,
3028
is_float,
3129
is_float_dtype,
3230
is_integer_dtype,
3331
is_numeric_dtype,
3432
is_scalar,
3533
is_signed_integer_dtype,
3634
is_unsigned_integer_dtype,
37-
needs_i8_conversion,
3835
pandas_dtype,
3936
)
4037
from pandas.core.dtypes.generic import ABCSeries
@@ -232,35 +229,6 @@ def __contains__(self, key) -> bool:
232229
except (OverflowError, TypeError, ValueError):
233230
return False
234231

235-
@doc(Index.astype)
236-
def astype(self, dtype, copy: bool = True):
237-
dtype = pandas_dtype(dtype)
238-
if is_float_dtype(self.dtype):
239-
if needs_i8_conversion(dtype):
240-
raise TypeError(
241-
f"Cannot convert Float64Index to dtype {dtype}; integer "
242-
"values are required for conversion"
243-
)
244-
elif is_integer_dtype(dtype) and not is_extension_array_dtype(dtype):
245-
# TODO(ExtensionIndex); this can change once we have an EA Index type
246-
# GH 13149
247-
arr = astype_nansafe(self._values, dtype=dtype)
248-
if isinstance(self, Float64Index):
249-
if dtype.kind == "i":
250-
return Int64Index(arr, name=self.name)
251-
else:
252-
return UInt64Index(arr, name=self.name)
253-
else:
254-
return NumericIndex(arr, name=self.name, dtype=dtype)
255-
elif self._is_backward_compat_public_numeric_index:
256-
# this block is needed so e.g. NumericIndex[int8].astype("int32") returns
257-
# NumericIndex[int32] and not Int64Index with dtype int64.
258-
# When Int64Index etc. are removed from the code base, removed this also.
259-
if not is_extension_array_dtype(dtype) and is_numeric_dtype(dtype):
260-
return self._constructor(self, dtype=dtype, copy=copy)
261-
262-
return super().astype(dtype, copy=copy)
263-
264232
# ----------------------------------------------------------------
265233
# Indexing Methods
266234

0 commit comments

Comments
 (0)