Skip to content

REF: simplify Block.setitem #45403

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 6 commits into from
Jan 19, 2022
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
11 changes: 4 additions & 7 deletions pandas/core/indexers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,23 @@ def is_scalar_indexer(indexer, ndim: int) -> bool:
return False


def is_empty_indexer(indexer, arr_value: ArrayLike) -> bool:
def is_empty_indexer(indexer) -> bool:
"""
Check if we have an empty indexer.

Parameters
----------
indexer : object
arr_value : np.ndarray or ExtensionArray

Returns
-------
bool
"""
if is_list_like(indexer) and not len(indexer):
return True
if arr_value.ndim == 1:
if not isinstance(indexer, tuple):
indexer = (indexer,)
return any(isinstance(idx, np.ndarray) and len(idx) == 0 for idx in indexer)
return False
if not isinstance(indexer, tuple):
indexer = (indexer,)
return any(isinstance(idx, np.ndarray) and len(idx) == 0 for idx in indexer)


# -----------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1883,7 +1883,7 @@ def _setitem_single_column(self, loc: int, value, plane_indexer):
elif (
is_array_like(value)
and is_exact_shape_match(ser, value)
and not is_empty_indexer(pi, value)
and not is_empty_indexer(pi)
):
if is_list_like(pi):
ser = value[np.argsort(pi)]
Expand Down Expand Up @@ -2092,7 +2092,7 @@ def ravel(i):
# we have a frame, with multiple indexers on both axes; and a
# series, so need to broadcast (see GH5206)
if sum_aligners == self.ndim and all(is_sequence(_) for _ in indexer):
if is_empty_indexer(indexer[0], ser._values):
if is_empty_indexer(indexer[0]):
return ser._values.copy()
ser = ser.reindex(obj.axes[0][indexer[0]], copy=True)._values

Expand Down
2 changes: 2 additions & 0 deletions pandas/core/internals/array_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,8 @@ def setitem(self, indexer, value):
See `setitem_inplace` for a version that works inplace and doesn't
return a new Manager.
"""
if isinstance(indexer, np.ndarray) and indexer.ndim > self.ndim:
raise ValueError(f"Cannot set values with ndim > {self.ndim}")
return self.apply_with_block("setitem", indexer=indexer, value=value)

def idelete(self, indexer) -> SingleArrayManager:
Expand Down
18 changes: 3 additions & 15 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
is_1d_only_ea_dtype,
is_1d_only_ea_obj,
is_dtype_equal,
is_extension_array_dtype,
is_interval_dtype,
is_list_like,
is_string_dtype,
Expand Down Expand Up @@ -911,37 +910,26 @@ def setitem(self, indexer, value):
`indexer` is a direct slice/positional indexer. `value` must
be a compatible shape.
"""
transpose = self.ndim == 2

if isinstance(indexer, np.ndarray) and indexer.ndim > self.ndim:
raise ValueError(f"Cannot set values with ndim > {self.ndim}")

# coerce None values, if appropriate
if value is None:
if self.is_numeric:
value = np.nan

# coerce if block dtype can store value
values = cast(np.ndarray, self.values)
if not self._can_hold_element(value):
# current dtype cannot store value, coerce to common dtype
return self.coerce_to_target_dtype(value).setitem(indexer, value)

# value must be storable at this moment
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
arr_value = value
else:
arr_value = np.asarray(value)

if transpose:
values = cast(np.ndarray, self.values)
if self.ndim == 2:
values = values.T

# length checking
check_setitem_lengths(indexer, value, values)

if is_empty_indexer(indexer, arr_value):
if is_empty_indexer(indexer):
# GH#8669 empty indexers, test_loc_setitem_boolean_mask_allfalse
pass

Expand Down
3 changes: 3 additions & 0 deletions pandas/core/internals/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ def setitem(self: T, indexer, value) -> T:

For SingleBlockManager, this backs s[indexer] = value
"""
if isinstance(indexer, np.ndarray) and indexer.ndim > self.ndim:
raise ValueError(f"Cannot set values with ndim > {self.ndim}")

return self.apply("setitem", indexer=indexer, value=value)

def putmask(self, mask, new, align: bool = True):
Expand Down