From 8f6fa5c7338cdb2fa82b222616e35187dc4c2623 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 13 Apr 2020 19:54:06 -0700 Subject: [PATCH] Re-use iloc, loc instead of set_labels, set_values --- pandas/core/indexing.py | 2 ++ pandas/core/series.py | 26 +++++++----------------- pandas/tests/series/indexing/test_loc.py | 4 ++-- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index b74399ed86fbd..0292f7257a22a 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -616,6 +616,8 @@ def _get_setitem_indexer(self, key): # invalid indexer type vs 'other' indexing errors if "cannot do" in str(e): raise + elif "unhashable type" in str(e): + raise raise IndexingError(key) from e def _ensure_listlike_indexer(self, key, axis=None): diff --git a/pandas/core/series.py b/pandas/core/series.py index 3f5927828e541..eec44f6c2060e 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1034,7 +1034,7 @@ def __setitem__(self, key, value): try: self._where(~key, value, inplace=True) except InvalidIndexError: - self._set_values(key.astype(np.bool_), value) + self.iloc[key] = value return else: @@ -1052,8 +1052,10 @@ def _set_with_engine(self, key, value): def _set_with(self, key, value): # other: fancy integer or otherwise if isinstance(key, slice): + # extract_array so that if we set e.g. ser[-5:] = ser[:5] + # we get the first five values, and not 5 NaNs indexer = self.index._convert_slice_indexer(key, kind="getitem") - return self._set_values(indexer, value) + self.iloc[indexer] = extract_array(value, extract_numpy=True) else: assert not isinstance(key, tuple) @@ -1071,25 +1073,11 @@ def _set_with(self, key, value): # should be caught by the is_bool_indexer check in __setitem__ if key_type == "integer": if self.index.inferred_type == "integer": - self._set_labels(key, value) + self.loc[key] = value else: - self._set_values(key, value) + self.iloc[key] = value else: - self._set_labels(key, value) - - def _set_labels(self, key, value): - key = com.asarray_tuplesafe(key) - indexer: np.ndarray = self.index.get_indexer(key) - mask = indexer == -1 - if mask.any(): - raise ValueError(f"{key[mask]} not contained in the index") - self._set_values(indexer, value) - - def _set_values(self, key, value): - if isinstance(key, Series): - key = key._values - self._mgr = self._mgr.setitem(indexer=key, value=value) - self._maybe_update_cacher() + self.loc[key] = value def _set_value(self, label, value, takeable: bool = False): """ diff --git a/pandas/tests/series/indexing/test_loc.py b/pandas/tests/series/indexing/test_loc.py index 7d6b6c78cc492..368adcfb32215 100644 --- a/pandas/tests/series/indexing/test_loc.py +++ b/pandas/tests/series/indexing/test_loc.py @@ -131,8 +131,8 @@ def test_basic_setitem_with_labels(datetime_series): inds_notfound = [0, 4, 5, 6] arr_inds_notfound = np.array([0, 4, 5, 6]) - msg = r"\[5\] not contained in the index" - with pytest.raises(ValueError, match=msg): + msg = r"\[5\] not in index" + with pytest.raises(KeyError, match=msg): s[inds_notfound] = 0 with pytest.raises(Exception, match=msg): s[arr_inds_notfound] = 0