Skip to content

BUG: Series[object].__setitem__(ndarray[M8ns]_with_matching_size) #43868

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 5 commits into from
Oct 12, 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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ Indexing
- Bug in :meth:`DataFrame.query` where method calls in query strings led to errors when the ``numexpr`` package was installed. (:issue:`22435`)
- Bug in :meth:`DataFrame.nlargest` and :meth:`Series.nlargest` where sorted result did not count indexes containing ``np.nan`` (:issue:`28984`)
- Bug in indexing on a non-unique object-dtype :class:`Index` with an NA scalar (e.g. ``np.nan``) (:issue:`43711`)
- Bug in :meth:`Series.__setitem__` with object dtype when setting an array with matching size and dtype='datetime64[ns]' or dtype='timedelta64[ns]' incorrectly converting the datetime/timedeltas to integers (:issue:`43868`)
-

Missing
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/indexers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def check_setitem_lengths(indexer, value, values) -> bool:
if not (
isinstance(indexer, np.ndarray)
and indexer.dtype == np.bool_
and len(indexer[indexer]) == len(value)
and indexer.sum() == len(value)
):
raise ValueError(
"cannot set using a list-like indexer "
Expand Down
31 changes: 0 additions & 31 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
from pandas.core.dtypes.common import (
is_1d_only_ea_dtype,
is_1d_only_ea_obj,
is_categorical_dtype,
is_dtype_equal,
is_extension_array_dtype,
is_list_like,
Expand Down Expand Up @@ -91,8 +90,6 @@
Categorical,
DatetimeArray,
ExtensionArray,
FloatingArray,
IntegerArray,
IntervalArray,
PandasArray,
PeriodArray,
Expand All @@ -110,7 +107,6 @@
from pandas.core.indexers import (
check_setitem_lengths,
is_empty_indexer,
is_exact_shape_match,
is_scalar_indexer,
)
import pandas.core.missing as missing
Expand Down Expand Up @@ -928,18 +924,15 @@ def setitem(self, indexer, value):
if is_extension_array_dtype(getattr(value, "dtype", None)):
# We need to be careful not to allow through strings that
# can be parsed to EADtypes
is_ea_value = True
arr_value = value
else:
is_ea_value = False
arr_value = np.asarray(value)

if transpose:
values = values.T

# length checking
check_setitem_lengths(indexer, value, values)
exact_match = is_exact_shape_match(values, arr_value)

if is_empty_indexer(indexer, arr_value):
# GH#8669 empty indexers
Expand All @@ -950,30 +943,6 @@ def setitem(self, indexer, value):
# be e.g. a list; see GH#6043
values[indexer] = value

elif exact_match and is_categorical_dtype(arr_value.dtype):
# GH25495 - If the current dtype is not categorical,
# we need to create a new categorical block
values[indexer] = value

elif exact_match and is_ea_value:
# GH#32395 if we're going to replace the values entirely, just
# substitute in the new array
if not self.is_object and isinstance(value, (IntegerArray, FloatingArray)):
# _can_hold_element will only allow us to get here if value
# has no NA entries.
values[indexer] = value.to_numpy(value.dtype.numpy_dtype)
else:
values[indexer] = np.asarray(value)

# if we are an exact match (ex-broadcasting),
# then use the resultant dtype
elif exact_match:
# We are setting _all_ of the array's values, so can cast to new dtype
values[indexer] = value

elif is_ea_value:
values[indexer] = value

else:
# error: Argument 1 to "setitem_datetimelike_compat" has incompatible type
# "Union[ndarray, ExtensionArray]"; expected "ndarray"
Expand Down
18 changes: 18 additions & 0 deletions pandas/tests/series/indexing/test_setitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,24 @@ def test_setitem_with_tz_dst(self, indexer_sli):
indexer_sli(ser)[[1, 2]] = vals
tm.assert_series_equal(ser, exp)

def test_object_series_setitem_dt64array_exact_match(self):
# make sure the dt64 isn't cast by numpy to integers
# https://github.com/numpy/numpy/issues/12550

ser = Series({"X": np.nan}, dtype=object)

indexer = [True]

# "exact_match" -> size of array being set matches size of ser
value = np.array([4], dtype="M8[ns]")

ser.iloc[indexer] = value

expected = Series([value[0]], index=["X"], dtype=object)
assert all(isinstance(x, np.datetime64) for x in expected.values)

tm.assert_series_equal(ser, expected)


class TestSetitemScalarIndexer:
def test_setitem_negative_out_of_bounds(self):
Expand Down