Skip to content

[BUG] Validate dtype when Int64Index, UInt64Index, or Float64Index are cons… #29545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 18, 2019
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ Numeric
- Bug in :class:`DataFrame` logical operations (`&`, `|`, `^`) not matching :class:`Series` behavior by filling NA values (:issue:`28741`)
- Bug in :meth:`DataFrame.interpolate` where specifying axis by name references variable before it is assigned (:issue:`29142`)
- Improved error message when using `frac` > 1 and `replace` = False (:issue:`27451`)
- Bug in numeric indexes resulted in it being possible to instantiate an :class:`Int64Index`, :class:`UInt64Index`, or :class:`Float64Index` with an invalid dtype (e.g. datetime-like) (:issue:`29539`)
-

Conversion
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ def __new__(
pass

# Return an actual float index.
return Float64Index(data, copy=copy, dtype=dtype, name=name)
return Float64Index(data, copy=copy, name=name)

elif inferred == "string":
pass
Expand Down
21 changes: 20 additions & 1 deletion pandas/core/indexes/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
is_float_dtype,
is_integer_dtype,
is_scalar,
is_signed_integer_dtype,
is_unsigned_integer_dtype,
needs_i8_conversion,
pandas_dtype,
)
Expand All @@ -26,6 +28,7 @@
)
from pandas.core.dtypes.missing import isna

from pandas._typing import Dtype
from pandas.core import algorithms
import pandas.core.common as com
from pandas.core.indexes.base import Index, InvalidIndexError, _index_shared_docs
Expand All @@ -45,7 +48,7 @@ class NumericIndex(Index):
_is_numeric_dtype = True

def __new__(cls, data=None, dtype=None, copy=False, name=None, fastpath=None):

cls._validate_dtype(dtype)
if fastpath is not None:
warnings.warn(
"The 'fastpath' keyword is deprecated, and will be "
Expand All @@ -72,6 +75,22 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, fastpath=None):
name = data.name
return cls._simple_new(subarr, name=name)

@classmethod
def _validate_dtype(cls, dtype: Dtype) -> None:
if dtype is None:
return
validation_metadata = {
"int64index": (is_signed_integer_dtype, "signed integer"),
"uint64index": (is_unsigned_integer_dtype, "unsigned integer"),
"float64index": (is_float_dtype, "float"),
"rangeindex": (is_signed_integer_dtype, "signed integer"),
}

validation_func, expected = validation_metadata[cls._typ]
if not validation_func(dtype):
msg = f"Incorrect `dtype` passed: expected {expected}, received {dtype}"
raise ValueError(msg)

@Appender(_index_shared_docs["_maybe_cast_slice_bound"])
def _maybe_cast_slice_bound(self, label, side, kind):
assert kind in ["ix", "loc", "getitem", None]
Expand Down
7 changes: 0 additions & 7 deletions pandas/core/indexes/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from pandas.core.dtypes.common import (
ensure_platform_int,
ensure_python_int,
is_int64_dtype,
is_integer,
is_integer_dtype,
is_list_like,
Expand Down Expand Up @@ -167,12 +166,6 @@ def _simple_new(cls, values, name=None, dtype=None, **kwargs):

# --------------------------------------------------------------------

@staticmethod
def _validate_dtype(dtype):
""" require dtype to be None or int64 """
if not (dtype is None or is_int64_dtype(dtype)):
raise TypeError("Invalid to pass a non-int64 dtype to RangeIndex")

@cache_readonly
def _constructor(self):
""" return the class to use for construction """
Expand Down
17 changes: 17 additions & 0 deletions pandas/tests/indexes/test_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ def test_constructor(self):
result = Index(np.array([np.nan]))
assert pd.isna(result.values).all()

@pytest.mark.parametrize(
"index, dtype",
[
(pd.Int64Index, "float64"),
(pd.UInt64Index, "categorical"),
(pd.Float64Index, "datetime64"),
(pd.RangeIndex, "float64"),
],
)
def test_invalid_dtype(self, index, dtype):
# GH 29539
with pytest.raises(
ValueError,
match=rf"Incorrect `dtype` passed: expected \w+(?: \w+)?, received {dtype}",
):
index([1, 2, 3], dtype=dtype)

def test_constructor_invalid(self):

# invalid
Expand Down
6 changes: 3 additions & 3 deletions pandas/tests/indexes/test_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def test_constructor_same(self):
result = RangeIndex(index)
tm.assert_index_equal(result, index, exact=True)

with pytest.raises(TypeError):
with pytest.raises(ValueError):
RangeIndex(index, dtype="float64")

def test_constructor_range(self):
Expand Down Expand Up @@ -140,7 +140,7 @@ def test_constructor_range(self):
expected = RangeIndex(1, 5, 2)
tm.assert_index_equal(result, expected, exact=True)

with pytest.raises(TypeError):
with pytest.raises(ValueError):
Index(range(1, 5, 2), dtype="float64")
msg = r"^from_range\(\) got an unexpected keyword argument"
with pytest.raises(TypeError, match=msg):
Expand Down Expand Up @@ -178,7 +178,7 @@ def test_constructor_corner(self):
RangeIndex(1.1, 10.2, 1.3)

# invalid passed type
with pytest.raises(TypeError):
with pytest.raises(ValueError):
RangeIndex(1, 5, dtype="float64")

@pytest.mark.parametrize(
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/series/indexing/test_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ def test_get():
1764.0,
1849.0,
1936.0,
],
dtype="object",
]
),
)

Expand Down