Skip to content

Commit adb284e

Browse files
Terji PetersenTerji Petersen
authored andcommitted
DEPR: move NumericIndexes into base Index, part 1
1 parent 7ccac68 commit adb284e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+296
-363
lines changed

pandas/__init__.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -183,38 +183,6 @@
183183
__git_version__ = v.get("full-revisionid")
184184
del get_versions, v
185185

186-
# GH 27101
187-
__deprecated_num_index_names = ["Float64Index", "Int64Index", "UInt64Index"]
188-
189-
190-
def __dir__() -> list[str]:
191-
# GH43028
192-
# Int64Index etc. are deprecated, but we still want them to be available in the dir.
193-
# Remove in Pandas 2.0, when we remove Int64Index etc. from the code base.
194-
return list(globals().keys()) + __deprecated_num_index_names
195-
196-
197-
def __getattr__(name):
198-
import warnings
199-
200-
if name in __deprecated_num_index_names:
201-
warnings.warn(
202-
f"pandas.{name} is deprecated "
203-
"and will be removed from pandas in a future version. "
204-
"Use pandas.Index with the appropriate dtype instead.",
205-
FutureWarning,
206-
stacklevel=2,
207-
)
208-
from pandas.core.api import Float64Index, Int64Index, UInt64Index
209-
210-
return {
211-
"Float64Index": Float64Index,
212-
"Int64Index": Int64Index,
213-
"UInt64Index": UInt64Index,
214-
}[name]
215-
216-
raise AttributeError(f"module 'pandas' has no attribute '{name}'")
217-
218186

219187
# module level doc-string
220188
__doc__ = """

pandas/core/frame.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11203,7 +11203,7 @@ def quantile(
1120311203
)
1120411204
if method == "single":
1120511205
# error: Argument "qs" to "quantile" of "BlockManager" has incompatible type
11206-
# "Index"; expected "Float64Index"
11206+
# "Index"; expected "NumericIndex"
1120711207
res = data._mgr.quantile(
1120811208
qs=q, axis=1, interpolation=interpolation # type: ignore[arg-type]
1120911209
)

pandas/core/indexes/base.py

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
ensure_platform_int,
9292
is_bool_dtype,
9393
is_categorical_dtype,
94+
is_complex_dtype,
9495
is_dtype_equal,
9596
is_ea_or_datetimelike_dtype,
9697
is_extension_array_dtype,
@@ -590,18 +591,14 @@ def _dtype_to_subclass(cls, dtype: DtypeObj):
590591

591592
return TimedeltaIndex
592593

593-
elif dtype.kind == "f":
594-
from pandas.core.api import Float64Index
595-
596-
return Float64Index
597-
elif dtype.kind == "u":
598-
from pandas.core.api import UInt64Index
599-
600-
return UInt64Index
601-
elif dtype.kind == "i":
602-
from pandas.core.api import Int64Index
594+
elif (
595+
is_numeric_dtype(dtype)
596+
and not is_bool_dtype(dtype)
597+
and not is_complex_dtype(dtype)
598+
):
599+
from pandas.core.api import NumericIndex
603600

604-
return Int64Index
601+
return NumericIndex
605602

606603
elif dtype.kind == "O":
607604
# NB: assuming away MultiIndex
@@ -1072,14 +1069,29 @@ def astype(self, dtype, copy: bool = True):
10721069
) from err
10731070

10741071
# pass copy=False because any copying will be done in the astype above
1075-
if self._is_backward_compat_public_numeric_index:
1076-
# this block is needed so e.g. NumericIndex[int8].astype("int32") returns
1077-
# NumericIndex[int32] and not Int64Index with dtype int64.
1072+
if not self._is_backward_compat_public_numeric_index and not isinstance(
1073+
self, ABCRangeIndex
1074+
):
1075+
# this block is needed so e.g. Int64Index.astype("int32") returns
1076+
# Int64Index and not a NumericIndex with dtype int32.
10781077
# When Int64Index etc. are removed from the code base, removed this also.
10791078
if isinstance(dtype, np.dtype) and is_numeric_dtype(dtype):
1080-
return self._constructor(
1081-
new_values, name=self.name, dtype=dtype, copy=False
1079+
from pandas.core.api import (
1080+
Float64Index,
1081+
Int64Index,
1082+
UInt64Index,
10821083
)
1084+
1085+
if is_signed_integer_dtype(dtype):
1086+
klass = Int64Index
1087+
elif is_unsigned_integer_dtype(dtype):
1088+
klass = UInt64Index
1089+
elif is_float_dtype(dtype):
1090+
klass = Float64Index
1091+
else:
1092+
klass = Index
1093+
return klass(new_values, name=self.name, dtype=dtype, copy=False)
1094+
10831095
return Index(new_values, name=self.name, dtype=new_values.dtype, copy=False)
10841096

10851097
_index_shared_docs[
@@ -5328,6 +5340,7 @@ def putmask(self, mask, value) -> Index:
53285340
if self.dtype != object and is_valid_na_for_dtype(value, self.dtype):
53295341
# e.g. None -> np.nan, see also Block._standardize_fill_value
53305342
value = self._na_value
5343+
53315344
try:
53325345
converted = self._validate_fill_value(value)
53335346
except (LossySetitemError, ValueError, TypeError) as err:
@@ -6196,13 +6209,6 @@ def map(self, mapper, na_action=None):
61966209
new_values, self.dtype, same_dtype=same_dtype
61976210
)
61986211

6199-
if self._is_backward_compat_public_numeric_index and is_numeric_dtype(
6200-
new_values.dtype
6201-
):
6202-
return self._constructor(
6203-
new_values, dtype=dtype, copy=False, name=self.name
6204-
)
6205-
62066212
return Index._with_infer(new_values, dtype=dtype, copy=False, name=self.name)
62076213

62086214
# TODO: De-duplicate with map, xref GH#32349
@@ -6679,10 +6685,17 @@ def insert(self, loc: int, item) -> Index:
66796685
loc = loc if loc >= 0 else loc - 1
66806686
new_values[loc] = item
66816687

6682-
if self._typ == "numericindex":
6683-
# Use self._constructor instead of Index to retain NumericIndex GH#43921
6684-
# TODO(2.0) can use Index instead of self._constructor
6685-
return self._constructor._with_infer(new_values, name=self.name)
6688+
if not self._is_backward_compat_public_numeric_index:
6689+
from pandas.core.indexes.numeric import NumericIndex
6690+
6691+
if not isinstance(self, ABCRangeIndex) or not isinstance(
6692+
self, NumericIndex
6693+
):
6694+
return Index._with_infer(new_values, name=self.name)
6695+
else:
6696+
# Use self._constructor instead of Index to retain old-style num. index
6697+
# TODO(2.0) can use Index instead of self._constructor
6698+
return self._constructor._with_infer(new_values, name=self.name)
66866699
else:
66876700
return Index._with_infer(new_values, name=self.name)
66886701

pandas/core/indexes/numeric.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
)
1414
from pandas._typing import (
1515
Dtype,
16+
DtypeObj,
1617
npt,
1718
)
1819
from pandas.util._decorators import (
@@ -347,7 +348,26 @@ def _format_native_types(
347348
"""
348349

349350

350-
class IntegerIndex(NumericIndex):
351+
class TempBaseIndex(NumericIndex):
352+
@classmethod
353+
def _dtype_to_subclass(cls, dtype: DtypeObj):
354+
if is_integer_dtype(dtype):
355+
from pandas.core.api import Int64Index
356+
357+
return Int64Index
358+
elif is_unsigned_integer_dtype(dtype):
359+
from pandas.core.api import UInt64Index
360+
361+
return UInt64Index
362+
elif is_float_dtype(dtype):
363+
from pandas.core.api import Float64Index
364+
365+
return Float64Index
366+
else:
367+
return super()._dtype_to_subclass(dtype)
368+
369+
370+
class IntegerIndex(TempBaseIndex):
351371
"""
352372
This is an abstract class for Int64Index, UInt64Index.
353373
"""
@@ -391,7 +411,7 @@ def _engine_type(self) -> type[libindex.UInt64Engine]:
391411
return libindex.UInt64Engine
392412

393413

394-
class Float64Index(NumericIndex):
414+
class Float64Index(TempBaseIndex):
395415
_index_descr_args = {
396416
"klass": "Float64Index",
397417
"dtype": "float64",

pandas/core/indexes/range.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ def _simple_new(cls, values: range, name: Hashable = None) -> RangeIndex:
185185
# error: Return type "Type[Int64Index]" of "_constructor" incompatible with return
186186
# type "Type[RangeIndex]" in supertype "Index"
187187
@cache_readonly
188-
def _constructor(self) -> type[Int64Index]: # type: ignore[override]
188+
def _constructor(self) -> type[NumericIndex]: # type: ignore[override]
189189
"""return the class to use for construction"""
190-
return Int64Index
190+
return NumericIndex
191191

192192
# error: Signature of "_data" incompatible with supertype "Index"
193193
@cache_readonly

pandas/core/internals/managers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@
6464
)
6565
from pandas.core.indexers import maybe_convert_indices
6666
from pandas.core.indexes.api import (
67-
Float64Index,
6867
Index,
68+
NumericIndex,
6969
ensure_index,
7070
)
7171
from pandas.core.internals.base import (
@@ -1582,7 +1582,7 @@ def _equal_values(self: BlockManager, other: BlockManager) -> bool:
15821582
def quantile(
15831583
self: T,
15841584
*,
1585-
qs: Float64Index,
1585+
qs: NumericIndex,
15861586
axis: AxisInt = 0,
15871587
interpolation: QuantileInterpolation = "linear",
15881588
) -> T:
@@ -1610,7 +1610,7 @@ def quantile(
16101610
assert axis == 1 # only ever called this way
16111611

16121612
new_axes = list(self.axes)
1613-
new_axes[1] = Float64Index(qs)
1613+
new_axes[1] = Index(qs, dtype=np.float64)
16141614

16151615
blocks = [
16161616
blk.quantile(axis=axis, qs=qs, interpolation=interpolation)

pandas/tests/api/test_api.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,14 @@ class TestPDApi(Base):
5555
"DatetimeIndex",
5656
"ExcelFile",
5757
"ExcelWriter",
58-
"Float64Index",
5958
"Flags",
6059
"Grouper",
6160
"HDFStore",
6261
"Index",
63-
"Int64Index",
6462
"MultiIndex",
6563
"Period",
6664
"PeriodIndex",
6765
"RangeIndex",
68-
"UInt64Index",
6966
"Series",
7067
"SparseDtype",
7168
"StringDtype",
@@ -93,7 +90,7 @@ class TestPDApi(Base):
9390
]
9491

9592
# these are already deprecated; awaiting removal
96-
deprecated_classes: list[str] = ["Float64Index", "Int64Index", "UInt64Index"]
93+
deprecated_classes: list[str] = []
9794

9895
# external modules exposed in pandas namespace
9996
modules: list[str] = []

pandas/tests/apply/test_series_apply.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def test_apply_datetimetz():
186186
# change dtype
187187
# GH 14506 : Returned dtype changed from int32 to int64
188188
result = s.apply(lambda x: x.hour)
189-
exp = Series(list(range(24)) + [0], name="XX", dtype=np.int64)
189+
exp = Series(list(range(24)) + [0], name="XX", dtype=np.int32)
190190
tm.assert_series_equal(result, exp)
191191

192192
# not vectorized
@@ -766,7 +766,7 @@ def test_map_datetimetz():
766766
# change dtype
767767
# GH 14506 : Returned dtype changed from int32 to int64
768768
result = s.map(lambda x: x.hour)
769-
exp = Series(list(range(24)) + [0], name="XX", dtype=np.int64)
769+
exp = Series(list(range(24)) + [0], name="XX", dtype=np.int32)
770770
tm.assert_series_equal(result, exp)
771771

772772
# not vectorized

pandas/tests/base/test_unique.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@
55

66
import pandas as pd
77
import pandas._testing as tm
8-
from pandas.core.api import NumericIndex
8+
from pandas.core.api import (
9+
Float64Index,
10+
Int64Index,
11+
NumericIndex,
12+
UInt64Index,
13+
)
914
from pandas.tests.base.common import allow_na_ops
1015

1116

1217
def test_unique(index_or_series_obj):
1318
obj = index_or_series_obj
19+
if isinstance(obj, (Int64Index, UInt64Index, Float64Index)):
20+
pytest.skip("these indexes will be removed in followup")
1421
obj = np.repeat(obj, range(1, len(obj) + 1))
1522
result = obj.unique()
1623

@@ -36,6 +43,8 @@ def test_unique(index_or_series_obj):
3643
@pytest.mark.parametrize("null_obj", [np.nan, None])
3744
def test_unique_null(null_obj, index_or_series_obj):
3845
obj = index_or_series_obj
46+
if isinstance(obj, (Int64Index, UInt64Index, Float64Index)):
47+
pytest.skip("these indexes will be removed in followup")
3948

4049
if not allow_na_ops(obj):
4150
pytest.skip("type doesn't allow for NA operations")

pandas/tests/base/test_value_counts.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
def test_value_counts(index_or_series_obj):
2525
obj = index_or_series_obj
2626
obj = np.repeat(obj, range(1, len(obj) + 1))
27+
28+
if obj.dtype == np.float16:
29+
pytest.xfail("we don't have Float16Index, so value_counts is problematic")
30+
2731
result = obj.value_counts()
2832

2933
counter = collections.Counter(obj)
@@ -57,6 +61,9 @@ def test_value_counts_null(null_obj, index_or_series_obj):
5761
orig = index_or_series_obj
5862
obj = orig.copy()
5963

64+
if obj.dtype == np.float16:
65+
pytest.xfail("we don't have Float16Index, so value_counts is problematic")
66+
6067
if not allow_na_ops(obj):
6168
pytest.skip("type doesn't allow for NA operations")
6269
elif len(obj) < 1:

0 commit comments

Comments
 (0)