Skip to content
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

BUG: Index constructor silently ignoring dtype #40411

Merged
merged 2 commits into from
Mar 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ Conversion
- Bug in :meth:`Series.view` and :meth:`Index.view` when converting between datetime-like (``datetime64[ns]``, ``datetime64[ns, tz]``, ``timedelta64``, ``period``) dtypes (:issue:`39788`)
- Bug in creating a :class:`DataFrame` from an empty ``np.recarray`` not retaining the original dtypes (:issue:`40121`)
- Bug in :class:`DataFrame` failing to raise ``TypeError`` when constructing from a ``frozenset`` (:issue:`40163`)
-
- Bug in :class:`Index` construction silently ignoring a passed ``dtype`` when the data cannot be cast to that dtype (:issue:`21311`)

Strings
^^^^^^^
Expand Down
61 changes: 5 additions & 56 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
can_hold_element,
find_common_type,
infer_dtype_from,
maybe_cast_to_integer_array,
validate_numeric_casting,
)
from pandas.core.dtypes.common import (
Expand Down Expand Up @@ -144,6 +143,7 @@
from pandas.core.construction import (
ensure_wrapped_if_datetimelike,
extract_array,
sanitize_array,
)
from pandas.core.indexers import deprecate_ndim_indexing
from pandas.core.indexes.frozen import FrozenList
Expand Down Expand Up @@ -399,18 +399,17 @@ def __new__(
# index-like
elif isinstance(data, (np.ndarray, Index, ABCSeries)):

if isinstance(data, ABCMultiIndex):
data = data._values

if dtype is not None:
# we need to avoid having numpy coerce
# things that look like ints/floats to ints unless
# they are actually ints, e.g. '0' and 0.0
# should not be coerced
# GH 11836
data = sanitize_array(data, None, dtype=dtype, copy=copy)

# error: Argument 1 to "_maybe_cast_with_dtype" has incompatible type
# "Union[ndarray, Index, Series]"; expected "ndarray"
data = _maybe_cast_with_dtype(
data, dtype, copy # type: ignore[arg-type]
)
dtype = data.dtype

if data.dtype.kind in ["i", "u", "f"]:
Expand Down Expand Up @@ -6366,56 +6365,6 @@ def maybe_extract_name(name, obj, cls) -> Hashable:
return name


def _maybe_cast_with_dtype(data: np.ndarray, dtype: np.dtype, copy: bool) -> np.ndarray:
"""
If a dtype is passed, cast to the closest matching dtype that is supported
by Index.

Parameters
----------
data : np.ndarray
dtype : np.dtype
copy : bool

Returns
-------
np.ndarray
"""
# we need to avoid having numpy coerce
# things that look like ints/floats to ints unless
# they are actually ints, e.g. '0' and 0.0
# should not be coerced
# GH 11836
if is_integer_dtype(dtype):
inferred = lib.infer_dtype(data, skipna=False)
if inferred == "integer":
data = maybe_cast_to_integer_array(data, dtype, copy=copy)
elif inferred in ["floating", "mixed-integer-float"]:
if isna(data).any():
raise ValueError("cannot convert float NaN to integer")

if inferred == "mixed-integer-float":
data = maybe_cast_to_integer_array(data, dtype)

# If we are actually all equal to integers,
# then coerce to integer.
try:
data = _try_convert_to_int_array(data, copy, dtype)
except ValueError:
data = np.array(data, dtype=np.float64, copy=copy)

elif inferred != "string":
data = data.astype(dtype)
elif is_float_dtype(dtype):
inferred = lib.infer_dtype(data, skipna=False)
if inferred != "string":
data = data.astype(dtype)
else:
data = np.array(data, dtype=dtype, copy=copy)

return data


def _maybe_cast_data_without_dtype(subarr):
"""
If we have an arraylike input but no passed dtype, try to infer
Expand Down
1 change: 0 additions & 1 deletion pandas/tests/indexes/base_class/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def test_constructor_wrong_kwargs(self):
with tm.assert_produces_warning(FutureWarning):
Index([], foo="bar")

@pytest.mark.xfail(reason="see GH#21311: Index doesn't enforce dtype argument")
def test_constructor_cast(self):
msg = "could not convert string to float"
with pytest.raises(ValueError, match=msg):
Expand Down