BUG/API: Series[mask] = (item,) unpacking item (original) (raw)

Reproducible Example

ser = pd.Series(range(5)) mask = np.array([True, False, True, False, True])

The following are all equivalent ATM, but only the first makes sense to me

ser[mask] = 10 ser[mask] = np.array([10]) ser[mask] = [10] ser[mask] = (10,)

If we try these with loc or iloc these raise

ser.loc[mask] = (10,) [...] ValueError: cannot set using a list-like indexer with a different length than the value

ser.iloc[mask] = [10] [...] ValueError: cannot set using a list-like indexer with a different length than the value

Issue Description

This behavior occurs because Series.__setitem__ goes through Series._where in cases where the key is a boolean mask. It then ends up going through Manager.putmask, which uses np.putmask semantics (mostly) that repeat/broadcast a listlike value.

AFAICT this repeat/broadcasting makes sense for Series.where and Series.mask, but not for Series.__setitem__. I think this behavior is largely accidental. If we disable this behavior in Series.__setitem__, 86 tests break. Of these, 84 are tests.series.indexing.test_where.test_downcast, and the PR (#4195) that introduced that test was about where, not __setitem__. The other two tests I tentatively think are breaking because of the particular way I've disabled the broadcasting.

Expected Behavior

ser[mask] = (10,) should raise.

Installed Versions

Details

Replace this line with the output of pd.show_versions()