From a79f2273347447ea5f3dfaad2ccc4395017fb0a6 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Fri, 28 Feb 2020 15:36:26 -0800 Subject: [PATCH 1/2] setitem_with_indexer cleanups --- pandas/core/indexing.py | 56 +++++++++++------------------------------ 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 3ab180bafd156..89872d7fc1e18 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1633,14 +1633,12 @@ def _setitem_with_indexer(self, indexer, value): info_idx = [info_idx] labels = item_labels[info_idx] + plane_indexer = indexer[:1] + lplane_indexer = length_of_indexer(plane_indexer[0], self.obj.index) + # lplane_indexer gives the expected length of obj[indexer[0]] + if len(labels) == 1: # We can operate on a single column - item = labels[0] - idx = indexer[0] - - plane_indexer = tuple([idx]) - lplane_indexer = length_of_indexer(plane_indexer[0], self.obj.index) - # lplane_indexer gives the expected length of obj[idx] # require that we are setting the right number of values that # we are indexing @@ -1652,11 +1650,6 @@ def _setitem_with_indexer(self, indexer, value): "length than the value" ) - # non-mi - else: - plane_indexer = indexer[:1] - lplane_indexer = length_of_indexer(plane_indexer[0], self.obj.index) - def setter(item, v): ser = self.obj[item] pi = plane_indexer[0] if lplane_indexer == 1 else plane_indexer @@ -1718,18 +1711,19 @@ def setter(item, v): for i, item in enumerate(labels): - # setting with a list, recoerces + # setting with a list, re-coerces setter(item, value[:, i].tolist()) - # we have an equal len list/ndarray - elif _can_do_equal_len( - labels, value, plane_indexer, lplane_indexer, self.obj - ): + elif len(labels) == 1 and lplane_indexer == len(value): + # we have an equal len list/ndarray setter(labels[0], value) - # per label values - else: + elif lplane_indexer == 0 and len(value) == len(self.obj.index): + # We get here in one case via .loc with a all-False mask + pass + else: + # per-label values if len(labels) != len(value): raise ValueError( "Must have equal len keys and value " @@ -1746,7 +1740,6 @@ def setter(item, v): else: if isinstance(indexer, tuple): - indexer = maybe_convert_ix(*indexer) # if we are setting on the info axis ONLY # set using those methods to avoid block-splitting @@ -1764,6 +1757,8 @@ def setter(item, v): self.obj[item_labels[indexer[info_axis]]] = value return + indexer = maybe_convert_ix(*indexer) + if isinstance(value, (ABCSeries, dict)): # TODO(EA): ExtensionBlock.setitem this causes issues with # setting for extensionarrays that store dicts. Need to decide @@ -2277,26 +2272,3 @@ def _maybe_numeric_slice(df, slice_, include_bool=False): dtypes.append(bool) slice_ = IndexSlice[:, df.select_dtypes(include=dtypes).columns] return slice_ - - -def _can_do_equal_len(labels, value, plane_indexer, lplane_indexer, obj) -> bool: - """ - Returns - ------- - bool - True if we have an equal len settable. - """ - if not len(labels) == 1 or not np.iterable(value) or is_scalar(plane_indexer[0]): - return False - - item = labels[0] - index = obj[item].index - - values_len = len(value) - # equal len list/ndarray - if len(index) == values_len: - return True - elif lplane_indexer == values_len: - return True - - return False From 7e74de39b02e6070b244ba83ef1ae43fa4bac016 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Fri, 28 Feb 2020 16:53:03 -0800 Subject: [PATCH 2/2] fix check --- pandas/core/indexing.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 89872d7fc1e18..35e61ab6a59c9 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1714,7 +1714,11 @@ def setter(item, v): # setting with a list, re-coerces setter(item, value[:, i].tolist()) - elif len(labels) == 1 and lplane_indexer == len(value): + elif ( + len(labels) == 1 + and lplane_indexer == len(value) + and not is_scalar(plane_indexer[0]) + ): # we have an equal len list/ndarray setter(labels[0], value)